aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/hotstuff/client.h24
-rw-r--r--include/hotstuff/consensus.h50
-rw-r--r--include/hotstuff/entity.h12
-rw-r--r--include/hotstuff/hotstuff.h11
-rw-r--r--src/consensus.cpp10
-rw-r--r--src/hotstuff.cpp52
-rw-r--r--src/hotstuff_app.cpp47
-rw-r--r--src/hotstuff_client.cpp6
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();