From 2757995cb91dd02ebd6ede693cc6c02c4e359afe Mon Sep 17 00:00:00 2001 From: Determinant Date: Sun, 7 Apr 2019 16:10:23 -0400 Subject: clean up consensus code --- include/hotstuff/consensus.h | 53 +++++++++---------------------- include/hotstuff/liveness.h | 36 ++++++++++----------- salticidae | 2 +- src/consensus.cpp | 75 +++++++++++++++++++++++--------------------- src/hotstuff.cpp | 13 ++++---- 5 files changed, 79 insertions(+), 100 deletions(-) diff --git a/include/hotstuff/consensus.h b/include/hotstuff/consensus.h index 5f781c5..a59c02f 100644 --- a/include/hotstuff/consensus.h +++ b/include/hotstuff/consensus.h @@ -38,7 +38,7 @@ class HotStuffCore { block_t b0; /** the genesis block */ /* === state variables === */ /** block containing the QC for the highest block having one */ - block_t bqc; + std::pair hqc; block_t bexec; /**< last executed block */ uint32_t vheight; /**< height of the block last voted for */ /* === auxilliary variables === */ @@ -49,16 +49,16 @@ class HotStuffCore { std::unordered_map qc_waiting; promise_t propose_waiting; promise_t receive_proposal_waiting; - promise_t bqc_update_waiting; + promise_t hqc_update_waiting; /* == feature switches == */ /** always vote negatively, useful for some PaceMakers */ bool neg_vote; block_t get_delivered_blk(const uint256_t &blk_hash); void sanity_check_delivered(const block_t &blk); - void check_commit(const block_t &_bqc); - bool update(const uint256_t &bqc_hash); - void on_bqc_update(); + void update(const block_t &nblk); + void update_hqc(const block_t &_hqc, const quorum_cert_bt &qc); + void on_hqc_update(); void on_qc_finish(const block_t &blk); void on_propose_(const Proposal &prop); void on_receive_proposal_(const Proposal &prop); @@ -152,12 +152,12 @@ class HotStuffCore { promise_t async_wait_proposal(); /** Get a promise resolved when a new proposal is received. */ promise_t async_wait_receive_proposal(); - /** Get a promise resolved when bqc is updated. */ - promise_t async_bqc_update(); + /** Get a promise resolved when hqc is updated. */ + promise_t async_hqc_update(); /* Other useful functions */ const block_t &get_genesis() { return b0; } - const block_t &get_bqc() { return bqc; } + const block_t &get_hqc() { return hqc.first; } const ReplicaConfig &get_config() { return config; } ReplicaID get_id() const { return id; } const std::set get_tails() const { return tails; } @@ -168,34 +168,27 @@ class HotStuffCore { /** Abstraction for proposal messages. */ struct Proposal: public Serializable { ReplicaID proposer; - /** hash for the block containing the highest QC */ - uint256_t bqc_hash; /** block being proposed */ block_t blk; - /** handle of the core object to allow polymorphism. The user should use * a pointer to the object of the class derived from HotStuffCore */ HotStuffCore *hsc; Proposal(): blk(nullptr), hsc(nullptr) {} Proposal(ReplicaID proposer, - const uint256_t &bqc_hash, const block_t &blk, HotStuffCore *hsc): proposer(proposer), - bqc_hash(bqc_hash), blk(blk), hsc(hsc) {} void serialize(DataStream &s) const override { s << proposer - << bqc_hash << *blk; } void unserialize(DataStream &s) override { assert(hsc != nullptr); - s >> proposer - >> bqc_hash; + s >> proposer; Block _blk; _blk.unserialize(s, hsc); blk = hsc->storage->add_blk(std::move(_blk), hsc->get_config()); @@ -205,7 +198,6 @@ struct Proposal: public Serializable { DataStream s; s << ""; return std::move(s); } @@ -214,11 +206,9 @@ struct Proposal: public Serializable { /** Abstraction for vote messages. */ struct Vote: public Serializable { ReplicaID voter; - /** hash for the block containing the highest QC */ - uint256_t bqc_hash; /** block being voted */ uint256_t blk_hash; - /** proof of validity for the vote (nullptr for a negative vote) */ + /** proof of validity for the vote */ part_cert_bt cert; /** handle of the core object to allow polymorphism */ @@ -226,18 +216,15 @@ struct Vote: public Serializable { Vote(): cert(nullptr), hsc(nullptr) {} Vote(ReplicaID voter, - const uint256_t &bqc_hash, const uint256_t &blk_hash, part_cert_bt &&cert, HotStuffCore *hsc): voter(voter), - bqc_hash(bqc_hash), blk_hash(blk_hash), cert(std::move(cert)), hsc(hsc) {} Vote(const Vote &other): voter(other.voter), - bqc_hash(other.bqc_hash), blk_hash(other.blk_hash), cert(other.cert ? other.cert->clone() : nullptr), hsc(other.hsc) {} @@ -245,23 +232,13 @@ struct Vote: public Serializable { Vote(Vote &&other) = default; void serialize(DataStream &s) const override { - s << voter - << bqc_hash - << blk_hash; - if (cert == nullptr) - s << (uint8_t)0; - else - s << (uint8_t)1 << *cert; + s << voter << blk_hash << *cert; } void unserialize(DataStream &s) override { assert(hsc != nullptr); - uint8_t has_cert; - s >> voter - >> bqc_hash - >> blk_hash - >> has_cert; - cert = has_cert ? hsc->parse_part_cert(s) : nullptr; + s >> voter >> blk_hash; + cert = hsc->parse_part_cert(s); } bool verify() const { @@ -281,9 +258,7 @@ struct Vote: public Serializable { DataStream s; s << ""; + << "blk=" << get_hex10(blk_hash) << ">"; return std::move(s); } }; diff --git a/include/hotstuff/liveness.h b/include/hotstuff/liveness.h index 903ac83..6d3c3cf 100644 --- a/include/hotstuff/liveness.h +++ b/include/hotstuff/liveness.h @@ -60,42 +60,42 @@ using pacemaker_bt = BoxObj; * direct parent, while including other tail blocks (up to parent_limit) as * uncles/aunts. */ class PMAllParents: public virtual PaceMaker { - block_t bqc_tail; + block_t hqc_tail; const int32_t parent_limit; /**< maximum number of parents */ - void reg_bqc_update() { - hsc->async_bqc_update().then([this](const block_t &bqc) { - const auto &pref = bqc->get_qc_ref(); + void reg_hqc_update() { + hsc->async_hqc_update().then([this](const block_t &hqc) { + const auto &pref = hqc; for (const auto &blk: hsc->get_tails()) { block_t b; for (b = blk; b->get_height() > pref->get_height(); b = b->get_parents()[0]); - if (b == pref && blk->get_height() > bqc_tail->get_height()) - bqc_tail = blk; + if (b == pref && blk->get_height() > hqc_tail->get_height()) + hqc_tail = blk; } - reg_bqc_update(); + reg_hqc_update(); }); } void reg_proposal() { hsc->async_wait_proposal().then([this](const Proposal &prop) { - bqc_tail = prop.blk; + hqc_tail = prop.blk; reg_proposal(); }); } void reg_receive_proposal() { hsc->async_wait_receive_proposal().then([this](const Proposal &prop) { - const auto &pref = hsc->get_bqc()->get_qc_ref(); + const auto &pref = hsc->get_hqc(); const auto &blk = prop.blk; block_t b; for (b = blk; b->get_height() > pref->get_height(); b = b->get_parents()[0]); - if (b == pref && blk->get_height() > bqc_tail->get_height()) - bqc_tail = blk; + if (b == pref && blk->get_height() > hqc_tail->get_height()) + hqc_tail = blk; reg_receive_proposal(); }); } @@ -103,15 +103,15 @@ class PMAllParents: public virtual PaceMaker { public: PMAllParents(int32_t parent_limit): parent_limit(parent_limit) {} void init() { - bqc_tail = hsc->get_genesis(); - reg_bqc_update(); + hqc_tail = hsc->get_genesis(); + reg_hqc_update(); reg_proposal(); reg_receive_proposal(); } std::vector get_parents() override { const auto &tails = hsc->get_tails(); - std::vector parents{bqc_tail}; + std::vector parents{hqc_tail}; auto nparents = tails.size(); if (parent_limit > 0) nparents = std::min(nparents, (size_t)parent_limit); @@ -119,7 +119,7 @@ class PMAllParents: public virtual PaceMaker { /* add the rest of tails as "uncles/aunts" */ for (const auto &blk: tails) { - if (blk != bqc_tail) + if (blk != hqc_tail) { parents.push_back(blk); if (!--nparents) break; @@ -386,7 +386,7 @@ class PMStickyProposer: virtual public PaceMaker { HOTSTUFF_LOG_PROTO("got block %s from %d", std::string(*prop.blk).c_str(), _proposer); p.reject(); (p = hsc->async_qc_finish(prop.blk)).then([this, blk=prop.blk, _proposer]() { - if (hsc->get_bqc()->get_qc_ref() == blk) + if (hsc->get_hqc() == blk) to_follower(_proposer); }); reg_cp_receive_proposal(); @@ -423,7 +423,7 @@ class PMStickyProposer: virtual public PaceMaker { to_candidate(); }); reg_cp_receive_proposal(); - proposer_propose(Proposal(-1, uint256_t(), hsc->get_genesis(), nullptr)); + proposer_propose(Proposal(-1, hsc->get_genesis(), nullptr)); } void to_candidate() { @@ -675,7 +675,7 @@ class PMRoundRobinProposer: virtual public PaceMaker { /* proposer unable to get a QC in time */ to_candidate(); }); - proposer_propose(Proposal(-1, uint256_t(), hsc->get_genesis(), nullptr)); + proposer_propose(Proposal(-1, hsc->get_genesis(), nullptr)); } void to_candidate() { diff --git a/salticidae b/salticidae index 07d197a..8a0d8fb 160000 --- a/salticidae +++ b/salticidae @@ -1 +1 @@ -Subproject commit 07d197a2d049aedb77536edeb3b20e51cc8c9588 +Subproject commit 8a0d8fbaf59be7acc536b2a753caa27aa1fbae24 diff --git a/src/consensus.cpp b/src/consensus.cpp index 8b6e977..b57e258 100644 --- a/src/consensus.cpp +++ b/src/consensus.cpp @@ -33,16 +33,14 @@ namespace hotstuff { HotStuffCore::HotStuffCore(ReplicaID id, privkey_bt &&priv_key): b0(new Block(true, 1)), - bqc(b0), bexec(b0), vheight(0), priv_key(std::move(priv_key)), - tails{bqc}, + tails{b0}, neg_vote(false), id(id), storage(new EntityStorage()) { storage->add_blk(b0); - b0->qc_ref = b0; } void HotStuffCore::sanity_check_delivered(const block_t &blk) { @@ -84,8 +82,20 @@ bool HotStuffCore::on_deliver_blk(const block_t &blk) { return true; } -void HotStuffCore::check_commit(const block_t &_blk) { - const block_t &blk = _blk->qc_ref; +void HotStuffCore::update_hqc(const block_t &_hqc, const quorum_cert_bt &qc) { + if (_hqc->height > hqc.first->height) + { + hqc = std::make_pair(_hqc, qc->clone()); + on_hqc_update(); + } +} + +void HotStuffCore::update(const block_t &nblk) { + const block_t &blk = nblk->qc_ref; + if (blk == nullptr) + throw std::runtime_error("empty qc_ref"); + update_hqc(blk, nblk->qc); + /* check for commit */ if (blk->qc_ref == nullptr) return; /* decided blk could possible be incomplete due to pruning */ if (blk->decision) return; @@ -117,18 +127,6 @@ void HotStuffCore::check_commit(const block_t &_blk) { bexec = p; } -bool HotStuffCore::update(const uint256_t &bqc_hash) { - block_t _bqc = get_delivered_blk(bqc_hash); - if (_bqc->qc_ref == nullptr) return false; - check_commit(_bqc); - if (_bqc->qc_ref->height > bqc->qc_ref->height) - { - bqc = _bqc; - on_bqc_update(); - } - return true; -} - void HotStuffCore::on_propose(const std::vector &cmds, const std::vector &parents, bytearray_t &&extra) { @@ -139,7 +137,7 @@ void HotStuffCore::on_propose(const std::vector &cmds, quorum_cert_bt qc = nullptr; block_t qc_ref = nullptr; /* a block can optionally carray a QC */ - if (p != b0 && p->voted.size() >= config.nmajority) + if (p->voted.size() >= config.nmajority) { qc = p->self_qc->clone(); qc_ref = p; @@ -155,15 +153,15 @@ void HotStuffCore::on_propose(const std::vector &cmds, const uint256_t bnew_hash = bnew->get_hash(); bnew->self_qc = create_quorum_cert(bnew_hash); on_deliver_blk(bnew); - update(bnew_hash); - Proposal prop(id, bqc->get_hash(), bnew, nullptr); + update(bnew); + Proposal prop(id, bnew, nullptr); LOG_PROTO("propose %s", std::string(*bnew).c_str()); /* self-vote */ if (bnew->height <= vheight) throw std::runtime_error("new block should be higher than vheight"); vheight = bnew->height; on_receive_vote( - Vote(id, bqc->get_hash(), bnew_hash, + Vote(id, bnew_hash, create_part_cert(*priv_key, bnew_hash), this)); on_propose_(prop); /* boradcast to other replicas */ @@ -171,14 +169,14 @@ void HotStuffCore::on_propose(const std::vector &cmds, } void HotStuffCore::on_receive_proposal(const Proposal &prop) { - if (!update(prop.bqc_hash)) return; LOG_PROTO("got %s", std::string(prop).c_str()); block_t bnew = prop.blk; sanity_check_delivered(bnew); + update(bnew); bool opinion = false; if (bnew->height > vheight) { - block_t pref = bqc->qc_ref; + block_t pref = hqc.first; block_t b; for (b = bnew; b->height > pref->height; @@ -195,14 +193,11 @@ void HotStuffCore::on_receive_proposal(const Proposal &prop) { on_receive_proposal_(prop); if (opinion && !neg_vote) do_vote(prop.proposer, - Vote(id, - bqc->get_hash(), - bnew->get_hash(), + Vote(id, bnew->get_hash(), create_part_cert(*priv_key, bnew->get_hash()), this)); } void HotStuffCore::on_receive_vote(const Vote &vote) { - if (!update(vote.bqc_hash)) return; LOG_PROTO("got %s", std::string(vote).c_str()); LOG_PROTO("now state: %s", std::string(*this).c_str()); block_t blk = get_delivered_blk(vote.blk_hash); @@ -225,10 +220,18 @@ void HotStuffCore::on_receive_vote(const Vote &vote) { { qc->compute(); on_qc_finish(blk); + update_hqc(blk, qc); } } /*** end HotStuff protocol logic ***/ -void HotStuffCore::on_init(uint32_t nfaulty) { config.nmajority = 2 * nfaulty + 1; } +void HotStuffCore::on_init(uint32_t nfaulty) { + config.nmajority = 2 * nfaulty + 1; + b0->qc = create_quorum_cert(b0->get_hash()); + b0->qc->compute(); + b0->self_qc = b0->qc->clone(); + b0->qc_ref = b0; + hqc = std::make_pair(b0, b0->qc->clone()); +} void HotStuffCore::prune(uint32_t staleness) { block_t start; @@ -292,9 +295,9 @@ promise_t HotStuffCore::async_wait_receive_proposal() { }); } -promise_t HotStuffCore::async_bqc_update() { - return bqc_update_waiting.then([this]() { - return bqc; +promise_t HotStuffCore::async_hqc_update() { + return hqc_update_waiting.then([this]() { + return hqc.first; }); } @@ -310,17 +313,17 @@ void HotStuffCore::on_receive_proposal_(const Proposal &prop) { t.resolve(prop); } -void HotStuffCore::on_bqc_update() { - auto t = std::move(bqc_update_waiting); - bqc_update_waiting = promise_t(); +void HotStuffCore::on_hqc_update() { + auto t = std::move(hqc_update_waiting); + hqc_update_waiting = promise_t(); t.resolve(); } HotStuffCore::operator std::string () const { DataStream s; s << ""; diff --git a/src/hotstuff.cpp b/src/hotstuff.cpp index 4a84927..9b36fa2 100644 --- a/src/hotstuff.cpp +++ b/src/hotstuff.cpp @@ -223,7 +223,8 @@ promise_t HotStuffBase::async_deliver_blk(const uint256_t &blk_hash, /* the parents should be delivered */ for (const auto &phash: blk->get_parent_hashes()) pms.push_back(async_deliver_blk(phash, replica_id)); - pms.push_back(blk->verify(get_config(), vpool)); + if (blk != get_genesis()) + pms.push_back(blk->verify(get_config(), vpool)); promise::all(pms).then([this, blk]() { on_deliver_blk(blk); }); @@ -238,8 +239,7 @@ void HotStuffBase::propose_handler(MsgPropose &&msg, const Net::conn_t &conn) { block_t blk = prop.blk; if (!blk) return; promise::all(std::vector{ - async_deliver_blk(prop.bqc_hash, peer), - async_deliver_blk(blk->get_hash(), peer), + async_deliver_blk(blk->get_hash(), peer) }).then([this, prop = std::move(prop)]() { on_receive_proposal(prop); }); @@ -251,11 +251,10 @@ void HotStuffBase::vote_handler(MsgVote &&msg, const Net::conn_t &conn) { //auto &vote = msg.vote; RcObj v(new Vote(std::move(msg.vote))); promise::all(std::vector{ - async_deliver_blk(v->bqc_hash, peer), async_deliver_blk(v->blk_hash, peer), v->verify(vpool), }).then([this, v=std::move(v)](const promise::values_t values) { - if (!promise::any_cast(values[2])) + if (!promise::any_cast(values[1])) LOG_WARN("invalid vote from %d", v->voter); else on_receive_vote(*v); @@ -415,7 +414,9 @@ void HotStuffBase::do_decide(Finality &&fin) { HotStuffBase::~HotStuffBase() {} -void HotStuffBase::start(std::vector> &&replicas, bool ec_loop) { +void HotStuffBase::start( + std::vector> &&replicas, + bool ec_loop) { for (size_t i = 0; i < replicas.size(); i++) { auto &addr = replicas[i].first; -- cgit v1.2.3