From b02268c29244a3e5617de1caac66fd6dfcddbed4 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 11 Jan 2024 08:57:16 -0500 Subject: [PATCH 01/13] add aggregate_vote to block_state --- libraries/chain/block_state.cpp | 27 +++++++++++++++++++ .../chain/include/eosio/chain/block_state.hpp | 5 +++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index 4c43eadc12..e355e9702c 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -102,5 +102,32 @@ namespace eosio::chain { ,_cached_trxs( std::move(trx_metas) ) {} #endif + + bool block_state::aggregate_vote(const hs_vote_message& vote) { + const auto& finalizers = finalizer_policy->finalizers; + auto it = std::find_if(finalizers.begin(), + finalizers.end(), + [&](const auto& finalizer) { return finalizer.public_key == vote.finalizer_key; }); + + if (it != finalizers.end()) { + auto index = std::distance(finalizers.begin(), it); + if( vote.strong ) { + std::vector d(strong_finalizer_digest.data(), strong_finalizer_digest.data() + strong_finalizer_digest.data_size()); + return pending_qc.add_strong_vote( d, + index, + vote.finalizer_key, + vote.sig ); + } else { + std::vector d(weak_finalizer_digest.data(), weak_finalizer_digest.data() + weak_finalizer_digest.data_size()); + return pending_qc.add_weak_vote( d, + index, + vote.finalizer_key, + vote.sig ); + } + } else { + wlog( "finalizer_key (${k}) in vote is not in finalizer policy", ("k", vote.finalizer_key) ); + return false; + } + } } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/block_state.hpp b/libraries/chain/include/eosio/chain/block_state.hpp index 6c98e1f2f1..d18088ca43 100644 --- a/libraries/chain/include/eosio/chain/block_state.hpp +++ b/libraries/chain/include/eosio/chain/block_state.hpp @@ -11,7 +11,8 @@ namespace eosio::chain { // ------ data members ------------------------------------------------------------- signed_block_ptr block; bool validated; // We have executed the block's trxs and verified that action merkle root (block id) matches. - digest_type finalizer_digest; + digest_type strong_finalizer_digest; + digest_type weak_finalizer_digest; pending_quorum_certificate pending_qc; // where we accumulate votes we receive std::optional valid_qc; // qc received from the network @@ -32,6 +33,8 @@ namespace eosio::chain { protocol_feature_activation_set_ptr get_activated_protocol_features() const { return block_header_state::activated_protocol_features; } deque extract_trxs_metas() { return {}; }; // [greg todo] see impl in block_state_legacy.hpp + + bool aggregate_vote(const hs_vote_message& vote); // aggregate vote into pending_qc }; using block_state_ptr = std::shared_ptr; From 7486f3992acccb28ce974a02d95cc3d44c4305a4 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 11 Jan 2024 08:58:14 -0500 Subject: [PATCH 02/13] add process_vote_message to controller --- libraries/chain/controller.cpp | 21 +++++++++++++++++-- libraries/chain/hotstuff/hotstuff.cpp | 10 ++++++--- .../chain/include/eosio/chain/controller.hpp | 2 +- plugins/net_plugin/net_plugin.cpp | 12 +++++------ 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index d5b2857a14..233d6afb4e 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -249,6 +249,23 @@ struct block_data_t { }, v); } + bool aggregate_vote(const hs_vote_message& vote) { + return std::visit( + overloaded{[](const block_data_legacy_t&) { + EOS_ASSERT(false, misc_exception, "attempting to call aggregate_vote in legacy mode"); + return false; }, + [&](const block_data_new_t& bd) { + auto bsp = bd.fork_db.get_block(vote.proposal_id); + if (bsp) { + return bsp->aggregate_vote(vote); + } else { + wlog("no block exists for the vote (proposal_id: ${id}", ("id", vote.proposal_id)); + return false; + }} + }, + v); + } + template R apply(F &f) { if constexpr (std::is_same_v) @@ -4007,8 +4024,8 @@ void controller::get_finalizer_state( finalizer_state& fs ) const { } // called from net threads -void controller::notify_hs_message( const uint32_t connection_id, const hs_message& msg ) { - my->pacemaker->on_hs_msg(connection_id, msg); +void controller::process_vote_message( const hs_vote_message& vote ) { + my->block_data.aggregate_vote(vote); }; const producer_authority_schedule& controller::active_producers()const { diff --git a/libraries/chain/hotstuff/hotstuff.cpp b/libraries/chain/hotstuff/hotstuff.cpp index 91dc48ff67..de83f59396 100644 --- a/libraries/chain/hotstuff/hotstuff.cpp +++ b/libraries/chain/hotstuff/hotstuff.cpp @@ -22,10 +22,14 @@ inline std::vector bitset_to_vector(const hs_bitset& bs) { bool pending_quorum_certificate::votes_t::add_vote(const std::vector& proposal_digest, size_t index, const bls_public_key& pubkey, const bls_signature& new_sig) { - if (_bitset[index]) + if (_bitset[index]) { + wlog( "finalizer ${i} has already voted", ("i", index) ); return false; // shouldn't be already present - if (!fc::crypto::blslib::verify(pubkey, proposal_digest, new_sig)) + } + if (!fc::crypto::blslib::verify(pubkey, proposal_digest, new_sig)) { + wlog( "signature from finalizer ${i} cannot be verified", ("i", index) ); return false; + } _bitset.set(index); _sig = fc::crypto::blslib::aggregate({_sig, new_sig}); // works even if _sig is default initialized (fp2::zero()) return true; @@ -192,4 +196,4 @@ quorum_certificate_message valid_quorum_certificate::to_msg() const { }; } -} // namespace eosio::chain \ No newline at end of file +} // namespace eosio::chain diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index b563e4a5ca..26951e20cb 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -317,7 +317,7 @@ namespace eosio::chain { void set_proposed_finalizers( const finalizer_policy& fin_set ); void get_finalizer_state( finalizer_state& fs ) const; // called from net threads - void notify_hs_message( const uint32_t connection_id, const hs_message& msg ); + void process_vote_message( const hs_vote_message& msg ); bool light_validation_allowed() const; bool skip_auth_check()const; diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index bf8f7d0a07..845cf502e4 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -1095,7 +1095,7 @@ namespace eosio { void handle_message( const block_id_type& id, signed_block_ptr ptr ); void handle_message( const packed_transaction& msg ) = delete; // packed_transaction_ptr overload used instead void handle_message( packed_transaction_ptr trx ); - void handle_message( const chain::hs_message& msg ); + void handle_message( const chain::hs_vote_message& msg ); // returns calculated number of blocks combined latency uint32_t calc_block_latency(); @@ -1177,9 +1177,9 @@ namespace eosio { c->handle_message( msg ); } - void operator()( const chain::hs_message& msg ) const { + void operator()( const chain::hs_vote_message& msg ) const { // continue call to handle_message on connection strand - peer_dlog( c, "handle hs_message" ); + peer_dlog( c, "handle hs_vote_message" ); c->handle_message( msg ); } }; @@ -3673,10 +3673,10 @@ namespace eosio { } } - void connection::handle_message( const chain::hs_message& msg ) { - peer_dlog(this, "received hs: ${msg}", ("msg", msg)); + void connection::handle_message( const chain::hs_vote_message& msg ) { + peer_dlog(this, "received vote: ${msg}", ("msg", msg)); controller& cc = my_impl->chain_plug->chain(); - cc.notify_hs_message(connection_id, msg); + cc.process_vote_message(msg); } size_t calc_trx_size( const packed_transaction_ptr& trx ) { From 3fd755a2752c0ffabe988271909ee6ca4fb32c58 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 11 Jan 2024 08:59:07 -0500 Subject: [PATCH 03/13] add block_state_tests --- unittests/block_state_tests.cpp | 90 +++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 unittests/block_state_tests.cpp diff --git a/unittests/block_state_tests.cpp b/unittests/block_state_tests.cpp new file mode 100644 index 0000000000..cf9cdd81bb --- /dev/null +++ b/unittests/block_state_tests.cpp @@ -0,0 +1,90 @@ +#include + +#include +#include +#include + +#include + +BOOST_AUTO_TEST_SUITE(block_state_tests) + +BOOST_AUTO_TEST_CASE(aggregate_vote_test) try { + using namespace eosio::chain; + using namespace fc::crypto::blslib; + + digest_type block_id(fc::sha256("0000000000000000000000000000001")); + + digest_type strong_digest(fc::sha256("0000000000000000000000000000002")); + std::vector strong_digest_data(strong_digest.data(), strong_digest.data() + strong_digest.data_size()); + + digest_type weak_digest(fc::sha256("0000000000000000000000000000003")); + std::vector weak_digest_data(weak_digest.data(), weak_digest.data() + weak_digest.data_size()); + + const size_t num_finalizers = 3; + + // initialize a set of private keys + std::vector private_key { + bls_private_key("PVT_BLS_r4ZpChd87ooyzl6MIkw23k7PRX8xptp7TczLJHCIIW88h/hS"), + bls_private_key("PVT_BLS_/l7xzXANaB+GrlTsbZEuTiSOiWTtpBoog+TZnirxUUSaAfCo"), + bls_private_key("PVT_BLS_3FoY73Q/gED3ejyg8cvnGqHrMmx4cLKwh/e0sbcsCxpCeqn3"), + }; + + // construct finalizers + std::vector public_key(num_finalizers); + std::vector finalizers(num_finalizers); + for (size_t i = 0; i < num_finalizers; ++i) { + public_key[i] = private_key[i].get_public_key(); + finalizers[i] = finalizer_authority{ "test", 1, public_key[i] }; + } + + { // all finalizers can aggregate votes + block_state_ptr bsp = std::make_shared(); + bsp->finalizer_policy = std::make_shared( 10, 15, finalizers ); + bsp->strong_finalizer_digest = strong_digest; + bsp->weak_finalizer_digest = weak_digest; + bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 }; + + for (size_t i = 0; i < num_finalizers; ++i) { + bool strong = (i % 2 == 0); // alternate strong and weak + auto sig = strong ? private_key[i].sign(strong_digest_data) : private_key[i].sign(weak_digest_data); + hs_vote_message vote{ block_id, strong, public_key[i], sig }; + BOOST_REQUIRE(bsp->aggregate_vote(vote)); + } + } + + { // public and private keys mismatched + block_state_ptr bsp = std::make_shared(); + bsp->finalizer_policy = std::make_shared( 10, 15, finalizers ); + bsp->strong_finalizer_digest = strong_digest; + bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 }; + + hs_vote_message vote {block_id, true, public_key[0], private_key[1].sign(strong_digest_data) }; + BOOST_REQUIRE(!bsp->aggregate_vote(vote)); + } + + { // duplicate votes + block_state_ptr bsp = std::make_shared(); + bsp->finalizer_policy = std::make_shared( 10, 15, finalizers ); + bsp->strong_finalizer_digest = strong_digest; + bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 }; + + hs_vote_message vote {block_id, true, public_key[0], private_key[0].sign(strong_digest_data) }; + BOOST_REQUIRE(bsp->aggregate_vote(vote)); + BOOST_REQUIRE(!bsp->aggregate_vote(vote)); + } + + { // public key does not exit in finalizer set + block_state_ptr bsp = std::make_shared(); + bsp->finalizer_policy = std::make_shared( 10, 15, finalizers ); + bsp->strong_finalizer_digest = strong_digest; + bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 }; + + bls_private_key new_private_key{ "PVT_BLS_warwI76e+pPX9wLFZKPFagngeFM8bm6J8D5w0iiHpxW7PiId" }; + bls_public_key new_public_key{ new_private_key.get_public_key() }; + + hs_vote_message vote {block_id, true, new_public_key, private_key[0].sign(strong_digest_data) }; + BOOST_REQUIRE(!bsp->aggregate_vote(vote)); + } +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_SUITE_END() From b155772da7a1407afd831d24efee32e5384673b0 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 11 Jan 2024 11:05:57 -0500 Subject: [PATCH 04/13] use add_vote instead of add_weak_vote and add_strong_vote --- libraries/chain/block_state.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index e355e9702c..67f6cab054 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -111,19 +111,13 @@ namespace eosio::chain { if (it != finalizers.end()) { auto index = std::distance(finalizers.begin(), it); - if( vote.strong ) { - std::vector d(strong_finalizer_digest.data(), strong_finalizer_digest.data() + strong_finalizer_digest.data_size()); - return pending_qc.add_strong_vote( d, - index, - vote.finalizer_key, - vote.sig ); - } else { - std::vector d(weak_finalizer_digest.data(), weak_finalizer_digest.data() + weak_finalizer_digest.data_size()); - return pending_qc.add_weak_vote( d, - index, - vote.finalizer_key, - vote.sig ); - } + const digest_type& digest = vote.strong ? strong_finalizer_digest : weak_finalizer_digest; + + return pending_qc.add_vote(vote.strong, + std::vector{digest.data(), digest.data() + digest.data_size()}, + index, + vote.finalizer_key, + vote.sig); } else { wlog( "finalizer_key (${k}) in vote is not in finalizer policy", ("k", vote.finalizer_key) ); return false; From 006dacb4b773338f81843c6c1fe7e1090d441393 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 12 Jan 2024 16:44:39 -0500 Subject: [PATCH 05/13] add mutex to protect vote in pending_quorum_certificate --- libraries/chain/block_state.cpp | 1 + libraries/chain/controller.cpp | 4 +- libraries/chain/hotstuff/hotstuff.cpp | 7 ++- .../chain/hotstuff/test/hotstuff_tools.cpp | 44 ++++++++++++++++--- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index 67f6cab054..aa41cb1672 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -114,6 +114,7 @@ namespace eosio::chain { const digest_type& digest = vote.strong ? strong_finalizer_digest : weak_finalizer_digest; return pending_qc.add_vote(vote.strong, +#warning TODO change to use std::span if possible std::vector{digest.data(), digest.data() + digest.data_size()}, index, vote.finalizer_key, diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 233d6afb4e..3bf9070a4c 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -249,6 +249,7 @@ struct block_data_t { }, v); } + // called from net thread bool aggregate_vote(const hs_vote_message& vote) { return std::visit( overloaded{[](const block_data_legacy_t&) { @@ -259,9 +260,8 @@ struct block_data_t { if (bsp) { return bsp->aggregate_vote(vote); } else { - wlog("no block exists for the vote (proposal_id: ${id}", ("id", vote.proposal_id)); return false; - }} + }; } }, v); } diff --git a/libraries/chain/hotstuff/hotstuff.cpp b/libraries/chain/hotstuff/hotstuff.cpp index de83f59396..8d3afc5935 100644 --- a/libraries/chain/hotstuff/hotstuff.cpp +++ b/libraries/chain/hotstuff/hotstuff.cpp @@ -44,7 +44,8 @@ void pending_quorum_certificate::votes_t::reset(size_t num_finalizers) { pending_quorum_certificate::pending_quorum_certificate(size_t num_finalizers, size_t quorum) : _num_finalizers(num_finalizers) - , _quorum(quorum) { + , _quorum(quorum) + , _mtx(std::make_unique()) { _weak_votes.resize(num_finalizers); _strong_votes.resize(num_finalizers); } @@ -72,6 +73,7 @@ void pending_quorum_certificate::reset(const fc::sha256& proposal_id, const dige _state = state_t::unrestricted; } +// called by add_vote, already protected by mutex bool pending_quorum_certificate::add_strong_vote(const std::vector& proposal_digest, size_t index, const bls_public_key& pubkey, const bls_signature& sig) { assert(index < _num_finalizers); @@ -103,6 +105,7 @@ bool pending_quorum_certificate::add_strong_vote(const std::vector& pro return true; } +// called by add_vote, already protected by mutex bool pending_quorum_certificate::add_weak_vote(const std::vector& proposal_digest, size_t index, const bls_public_key& pubkey, const bls_signature& sig) { assert(index < _num_finalizers); @@ -138,8 +141,10 @@ bool pending_quorum_certificate::add_weak_vote(const std::vector& propo return true; } +// thread safe bool pending_quorum_certificate::add_vote(bool strong, const std::vector& proposal_digest, size_t index, const bls_public_key& pubkey, const bls_signature& sig) { + std::lock_guard g(*_mtx); return strong ? add_strong_vote(proposal_digest, index, pubkey, sig) : add_weak_vote(proposal_digest, index, pubkey, sig); } diff --git a/libraries/chain/hotstuff/test/hotstuff_tools.cpp b/libraries/chain/hotstuff/test/hotstuff_tools.cpp index 49326990ec..2254a5e487 100644 --- a/libraries/chain/hotstuff/test/hotstuff_tools.cpp +++ b/libraries/chain/hotstuff/test/hotstuff_tools.cpp @@ -100,11 +100,11 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { pubkey.push_back(k.get_public_key()); auto weak_vote = [&](pending_quorum_certificate& qc, const std::vector& digest, size_t index) { - return qc.add_weak_vote(digest, index, pubkey[index], sk[index].sign(digest)); + return qc.add_vote(false, digest, index, pubkey[index], sk[index].sign(digest)); }; auto strong_vote = [&](pending_quorum_certificate& qc, const std::vector& digest, size_t index) { - return qc.add_strong_vote(digest, index, pubkey[index], sk[index].sign(digest)); + return qc.add_vote(true, digest, index, pubkey[index], sk[index].sign(digest)); }; { @@ -180,7 +180,7 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { BOOST_CHECK(qc.is_quorum_met()); { - pending_quorum_certificate qc2(qc); + pending_quorum_certificate qc2(std::move(qc)); // add a weak vote // --------------- @@ -188,9 +188,25 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { BOOST_CHECK_EQUAL(qc2._state, state_t::weak_final); BOOST_CHECK(qc2.is_quorum_met()); } + } + + { + pending_quorum_certificate qc(3, 2); // 3 finalizers, quorum = 2 + + // add a weak vote + // --------------- + weak_vote(qc, digest, 0); + BOOST_CHECK_EQUAL(qc._state, state_t::unrestricted); + BOOST_CHECK(!qc.is_quorum_met()); + + // add a strong vote + // ----------------- + strong_vote(qc, digest, 1); + BOOST_CHECK_EQUAL(qc._state, state_t::weak_achieved); + BOOST_CHECK(qc.is_quorum_met()); { - pending_quorum_certificate qc2(qc); + pending_quorum_certificate qc2(std::move(qc)); // add a strong vote // ----------------- @@ -216,7 +232,7 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { BOOST_CHECK(qc.is_quorum_met()); { - pending_quorum_certificate qc2(qc); + pending_quorum_certificate qc2(std::move(qc)); // add a weak vote // --------------- @@ -224,9 +240,25 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { BOOST_CHECK_EQUAL(qc2._state, state_t::weak_final); BOOST_CHECK(qc2.is_quorum_met()); } + } + + { + pending_quorum_certificate qc(3, 2); // 3 finalizers, quorum = 2 + + // add a weak vote + // --------------- + weak_vote(qc, digest, 0); + BOOST_CHECK_EQUAL(qc._state, state_t::unrestricted); + BOOST_CHECK(!qc.is_quorum_met()); + + // add a weak vote + // --------------- + weak_vote(qc, digest, 1); + BOOST_CHECK_EQUAL(qc._state, state_t::weak_final); + BOOST_CHECK(qc.is_quorum_met()); { - pending_quorum_certificate qc2(qc); + pending_quorum_certificate qc2(std::move(qc)); // add a strong vote // ----------------- From da6a2aa9f8c41f55aa56d812b13337f6a70c4c21 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 12 Jan 2024 17:11:36 -0500 Subject: [PATCH 06/13] broadcast received vote message after it is processed --- libraries/chain/controller.cpp | 4 +-- .../chain/include/eosio/chain/controller.hpp | 2 +- .../include/eosio/chain/hotstuff/hotstuff.hpp | 28 ++++++++++++------- plugins/net_plugin/net_plugin.cpp | 6 +++- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 3bf9070a4c..775989fdb0 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -4024,8 +4024,8 @@ void controller::get_finalizer_state( finalizer_state& fs ) const { } // called from net threads -void controller::process_vote_message( const hs_vote_message& vote ) { - my->block_data.aggregate_vote(vote); +bool controller::process_vote_message( const hs_vote_message& vote ) { + return my->block_data.aggregate_vote(vote); }; const producer_authority_schedule& controller::active_producers()const { diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 26951e20cb..a9c59a6191 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -317,7 +317,7 @@ namespace eosio::chain { void set_proposed_finalizers( const finalizer_policy& fin_set ); void get_finalizer_state( finalizer_state& fs ) const; // called from net threads - void process_vote_message( const hs_vote_message& msg ); + bool process_vote_message( const hs_vote_message& msg ); bool light_validation_allowed() const; bool skip_auth_check()const; diff --git a/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp index 88bf7eb530..f732d5dc2a 100644 --- a/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp @@ -7,6 +7,8 @@ #include +#include + namespace eosio::chain { using hs_bitset = boost::dynamic_bitset; @@ -160,16 +162,7 @@ namespace eosio::chain { void reset(const fc::sha256& proposal_id, const digest_type& proposal_digest, size_t num_finalizers, size_t quorum); - bool add_strong_vote(const std::vector& proposal_digest, - size_t index, - const bls_public_key& pubkey, - const bls_signature& sig); - - bool add_weak_vote(const std::vector& proposal_digest, - size_t index, - const bls_public_key& pubkey, - const bls_signature& sig); - + // thread safe bool add_vote(bool strong, const std::vector& proposal_digest, size_t index, @@ -190,8 +183,23 @@ namespace eosio::chain { state_t _state { state_t::unrestricted }; size_t _num_finalizers {0}; size_t _quorum {0}; + std::unique_ptr _mtx; // protect both _strong_votes and _weak_votes votes_t _weak_votes; votes_t _strong_votes; + + private: +#warning TODO move members above to private after unification. Currently they are used by qc_chain.cpp directly + // called by add_vote, already protected by mutex + bool add_strong_vote(const std::vector& proposal_digest, + size_t index, + const bls_public_key& pubkey, + const bls_signature& sig); + + // called by add_vote, already protected by mutex + bool add_weak_vote(const std::vector& proposal_digest, + size_t index, + const bls_public_key& pubkey, + const bls_signature& sig); }; // -------------------- valid_quorum_certificate ------------------------------------------------- diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 845cf502e4..aeefaaacad 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -3676,7 +3676,11 @@ namespace eosio { void connection::handle_message( const chain::hs_vote_message& msg ) { peer_dlog(this, "received vote: ${msg}", ("msg", msg)); controller& cc = my_impl->chain_plug->chain(); - cc.process_vote_message(msg); + if( cc.process_vote_message(msg) ) { +#warning TDDO remove hs_message + hs_message hs_msg{msg}; + my_impl->bcast_hs_message(connection_id, hs_msg); + } } size_t calc_trx_size( const packed_transaction_ptr& trx ) { From 0eda04af05a7c8a45d66dc3d8aec5f1d31df34d8 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 12 Jan 2024 17:36:06 -0500 Subject: [PATCH 07/13] remove the warning for double vote --- libraries/chain/hotstuff/hotstuff.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/chain/hotstuff/hotstuff.cpp b/libraries/chain/hotstuff/hotstuff.cpp index 8d3afc5935..099e8e7825 100644 --- a/libraries/chain/hotstuff/hotstuff.cpp +++ b/libraries/chain/hotstuff/hotstuff.cpp @@ -23,7 +23,6 @@ inline std::vector bitset_to_vector(const hs_bitset& bs) { bool pending_quorum_certificate::votes_t::add_vote(const std::vector& proposal_digest, size_t index, const bls_public_key& pubkey, const bls_signature& new_sig) { if (_bitset[index]) { - wlog( "finalizer ${i} has already voted", ("i", index) ); return false; // shouldn't be already present } if (!fc::crypto::blslib::verify(pubkey, proposal_digest, new_sig)) { From ea3ae1fe36419586ddc3cbd3aba0fc9bb32a65a2 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 12 Jan 2024 19:07:10 -0500 Subject: [PATCH 08/13] create _mtx in default construtor of pending_quorum_certificate too --- libraries/chain/hotstuff/hotstuff.cpp | 4 ++++ libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/chain/hotstuff/hotstuff.cpp b/libraries/chain/hotstuff/hotstuff.cpp index 099e8e7825..db95138ae0 100644 --- a/libraries/chain/hotstuff/hotstuff.cpp +++ b/libraries/chain/hotstuff/hotstuff.cpp @@ -41,6 +41,10 @@ void pending_quorum_certificate::votes_t::reset(size_t num_finalizers) { _sig = bls_signature(); } +pending_quorum_certificate::pending_quorum_certificate() + : _mtx(std::make_unique()) { +} + pending_quorum_certificate::pending_quorum_certificate(size_t num_finalizers, size_t quorum) : _num_finalizers(num_finalizers) , _quorum(quorum) diff --git a/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp index f732d5dc2a..c648f8031f 100644 --- a/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp @@ -146,7 +146,7 @@ namespace eosio::chain { void reset(size_t num_finalizers); }; - pending_quorum_certificate() = default; + pending_quorum_certificate(); explicit pending_quorum_certificate(size_t num_finalizers, size_t quorum); From 01caa3fcaaee984a81f3683b269fdd96941889a8 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 16 Jan 2024 09:51:12 -0500 Subject: [PATCH 09/13] make pending_quorum_certificate thread safe and make members as private to prevent from direct accesses --- libraries/chain/block_state.cpp | 1 + libraries/chain/hotstuff/hotstuff.cpp | 18 ++++---- .../chain/hotstuff/test/hotstuff_tools.cpp | 44 +++++++++---------- .../include/eosio/chain/hotstuff/hotstuff.hpp | 19 +++++--- 4 files changed, 47 insertions(+), 35 deletions(-) diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index aa41cb1672..1e9f0319e5 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -103,6 +103,7 @@ namespace eosio::chain { {} #endif + // Called from net threads bool block_state::aggregate_vote(const hs_vote_message& vote) { const auto& finalizers = finalizer_policy->finalizers; auto it = std::find_if(finalizers.begin(), diff --git a/libraries/chain/hotstuff/hotstuff.cpp b/libraries/chain/hotstuff/hotstuff.cpp index db95138ae0..d59c347d21 100644 --- a/libraries/chain/hotstuff/hotstuff.cpp +++ b/libraries/chain/hotstuff/hotstuff.cpp @@ -62,11 +62,13 @@ pending_quorum_certificate::pending_quorum_certificate(const fc::sha256& propos } bool pending_quorum_certificate::is_quorum_met() const { + std::lock_guard g(*_mtx); return _state == state_t::weak_achieved || _state == state_t::weak_final || _state == state_t::strong; } void pending_quorum_certificate::reset(const fc::sha256& proposal_id, const digest_type& proposal_digest, size_t num_finalizers, size_t quorum) { + std::lock_guard g(*_mtx); _proposal_id = proposal_id; _proposal_digest.assign(proposal_digest.data(), proposal_digest.data() + 32); _quorum = quorum; @@ -169,15 +171,15 @@ std::string pending_quorum_certificate::get_votes_string() const { valid_quorum_certificate::valid_quorum_certificate(const pending_quorum_certificate& qc) - : _proposal_id(qc._proposal_id) - , _proposal_digest(qc._proposal_digest) { - if (qc._state == pending_quorum_certificate::state_t::strong) { - _strong_votes = qc._strong_votes._bitset; - _sig = qc._strong_votes._sig; + : _proposal_id(qc.proposal_id()) + , _proposal_digest(qc.proposal_digest()) { + if (qc.state() == pending_quorum_certificate::state_t::strong) { + _strong_votes = qc.strong_votes()._bitset; + _sig = qc.strong_votes()._sig; } else if (qc.is_quorum_met()) { - _strong_votes = qc._strong_votes._bitset; - _weak_votes = qc._weak_votes._bitset; - _sig = fc::crypto::blslib::aggregate({qc._strong_votes._sig, qc._weak_votes._sig}); + _strong_votes = qc.strong_votes()._bitset; + _weak_votes = qc.weak_votes()._bitset; + _sig = fc::crypto::blslib::aggregate({qc.strong_votes()._sig, qc.weak_votes()._sig}); } else assert(0); // this should be called only when we have a valid qc. } diff --git a/libraries/chain/hotstuff/test/hotstuff_tools.cpp b/libraries/chain/hotstuff/test/hotstuff_tools.cpp index 2254a5e487..1ecb2bbec4 100644 --- a/libraries/chain/hotstuff/test/hotstuff_tools.cpp +++ b/libraries/chain/hotstuff/test/hotstuff_tools.cpp @@ -109,58 +109,58 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { { pending_quorum_certificate qc(2, 1); // 2 finalizers, quorum = 1 - BOOST_CHECK_EQUAL(qc._state, state_t::unrestricted); + BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted); // add one weak vote // ----------------- weak_vote(qc, digest, 0); - BOOST_CHECK_EQUAL(qc._state, state_t::weak_achieved); + BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved); BOOST_CHECK(qc.is_quorum_met()); // add duplicate weak vote // ----------------------- bool ok = weak_vote(qc, digest, 0); BOOST_CHECK(!ok); // vote was a duplicate - BOOST_CHECK_EQUAL(qc._state, state_t::weak_achieved); + BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved); BOOST_CHECK(qc.is_quorum_met()); // add another weak vote // --------------------- weak_vote(qc, digest, 1); - BOOST_CHECK_EQUAL(qc._state, state_t::weak_final); + BOOST_CHECK_EQUAL(qc.state(), state_t::weak_final); } { pending_quorum_certificate qc(2, 1); // 2 finalizers, quorum = 1 - BOOST_CHECK_EQUAL(qc._state, state_t::unrestricted); + BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted); // add a weak vote // --------------- weak_vote(qc, digest, 0); - BOOST_CHECK_EQUAL(qc._state, state_t::weak_achieved); + BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved); BOOST_CHECK(qc.is_quorum_met()); // add a strong vote // ----------------- strong_vote(qc, digest, 1); - BOOST_CHECK_EQUAL(qc._state, state_t::strong); + BOOST_CHECK_EQUAL(qc.state(), state_t::strong); BOOST_CHECK(qc.is_quorum_met()); } { pending_quorum_certificate qc(2, 1); // 2 finalizers, quorum = 1 - BOOST_CHECK_EQUAL(qc._state, state_t::unrestricted); + BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted); // add a strong vote // ----------------- strong_vote(qc, digest, 1); - BOOST_CHECK_EQUAL(qc._state, state_t::strong); + BOOST_CHECK_EQUAL(qc.state(), state_t::strong); BOOST_CHECK(qc.is_quorum_met()); // add a strong vote // ----------------- strong_vote(qc, digest, 1); - BOOST_CHECK_EQUAL(qc._state, state_t::strong); + BOOST_CHECK_EQUAL(qc.state(), state_t::strong); BOOST_CHECK(qc.is_quorum_met()); } @@ -170,13 +170,13 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { // add a weak vote // --------------- weak_vote(qc, digest, 0); - BOOST_CHECK_EQUAL(qc._state, state_t::unrestricted); + BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted); BOOST_CHECK(!qc.is_quorum_met()); // add a strong vote // ----------------- strong_vote(qc, digest, 1); - BOOST_CHECK_EQUAL(qc._state, state_t::weak_achieved); + BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved); BOOST_CHECK(qc.is_quorum_met()); { @@ -185,7 +185,7 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { // add a weak vote // --------------- weak_vote(qc2, digest, 2); - BOOST_CHECK_EQUAL(qc2._state, state_t::weak_final); + BOOST_CHECK_EQUAL(qc2.state(), state_t::weak_final); BOOST_CHECK(qc2.is_quorum_met()); } } @@ -196,13 +196,13 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { // add a weak vote // --------------- weak_vote(qc, digest, 0); - BOOST_CHECK_EQUAL(qc._state, state_t::unrestricted); + BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted); BOOST_CHECK(!qc.is_quorum_met()); // add a strong vote // ----------------- strong_vote(qc, digest, 1); - BOOST_CHECK_EQUAL(qc._state, state_t::weak_achieved); + BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved); BOOST_CHECK(qc.is_quorum_met()); { @@ -211,7 +211,7 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { // add a strong vote // ----------------- strong_vote(qc2, digest, 2); - BOOST_CHECK_EQUAL(qc2._state, state_t::strong); + BOOST_CHECK_EQUAL(qc2.state(), state_t::strong); BOOST_CHECK(qc2.is_quorum_met()); } } @@ -222,13 +222,13 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { // add a weak vote // --------------- weak_vote(qc, digest, 0); - BOOST_CHECK_EQUAL(qc._state, state_t::unrestricted); + BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted); BOOST_CHECK(!qc.is_quorum_met()); // add a weak vote // --------------- weak_vote(qc, digest, 1); - BOOST_CHECK_EQUAL(qc._state, state_t::weak_final); + BOOST_CHECK_EQUAL(qc.state(), state_t::weak_final); BOOST_CHECK(qc.is_quorum_met()); { @@ -237,7 +237,7 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { // add a weak vote // --------------- weak_vote(qc2, digest, 2); - BOOST_CHECK_EQUAL(qc2._state, state_t::weak_final); + BOOST_CHECK_EQUAL(qc2.state(), state_t::weak_final); BOOST_CHECK(qc2.is_quorum_met()); } } @@ -248,13 +248,13 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { // add a weak vote // --------------- weak_vote(qc, digest, 0); - BOOST_CHECK_EQUAL(qc._state, state_t::unrestricted); + BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted); BOOST_CHECK(!qc.is_quorum_met()); // add a weak vote // --------------- weak_vote(qc, digest, 1); - BOOST_CHECK_EQUAL(qc._state, state_t::weak_final); + BOOST_CHECK_EQUAL(qc.state(), state_t::weak_final); BOOST_CHECK(qc.is_quorum_met()); { @@ -263,7 +263,7 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { // add a strong vote // ----------------- strong_vote(qc2, digest, 2); - BOOST_CHECK_EQUAL(qc2._state, state_t::weak_final); + BOOST_CHECK_EQUAL(qc2.state(), state_t::weak_final); BOOST_CHECK(qc2.is_quorum_met()); } } diff --git a/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp index c648f8031f..2b0c8936f6 100644 --- a/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp @@ -155,11 +155,10 @@ namespace eosio::chain { size_t num_finalizers, size_t quorum); - size_t num_weak() const { return _weak_votes.count(); } - size_t num_strong() const { return _strong_votes.count(); } - + // thread safe bool is_quorum_met() const; + // thread safe void reset(const fc::sha256& proposal_id, const digest_type& proposal_digest, size_t num_finalizers, size_t quorum); // thread safe @@ -169,6 +168,12 @@ namespace eosio::chain { const bls_public_key& pubkey, const bls_signature& sig); + fc::sha256 proposal_id() const { std::lock_guard g(*_mtx); return _proposal_id; }; + state_t state() const { std::lock_guard g(*_mtx); return _state; }; + votes_t weak_votes() const { std::lock_guard g(*_mtx); return _weak_votes; }; + votes_t strong_votes() const { std::lock_guard g(*_mtx); return _strong_votes; }; + std::vector proposal_digest() const { std::lock_guard g(*_mtx); return _proposal_digest; }; + // ================== begin compatibility functions ======================= // these are present just to make the tests still work. will be removed. // these assume *only* strong votes. @@ -177,7 +182,9 @@ namespace eosio::chain { std::string get_votes_string() const; // ================== end compatibility functions ======================= + private: friend struct fc::reflector; + friend class qc_chain; fc::sha256 _proposal_id; // only used in to_msg(). Remove eventually std::vector _proposal_digest; state_t _state { state_t::unrestricted }; @@ -187,8 +194,10 @@ namespace eosio::chain { votes_t _weak_votes; votes_t _strong_votes; - private: -#warning TODO move members above to private after unification. Currently they are used by qc_chain.cpp directly + // num_weak and num_strong are protected by mutex by add_vote + size_t num_weak() const { return _weak_votes.count(); } + size_t num_strong() const { return _strong_votes.count(); } + // called by add_vote, already protected by mutex bool add_strong_vote(const std::vector& proposal_digest, size_t index, From cf0757602c24f4fefa818444808cecd6e8cd10a8 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 16 Jan 2024 10:57:00 -0500 Subject: [PATCH 10/13] fix a merging conflict --- libraries/chain/block_state.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index c078cf70b1..96ab9611c1 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -55,14 +55,14 @@ void block_state::set_trxs_metas( deque&& trxs_metas, // Called from net threads bool block_state::aggregate_vote(const hs_vote_message& vote) { - const auto& finalizers = finalizer_policy->finalizers; + const auto& finalizers = active_finalizer_policy->finalizers; auto it = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& finalizer) { return finalizer.public_key == vote.finalizer_key; }); if (it != finalizers.end()) { auto index = std::distance(finalizers.begin(), it); - const digest_type& digest = vote.strong ? strong_finalizer_digest : weak_finalizer_digest; + const digest_type& digest = vote.strong ? strong_digest : weak_digest; return pending_qc.add_vote(vote.strong, #warning TODO change to use std::span if possible std::vector{digest.data(), digest.data() + digest.data_size()}, From 425f0c20ea6ea1afd67fbb793122b2c88ed8668f Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 16 Jan 2024 11:19:13 -0500 Subject: [PATCH 11/13] one more merging conflict --- unittests/block_state_tests.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/unittests/block_state_tests.cpp b/unittests/block_state_tests.cpp index cf9cdd81bb..28ad30258c 100644 --- a/unittests/block_state_tests.cpp +++ b/unittests/block_state_tests.cpp @@ -39,9 +39,9 @@ BOOST_AUTO_TEST_CASE(aggregate_vote_test) try { { // all finalizers can aggregate votes block_state_ptr bsp = std::make_shared(); - bsp->finalizer_policy = std::make_shared( 10, 15, finalizers ); - bsp->strong_finalizer_digest = strong_digest; - bsp->weak_finalizer_digest = weak_digest; + bsp->active_finalizer_policy = std::make_shared( 10, 15, finalizers ); + bsp->strong_digest = strong_digest; + bsp->weak_digest = weak_digest; bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 }; for (size_t i = 0; i < num_finalizers; ++i) { @@ -54,8 +54,8 @@ BOOST_AUTO_TEST_CASE(aggregate_vote_test) try { { // public and private keys mismatched block_state_ptr bsp = std::make_shared(); - bsp->finalizer_policy = std::make_shared( 10, 15, finalizers ); - bsp->strong_finalizer_digest = strong_digest; + bsp->active_finalizer_policy = std::make_shared( 10, 15, finalizers ); + bsp->strong_digest = strong_digest; bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 }; hs_vote_message vote {block_id, true, public_key[0], private_key[1].sign(strong_digest_data) }; @@ -64,8 +64,8 @@ BOOST_AUTO_TEST_CASE(aggregate_vote_test) try { { // duplicate votes block_state_ptr bsp = std::make_shared(); - bsp->finalizer_policy = std::make_shared( 10, 15, finalizers ); - bsp->strong_finalizer_digest = strong_digest; + bsp->active_finalizer_policy = std::make_shared( 10, 15, finalizers ); + bsp->strong_digest = strong_digest; bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 }; hs_vote_message vote {block_id, true, public_key[0], private_key[0].sign(strong_digest_data) }; @@ -75,8 +75,8 @@ BOOST_AUTO_TEST_CASE(aggregate_vote_test) try { { // public key does not exit in finalizer set block_state_ptr bsp = std::make_shared(); - bsp->finalizer_policy = std::make_shared( 10, 15, finalizers ); - bsp->strong_finalizer_digest = strong_digest; + bsp->active_finalizer_policy = std::make_shared( 10, 15, finalizers ); + bsp->strong_digest = strong_digest; bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 }; bls_private_key new_private_key{ "PVT_BLS_warwI76e+pPX9wLFZKPFagngeFM8bm6J8D5w0iiHpxW7PiId" }; From c3e2f005443b9e6057171c0bb86fd43f58d98610 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 16 Jan 2024 14:26:45 -0500 Subject: [PATCH 12/13] provide pending_quorum_certificate::to_valid_quorum_certificate() for easier thread safety; remove valid_quorum_certificate(const pending_quorum_certificate&) --- libraries/chain/hotstuff/hotstuff.cpp | 36 ++++---- libraries/chain/hotstuff/qc_chain.cpp | 2 +- .../include/eosio/chain/hotstuff/hotstuff.hpp | 83 +++++++++---------- 3 files changed, 61 insertions(+), 60 deletions(-) diff --git a/libraries/chain/hotstuff/hotstuff.cpp b/libraries/chain/hotstuff/hotstuff.cpp index d59c347d21..200331842e 100644 --- a/libraries/chain/hotstuff/hotstuff.cpp +++ b/libraries/chain/hotstuff/hotstuff.cpp @@ -154,6 +154,27 @@ bool pending_quorum_certificate::add_vote(bool strong, const std::vector& proposal_digest, const std::vector& strong_votes, // bitset encoding, following canonical order diff --git a/libraries/chain/hotstuff/qc_chain.cpp b/libraries/chain/hotstuff/qc_chain.cpp index 2336fb7c75..8315901810 100644 --- a/libraries/chain/hotstuff/qc_chain.cpp +++ b/libraries/chain/hotstuff/qc_chain.cpp @@ -372,7 +372,7 @@ namespace eosio::chain { ("id", _id)); //fc_tlog(_logger, " === update_high_qc : _current_qc ==="); - update_high_qc(_current_qc); + update_high_qc(_current_qc.to_valid_quorum_certificate()); fc_dlog(_logger, " === ${id} quorum met on #${block_num} ${phase_counter} ${proposal_id} ", ("block_num", p->block_num()) ("phase_counter", p->phase_counter) diff --git a/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp index 2b0c8936f6..1d1b6e57bb 100644 --- a/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp @@ -122,6 +122,43 @@ namespace eosio::chain { using bls_signature = fc::crypto::blslib::bls_signature; using bls_private_key = fc::crypto::blslib::bls_private_key; + // -------------------- valid_quorum_certificate ------------------------------------------------- + class valid_quorum_certificate { + public: + valid_quorum_certificate(const fc::sha256& proposal_id, + const std::vector& proposal_digest, + const std::vector& strong_votes, //bitset encoding, following canonical order + const std::vector& weak_votes, //bitset encoding, following canonical order + const bls_signature& sig); + + valid_quorum_certificate() = default; + valid_quorum_certificate(const valid_quorum_certificate&) = default; + + bool is_weak() const { return !!_weak_votes; } + bool is_strong() const { return !_weak_votes; } + + // ================== begin compatibility functions ======================= + // these are present just to make the tests still work. will be removed. + // these assume *only* strong votes. + quorum_certificate_message to_msg() const; + const fc::sha256& get_proposal_id() const { return _proposal_id; } + // ================== end compatibility functions ======================= + + friend struct fc::reflector; + fc::sha256 _proposal_id; // [todo] remove + std::vector _proposal_digest; // [todo] remove + std::optional _strong_votes; + std::optional _weak_votes; + bls_signature _sig; + }; + + // -------------------- quorum_certificate ------------------------------------------------------- + struct quorum_certificate { + uint32_t block_height; + valid_quorum_certificate qc; + }; + + // -------------------- pending_quorum_certificate ------------------------------------------------- class pending_quorum_certificate { public: @@ -168,11 +205,8 @@ namespace eosio::chain { const bls_public_key& pubkey, const bls_signature& sig); - fc::sha256 proposal_id() const { std::lock_guard g(*_mtx); return _proposal_id; }; - state_t state() const { std::lock_guard g(*_mtx); return _state; }; - votes_t weak_votes() const { std::lock_guard g(*_mtx); return _weak_votes; }; - votes_t strong_votes() const { std::lock_guard g(*_mtx); return _strong_votes; }; - std::vector proposal_digest() const { std::lock_guard g(*_mtx); return _proposal_digest; }; + state_t state() const { std::lock_guard g(*_mtx); return _state; }; + valid_quorum_certificate to_valid_quorum_certificate() const; // ================== begin compatibility functions ======================= // these are present just to make the tests still work. will be removed. @@ -210,45 +244,6 @@ namespace eosio::chain { const bls_public_key& pubkey, const bls_signature& sig); }; - - // -------------------- valid_quorum_certificate ------------------------------------------------- - class valid_quorum_certificate { - public: - valid_quorum_certificate(const pending_quorum_certificate& qc); - - valid_quorum_certificate(const fc::sha256& proposal_id, - const std::vector& proposal_digest, - const std::vector& strong_votes, //bitset encoding, following canonical order - const std::vector& weak_votes, //bitset encoding, following canonical order - const bls_signature& sig); - - valid_quorum_certificate() = default; - valid_quorum_certificate(const valid_quorum_certificate&) = default; - - bool is_weak() const { return !!_weak_votes; } - bool is_strong() const { return !_weak_votes; } - - // ================== begin compatibility functions ======================= - // these are present just to make the tests still work. will be removed. - // these assume *only* strong votes. - quorum_certificate_message to_msg() const; - const fc::sha256& get_proposal_id() const { return _proposal_id; } - // ================== end compatibility functions ======================= - - friend struct fc::reflector; - fc::sha256 _proposal_id; // [todo] remove - std::vector _proposal_digest; // [todo] remove - std::optional _strong_votes; - std::optional _weak_votes; - bls_signature _sig; - }; - - // -------------------- quorum_certificate ------------------------------------------------------- - struct quorum_certificate { - uint32_t block_height; - valid_quorum_certificate qc; - }; - } //eosio::chain From 0db523db6c2df5bb8a1efe7d9bcf474acebb32a7 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 17 Jan 2024 08:56:27 -0500 Subject: [PATCH 13/13] do not assert when receiving a vote in legacy --- libraries/chain/controller.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 3a706f0f94..9f1034cc69 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -301,19 +301,16 @@ struct block_data_t { }, v); } - // called from net thread + // called from net thread bool aggregate_vote(const hs_vote_message& vote) { return std::visit( overloaded{[](const block_data_legacy_t&) { - EOS_ASSERT(false, misc_exception, "attempting to call aggregate_vote in legacy mode"); + // We can be late in switching to Instant Finality + // and receive votes from those already having switched. return false; }, [&](const block_data_new_t& bd) { auto bsp = bd.fork_db.get_block(vote.proposal_id); - if (bsp) { - return bsp->aggregate_vote(vote); - } else { - return false; - }; } + return bsp && bsp->aggregate_vote(vote); } }, v); }