diff options
-rw-r--r-- | include/hotstuff/client.h | 24 | ||||
-rw-r--r-- | include/hotstuff/consensus.h | 50 | ||||
-rw-r--r-- | include/hotstuff/entity.h | 12 | ||||
-rw-r--r-- | include/hotstuff/hotstuff.h | 11 | ||||
-rw-r--r-- | src/consensus.cpp | 10 | ||||
-rw-r--r-- | src/hotstuff.cpp | 52 | ||||
-rw-r--r-- | src/hotstuff_app.cpp | 47 | ||||
-rw-r--r-- | src/hotstuff_client.cpp | 6 |
8 files changed, 91 insertions, 121 deletions
diff --git a/include/hotstuff/client.h b/include/hotstuff/client.h index 87e60b7..95a003d 100644 --- a/include/hotstuff/client.h +++ b/include/hotstuff/client.h @@ -14,30 +14,6 @@ enum { CHK_CMD = 0x6 }; -struct Finality: public Serializable { - ReplicaID rid; - int8_t decision; - uint256_t cmd_hash; - uint256_t blk_hash; - - public: - Finality() = default; - Finality(ReplicaID rid, int8_t decision, - uint256_t cmd_hash, uint256_t blk_hash): - rid(rid), decision(decision), - cmd_hash(cmd_hash), blk_hash(blk_hash) {} - - void serialize(DataStream &s) const override { - s << rid << decision << cmd_hash; - if (decision == 1) s << blk_hash; - } - - void unserialize(DataStream &s) override { - s >> rid >> decision >> cmd_hash; - if (decision == 1) s >> blk_hash; - } -}; - struct MsgClient: public salticidae::MsgBase<> { using MsgBase::MsgBase; void gen_reqcmd(const Command &cmd); diff --git a/include/hotstuff/consensus.h b/include/hotstuff/consensus.h index a3a1f25..475f1f2 100644 --- a/include/hotstuff/consensus.h +++ b/include/hotstuff/consensus.h @@ -14,6 +14,7 @@ namespace hotstuff { struct Proposal; struct Vote; +struct Finality; /** Abstraction for HotStuff protocol state machine (without network implementation). */ class HotStuffCore { @@ -86,7 +87,7 @@ class HotStuffCore { * the events. */ protected: /** Called by HotStuffCore upon the decision being made for cmd. */ - virtual void do_decide(const command_t &cmd) = 0; + virtual void do_decide(Finality &&fin) = 0; /** Called by HotStuffCore upon broadcasting a new proposal. * The user should send the proposal message to all replicas except for * itself. */ @@ -127,7 +128,6 @@ class HotStuffCore { /* Other useful functions */ block_t get_genesis() { return b0; } const ReplicaConfig &get_config() { return config; } - int8_t get_cmd_decision(const uint256_t &cmd_hash); ReplicaID get_id() const { return id; } const std::set<block_t, BlockHeightCmp> get_tails() const { return tails; } operator std::string () const; @@ -249,6 +249,52 @@ struct Vote: public Serializable { } }; +struct Finality: public Serializable { + ReplicaID rid; + int8_t decision; + uint32_t cmd_idx; + uint32_t cmd_height; + uint256_t cmd_hash; + uint256_t blk_hash; + + public: + Finality() = default; + Finality(ReplicaID rid, + int8_t decision, + uint32_t cmd_idx, + uint32_t cmd_height, + uint256_t cmd_hash, + uint256_t blk_hash): + rid(rid), decision(decision), + cmd_idx(cmd_idx), cmd_height(cmd_height), + cmd_hash(cmd_hash), blk_hash(blk_hash) {} + + void serialize(DataStream &s) const override { + s << rid << decision + << cmd_idx << cmd_height + << cmd_hash; + if (decision == 1) s << blk_hash; + } + + void unserialize(DataStream &s) override { + s >> rid >> decision + >> cmd_idx >> cmd_height + >> cmd_hash; + if (decision == 1) s >> blk_hash; + } + + operator std::string () const { + DataStream s; + s << "<fin " + << "decision=" << std::to_string(decision) << " " + << "cmd_idx=" << std::to_string(cmd_idx) << " " + << "cmd_height=" << std::to_string(cmd_height) << " " + << "cmd=" << get_hex10(cmd_hash) << " " + << "blk=" << get_hex10(blk_hash) << ">"; + return std::move(s); + } +}; + } #endif diff --git a/include/hotstuff/entity.h b/include/hotstuff/entity.h index 28b5148..1fca18c 100644 --- a/include/hotstuff/entity.h +++ b/include/hotstuff/entity.h @@ -80,9 +80,10 @@ class Command: public Serializable { virtual ~Command() = default; virtual const uint256_t &get_hash() const = 0; virtual bool verify() const = 0; - inline int8_t get_decision() const; - block_t get_container() const { - return container; + virtual operator std::string () const { + DataStream s; + s << "<cmd id=" << get_hex10(get_hash()) << ">"; + return std::move(s); } }; @@ -194,11 +195,6 @@ struct BlockHeightCmp { } }; -int8_t Command::get_decision() const { - block_t cptr = container; - return cptr ? cptr->get_decision() : 0; -} - class EntityStorage { std::unordered_map<const uint256_t, block_t> blk_cache; std::unordered_map<const uint256_t, command_t> cmd_cache; diff --git a/include/hotstuff/hotstuff.h b/include/hotstuff/hotstuff.h index c8d8b5d..45992f1 100644 --- a/include/hotstuff/hotstuff.h +++ b/include/hotstuff/hotstuff.h @@ -152,8 +152,13 @@ class HotStuffBase: public HotStuffCore { void do_broadcast_proposal(const Proposal &) override; void do_vote(ReplicaID, const Vote &) override; - void do_decide(const command_t &) override; - void do_forward(const uint256_t &cmd_hash, ReplicaID rid); + void do_decide(Finality &&) override; + + protected: + + /** Called to replicate the execution of a command, the application should + * implement this to make transition for the application state. */ + virtual void state_machine_execute(const Finality &) = 0; public: HotStuffBase(uint32_t blk_size, @@ -182,8 +187,6 @@ class HotStuffBase: public HotStuffCore { promise_t async_fetch_blk(const uint256_t &blk_hash, const NetAddr *replica_id, bool fetch_now = true); /** Returns a promise resolved (with block_t blk) when Block is delivered (i.e. prefix is fetched). */ promise_t async_deliver_blk(const uint256_t &blk_hash, const NetAddr &replica_id); - /** Returns a promise resolved (with command_t cmd) when Command is decided. */ - promise_t async_decide(const uint256_t &cmd_hash); }; /** HotStuff protocol (templated by cryptographic implementation). */ diff --git a/src/consensus.cpp b/src/consensus.cpp index 6b8b398..57152f0 100644 --- a/src/consensus.cpp +++ b/src/consensus.cpp @@ -91,7 +91,10 @@ void HotStuffCore::check_commit(const block_t &_blk) { #ifdef HOTSTUFF_ENABLE_LOG_PROTO LOG_INFO("commit %s", std::string(*blk).c_str()); #endif - for (auto cmd: blk->cmds) do_decide(cmd); + size_t idx = 0; + for (auto cmd: blk->cmds) + do_decide(Finality(id, 1, idx, blk->height, + cmd->get_hash(), blk->get_hash())); } bexec = p; } @@ -238,11 +241,6 @@ void HotStuffCore::prune(uint32_t staleness) { } } -int8_t HotStuffCore::get_cmd_decision(const uint256_t &cmd_hash) { - auto cmd = storage->find_cmd(cmd_hash); - return cmd != nullptr ? cmd->get_decision() : 0; -} - void HotStuffCore::add_replica(ReplicaID rid, const NetAddr &addr, pubkey_bt &&pub_key) { config.add_replica(rid, diff --git a/src/hotstuff.cpp b/src/hotstuff.cpp index a37e872..687e21d 100644 --- a/src/hotstuff.cpp +++ b/src/hotstuff.cpp @@ -72,12 +72,13 @@ void MsgHotStuff::parse_rfetchblk(std::vector<block_t> &blks, HotStuffCore *hsc) } promise_t HotStuffBase::exec_command(command_t cmd) { + const uint256_t &cmd_hash = cmd->get_hash(); ReplicaID proposer = pmaker->get_proposer(); /* not the proposer */ if (proposer != get_id()) - return promise_t([proposer, cmd](promise_t &pm) { - pm.resolve(Finality(proposer, -1, - cmd->get_hash(), uint256_t())); + return promise_t([proposer, cmd_hash](promise_t &pm) { + pm.resolve(Finality(proposer, -1, 0, 0, + cmd_hash, uint256_t())); }); cmd_pending.push(storage->add_cmd(cmd)); if (cmd_pending.size() >= blk_size) @@ -92,13 +93,13 @@ promise_t HotStuffBase::exec_command(command_t cmd) { on_propose(cmds, pmaker->get_parents()); }); } - return async_decide(cmd->get_hash()).then([this](const command_t &cmd) { - block_t blk = cmd->get_container(); - return Finality(get_id(), - cmd->get_decision(), - cmd->get_hash(), - blk->get_hash()); - }); + auto it = decision_waiting.find(cmd_hash); + if (it == decision_waiting.end()) + { + promise_t pm{[](promise_t){}}; + it = decision_waiting.insert(std::make_pair(cmd_hash, pm)).first; + } + return it->second; } void HotStuffBase::add_replica(ReplicaID idx, const NetAddr &addr, @@ -380,21 +381,6 @@ void HotStuffBase::print_stat() const { #endif } -promise_t HotStuffBase::async_decide(const uint256_t &cmd_hash) { - if (get_cmd_decision(cmd_hash)) - return promise_t([this, cmd_hash](promise_t pm){ - pm.resolve(storage->find_cmd(cmd_hash)); - }); - /* otherwise the do_decide will resolve the promise */ - auto it = decision_waiting.find(cmd_hash); - if (it == decision_waiting.end()) - { - promise_t pm{[](promise_t){}}; - it = decision_waiting.insert(std::make_pair(cmd_hash, pm)).first; - } - return it->second; -} - HotStuffBase::HotStuffBase(uint32_t blk_size, ReplicaID rid, privkey_bt &&priv_key, @@ -448,20 +434,12 @@ void HotStuffBase::do_vote(ReplicaID last_proposer, const Vote &vote) { }); } -void HotStuffBase::do_decide(const command_t &cmd) { - auto it = decision_waiting.find(cmd->get_hash()); - if (it != decision_waiting.end()) - { - it->second.resolve(cmd); - decision_waiting.erase(it); - } -} - -void HotStuffBase::do_forward(const uint256_t &cmd_hash, ReplicaID rid) { - auto it = decision_waiting.find(cmd_hash); +void HotStuffBase::do_decide(Finality &&fin) { + state_machine_execute(fin); + auto it = decision_waiting.find(fin.cmd_hash); if (it != decision_waiting.end()) { - it->second.reject(rid); + it->second.resolve(std::move(fin)); decision_waiting.erase(it); } } diff --git a/src/hotstuff_app.cpp b/src/hotstuff_app.cpp index 1a63776..c629809 100644 --- a/src/hotstuff_app.cpp +++ b/src/hotstuff_app.cpp @@ -53,35 +53,20 @@ using HotStuff = hotstuff::HotStuffSecp256k1; class HotStuffApp: public HotStuff { double stat_period; - /** libevent handle */ EventContext eb; - /** network messaging between a replica and its client */ + /** Network messaging between a replica and its client. */ ClientNetwork<MsgClient> cn; - /** timer object to schedule a periodic printing of system statistics */ + /** Timer object to schedule a periodic printing of system statistics */ Event ev_stat_timer; - /** the binding address for client RPC */ + /** The listen address for client RPC */ NetAddr clisten_addr; + /** Maximum number of parents. */ int32_t parent_limit; using conn_client_t = MsgNetwork<MsgClient>::conn_t; - /** Client */ - /** submits a new command */ - inline void client_request_cmd_handler(const MsgClient &, conn_client_t); - /** checks if a cmd is decided */ - inline void client_check_cmd_handler(const MsgClient &, conn_client_t); - - Finality get_finality(const uint256_t cmd_hash) const { - command_t cmd = storage->find_cmd(cmd_hash); - hotstuff::block_t blk = cmd ? cmd->get_container() : nullptr; - return Finality(get_id(), - cmd ? cmd->get_decision() : 0, - cmd_hash, - blk ? blk->get_hash() : uint256_t()); - } - - /** The callback function to print stat */ - inline void print_stat_cb(evutil_socket_t, short); + void client_request_cmd_handler(const MsgClient &, conn_client_t); + void print_stat_cb(evutil_socket_t, short); command_t parse_cmd(DataStream &s) override { auto cmd = new CommandDummy(); @@ -89,6 +74,10 @@ class HotStuffApp: public HotStuff { return cmd; } + void state_machine_execute(const Finality &fin) override { + LOG_INFO("replicated %s", std::string(fin).c_str()); + } + public: HotStuffApp(uint32_t blk_size, int32_t parent_limit, @@ -102,7 +91,6 @@ class HotStuffApp: public HotStuff { void start(); }; - std::pair<std::string, std::string> split_ip_port_cport(const std::string &s) { auto ret = trim_all(split(s, ";")); if (ret.size() != 2) @@ -222,7 +210,6 @@ HotStuffApp::HotStuffApp(uint32_t blk_size, parent_limit(parent_limit) { /* register the handlers for msg from clients */ cn.reg_handler(hotstuff::REQ_CMD, std::bind(&HotStuffApp::client_request_cmd_handler, this, _1, _2)); - cn.reg_handler(hotstuff::CHK_CMD, std::bind(&HotStuffApp::client_check_cmd_handler, this, _1, _2)); cn.listen(clisten_addr); } @@ -242,12 +229,12 @@ void HotStuffApp::client_request_cmd_handler(const MsgClient &msg, conn_client_t { LOG_WARN("invalid client cmd"); MsgClient resp; - resp.gen_respcmd(Finality(get_id(), -1, cmd_hash, uint256_t())); + resp.gen_respcmd(Finality(get_id(), -1, 0, 0, cmd_hash, uint256_t())); cn.send_msg(resp, addr); } else { - LOG_DEBUG("processing client cmd %.10s", get_hex(cmd_hash).c_str()); + LOG_DEBUG("processing %s", std::string(*cmd).c_str()); exec_command(cmd).then([this, addr](Finality fin) { MsgClient resp; resp.gen_respcmd(fin); @@ -256,16 +243,6 @@ void HotStuffApp::client_request_cmd_handler(const MsgClient &msg, conn_client_t } } -void HotStuffApp::client_check_cmd_handler(const MsgClient &msg, conn_client_t conn_) { - auto conn = static_pointer_cast<ClientNetwork<MsgClient>::Conn>(conn_); - const NetAddr addr = conn->get_addr(); - uint256_t cmd_hash; - msg.parse_chkcmd(cmd_hash); - MsgClient resp; - resp.gen_respcmd(get_finality(cmd_hash)); - cn.send_msg(resp, addr); -} - void HotStuffApp::start() { ev_stat_timer = Event(eb, -1, 0, std::bind(&HotStuffApp::print_stat_cb, this, _1, _2)); diff --git a/src/hotstuff_client.cpp b/src/hotstuff_client.cpp index bee60c3..3931a0c 100644 --- a/src/hotstuff_client.cpp +++ b/src/hotstuff_client.cpp @@ -91,11 +91,7 @@ void on_receive(const MsgClient &msg, MsgNetwork<MsgClient>::conn_t) { it->second.rid = proposer; return; } - HOTSTUFF_LOG_INFO( - "got response for %.10s: <decision=%d, blk=%.10s>", - get_hex(cmd_hash).c_str(), - fin.decision, - get_hex(fin.blk_hash).c_str()); + HOTSTUFF_LOG_INFO("got %s", std::string(fin).c_str()); if (it == waiting.end()) return; waiting.erase(it); try_send(); |