diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index 74865cabcc..e01a811864 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -69,7 +69,7 @@ void block_state::set_trxs_metas( deque&& trxs_metas, } // Called from net threads -std::pair> block_state::aggregate_vote(const vote_message& vote) { +std::pair> block_state::aggregate_vote(const vote_message& vote) { const auto& finalizers = active_finalizer_policy->finalizers; auto it = std::find_if(finalizers.begin(), finalizers.end(), @@ -78,17 +78,17 @@ std::pair> block_state::aggregate_vote(const vote_ if (it != finalizers.end()) { auto index = std::distance(finalizers.begin(), it); const digest_type& digest = vote.strong ? strong_digest : weak_digest; - auto [valid, strong] = pending_qc.add_vote(vote.strong, + auto [status, strong] = 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, vote.sig, finalizers[index].weight); - return {valid, strong ? core.final_on_strong_qc_block_num : std::optional{}}; + return {status, strong ? core.final_on_strong_qc_block_num : std::optional{}}; } else { wlog( "finalizer_key (${k}) in vote is not in finalizer policy", ("k", vote.finalizer_key) ); - return {}; + return {vote_status::unknown_public_key, {}}; } } @@ -116,12 +116,12 @@ void block_state::verify_qc(const valid_quorum_certificate& qc) const { // verfify quorum is met if( qc.is_strong() ) { EOS_ASSERT( strong_weights >= active_finalizer_policy->threshold, - block_validate_exception, + invalid_qc_claim, "strong quorum is not met, strong_weights: ${s}, threshold: ${t}", ("s", strong_weights)("t", active_finalizer_policy->threshold) ); } else { EOS_ASSERT( strong_weights + weak_weights >= active_finalizer_policy->threshold, - block_validate_exception, + invalid_qc_claim, "weak quorum is not met, strong_weights: ${s}, weak_weights: ${w}, threshold: ${t}", ("s", strong_weights)("w", weak_weights)("t", active_finalizer_policy->threshold) ); } @@ -155,7 +155,7 @@ void block_state::verify_qc(const valid_quorum_certificate& qc) const { } // validate aggregated signature - EOS_ASSERT( fc::crypto::blslib::aggregate_verify( pubkeys, digests, qc._sig ), block_validate_exception, "signature validation failed" ); + EOS_ASSERT( fc::crypto::blslib::aggregate_verify( pubkeys, digests, qc._sig ), invalid_qc_claim, "signature validation failed" ); } std::optional block_state::get_best_qc() const { diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 2e11252a28..f5a58e5a19 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -2999,18 +2999,18 @@ struct controller_impl { } /// apply_block // called from net threads and controller's thread pool - bool process_vote_message( const vote_message& vote ) { - auto do_vote = [&vote](auto& forkdb) -> std::pair> { + vote_status process_vote_message( const vote_message& vote ) { + auto do_vote = [&vote](auto& forkdb) -> std::pair> { auto bsp = forkdb.get_block(vote.proposal_id); if (bsp) return bsp->aggregate_vote(vote); - return {false, {}}; + return {vote_status::unknown_block, {}}; }; - auto [valid, new_lib] = fork_db.apply_if>>(do_vote); + auto [status, new_lib] = fork_db.apply_if>>(do_vote); if (new_lib) { set_if_irreversible_block_num(*new_lib); } - return valid; + return status; }; void create_and_send_vote_msg(const block_state_ptr& bsp) { @@ -3097,12 +3097,12 @@ struct controller_impl { // block doesn't have a header extension either. Then return early. // ------------------------------------------------------------------------------------------ EOS_ASSERT( !qc_extension_present, - block_validate_exception, + invalid_qc_claim, "Block #${b} includes a QC block extension, but doesn't have a finality header extension", ("b", block_num) ); EOS_ASSERT( !prev_header_ext, - block_validate_exception, + invalid_qc_claim, "Block #${b} doesn't have a finality header extension even though its predecessor does.", ("b", block_num) ); return; @@ -3118,7 +3118,7 @@ struct controller_impl { // ------------------------------------------------------------------------------------------------- if (!prev_header_ext) { EOS_ASSERT( !qc_extension_present && qc_claim.last_qc_block_num == block_num && qc_claim.is_last_qc_strong == false, - block_validate_exception, + invalid_qc_claim, "Block #${b}, which is the finality transition block, doesn't have the expected extensions", ("b", block_num) ); return; @@ -3136,7 +3136,7 @@ struct controller_impl { // new claimed QC block number cannot be smaller than previous block's EOS_ASSERT( qc_claim.last_qc_block_num >= prev_qc_claim.last_qc_block_num, - block_validate_exception, + invalid_qc_claim, "Block #${b} claims a last_qc_block_num (${n1}) less than the previous block's (${n2})", ("n1", qc_claim.last_qc_block_num)("n2", prev_qc_claim.last_qc_block_num)("b", block_num) ); @@ -3144,7 +3144,7 @@ struct controller_impl { if( qc_claim.is_last_qc_strong == prev_qc_claim.is_last_qc_strong ) { // QC block extension is redundant EOS_ASSERT( !qc_extension_present, - block_validate_exception, + invalid_qc_claim, "Block #${b} should not provide a QC block extension since its QC claim is the same as the previous block's", ("b", block_num) ); @@ -3155,14 +3155,14 @@ struct controller_impl { // new claimed QC must be stronger than previous if the claimed block number is the same EOS_ASSERT( qc_claim.is_last_qc_strong, - block_validate_exception, + invalid_qc_claim, "claimed QC (${s1}) must be stricter than previous block's (${s2}) if block number is the same. Block number: ${b}", ("s1", qc_claim.is_last_qc_strong)("s2", prev_qc_claim.is_last_qc_strong)("b", block_num) ); } // At this point, we are making a new claim in this block, so it better include a QC to justify this claim. EOS_ASSERT( qc_extension_present, - block_validate_exception, + invalid_qc_claim, "Block #${b} is making a new finality claim, but doesn't include a qc to justify this claim", ("b", block_num) ); const auto& qc_ext = std::get(block_exts.lower_bound(qc_ext_id)->second); @@ -3170,20 +3170,20 @@ struct controller_impl { // Check QC information in header extension and block extension match EOS_ASSERT( qc_proof.block_num == qc_claim.last_qc_block_num, - block_validate_exception, + invalid_qc_claim, "Block #${b}: Mismatch between qc.block_num (${n1}) in block extension and last_qc_block_num (${n2}) in header extension", ("n1", qc_proof.block_num)("n2", qc_claim.last_qc_block_num)("b", block_num) ); // Verify claimed strictness is the same as in proof EOS_ASSERT( qc_proof.qc.is_strong() == qc_claim.is_last_qc_strong, - block_validate_exception, + invalid_qc_claim, "QC is_strong (${s1}) in block extension does not match is_last_qc_strong (${s2}) in header extension. Block number: ${b}", ("s1", qc_proof.qc.is_strong())("s2", qc_claim.is_last_qc_strong)("b", block_num) ); // find the claimed block's block state on branch of id auto bsp = fork_db_fetch_bsp_by_num( prev.id, qc_claim.last_qc_block_num ); EOS_ASSERT( bsp, - block_validate_exception, + invalid_qc_claim, "Block state was not found in forkdb for last_qc_block_num ${q}. Block number: ${b}", ("q", qc_claim.last_qc_block_num)("b", block_num) ); @@ -4402,7 +4402,7 @@ void controller::set_proposed_finalizers( const finalizer_policy& fin_pol ) { } // called from net threads -bool controller::process_vote_message( const vote_message& vote ) { +vote_status controller::process_vote_message( const vote_message& vote ) { return my->process_vote_message( vote ); }; diff --git a/libraries/chain/hotstuff/hotstuff.cpp b/libraries/chain/hotstuff/hotstuff.cpp index e2f361ff1e..93642aebf7 100644 --- a/libraries/chain/hotstuff/hotstuff.cpp +++ b/libraries/chain/hotstuff/hotstuff.cpp @@ -20,18 +20,18 @@ inline std::vector bitset_to_vector(const hs_bitset& bs) { return r; } -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) { +vote_status 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]) { - return false; // shouldn't be already present + return vote_status::duplicate; // shouldn't be already present } if (!fc::crypto::blslib::verify(pubkey, proposal_digest, new_sig)) { wlog( "signature from finalizer ${i} cannot be verified", ("i", index) ); - return false; + return vote_status::invalid_signature; } _bitset.set(index); _sig = fc::crypto::blslib::aggregate({_sig, new_sig}); // works even if _sig is default initialized (fp2::zero()) - return true; + return vote_status::success; } void pending_quorum_certificate::votes_t::reset(size_t num_finalizers) { @@ -59,11 +59,11 @@ bool pending_quorum_certificate::is_quorum_met() const { } // 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, - uint64_t weight) { - if (!_strong_votes.add_vote(proposal_digest, index, pubkey, sig)) - return false; +vote_status pending_quorum_certificate::add_strong_vote(const std::vector& proposal_digest, size_t index, + const bls_public_key& pubkey, const bls_signature& sig, + uint64_t weight) { + if (auto s = _strong_votes.add_vote(proposal_digest, index, pubkey, sig); s != vote_status::success) + return s; _strong_sum += weight; switch (_state) { @@ -86,15 +86,15 @@ bool pending_quorum_certificate::add_strong_vote(const std::vector& pro // getting another strong vote...nothing to do break; } - return true; + return vote_status::success; } // 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, - uint64_t weight) { - if (!_weak_votes.add_vote(proposal_digest, index, pubkey, sig)) - return false; +vote_status pending_quorum_certificate::add_weak_vote(const std::vector& proposal_digest, size_t index, + const bls_public_key& pubkey, const bls_signature& sig, + uint64_t weight) { + if (auto s = _weak_votes.add_vote(proposal_digest, index, pubkey, sig); s != vote_status::success) + return s; _weak_sum += weight; switch (_state) { @@ -121,17 +121,17 @@ bool pending_quorum_certificate::add_weak_vote(const std::vector& propo // getting another weak vote... nothing to do break; } - return true; + return vote_status::success; } // thread safe, -std::pair pending_quorum_certificate::add_vote(bool strong, const std::vector& proposal_digest, size_t index, - const bls_public_key& pubkey, const bls_signature& sig, - uint64_t weight) { +std::pair pending_quorum_certificate::add_vote(bool strong, const std::vector& proposal_digest, size_t index, + const bls_public_key& pubkey, const bls_signature& sig, + uint64_t weight) { std::lock_guard g(*_mtx); - bool valid = strong ? add_strong_vote(proposal_digest, index, pubkey, sig, weight) - : add_weak_vote(proposal_digest, index, pubkey, sig, weight); - return {valid, _state == state_t::strong}; + vote_status s = strong ? add_strong_vote(proposal_digest, index, pubkey, sig, weight) + : add_weak_vote(proposal_digest, index, pubkey, sig, weight); + return {s, _state == state_t::strong}; } // thread safe diff --git a/libraries/chain/hotstuff/test/finality_misc_tests.cpp b/libraries/chain/hotstuff/test/finality_misc_tests.cpp index 9f1726f07b..418d82116c 100644 --- a/libraries/chain/hotstuff/test/finality_misc_tests.cpp +++ b/libraries/chain/hotstuff/test/finality_misc_tests.cpp @@ -74,8 +74,8 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try { // add duplicate weak vote // ----------------------- - bool ok = weak_vote(qc, digest, 0, weight); - BOOST_CHECK(!ok); // vote was a duplicate + auto ok = weak_vote(qc, digest, 0, weight); + BOOST_CHECK(ok != vote_status::success); // vote was a duplicate BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved); BOOST_CHECK(qc.is_quorum_met()); diff --git a/libraries/chain/include/eosio/chain/block_state.hpp b/libraries/chain/include/eosio/chain/block_state.hpp index 4548c2804f..9492ca0591 100644 --- a/libraries/chain/include/eosio/chain/block_state.hpp +++ b/libraries/chain/include/eosio/chain/block_state.hpp @@ -39,7 +39,7 @@ struct block_state : public block_header_state { // block_header_state provi void set_trxs_metas(deque&& trxs_metas, bool keys_recovered); const deque& trxs_metas() const { return cached_trxs; } - std::pair> aggregate_vote(const vote_message& vote); // aggregate vote into pending_qc + std::pair> aggregate_vote(const vote_message& vote); // aggregate vote into pending_qc void verify_qc(const valid_quorum_certificate& qc) const; // verify given qc is valid with respect block_state using bhs_t = block_header_state; diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 931a3070b1..9334f69fff 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -326,7 +327,7 @@ namespace eosio::chain { // called by host function set_finalizers void set_proposed_finalizers( const finalizer_policy& fin_set ); // called from net threads - bool process_vote_message( const vote_message& msg ); + vote_status process_vote_message( const vote_message& msg ); bool light_validation_allowed() const; bool skip_auth_check()const; diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index 22aa819574..f7a41b640d 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -255,6 +255,8 @@ namespace eosio { namespace chain { 3030012, "Invalid block extension" ) FC_DECLARE_DERIVED_EXCEPTION( ill_formed_additional_block_signatures_extension, block_validate_exception, 3030013, "Block includes an ill-formed additional block signature extension" ) + FC_DECLARE_DERIVED_EXCEPTION( invalid_qc_claim, block_validate_exception, + 3030014, "Block includes an invalid QC claim" ) FC_DECLARE_DERIVED_EXCEPTION( transaction_exception, chain_exception, 3040000, "Transaction exception" ) diff --git a/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp index a11e32653d..e2003fa313 100644 --- a/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp @@ -92,6 +92,14 @@ namespace eosio::chain { invalid // invalid message (other reason) }; + enum class vote_status { + success, + duplicate, + unknown_public_key, + invalid_signature, + unknown_block + }; + using bls_public_key = fc::crypto::blslib::bls_public_key; using bls_signature = fc::crypto::blslib::bls_signature; using bls_private_key = fc::crypto::blslib::bls_private_key; @@ -151,8 +159,8 @@ namespace eosio::chain { void resize(size_t num_finalizers) { _bitset.resize(num_finalizers); } size_t count() const { return _bitset.count(); } - bool add_vote(const std::vector& proposal_digest, size_t index, const bls_public_key& pubkey, - const bls_signature& new_sig); + vote_status add_vote(const std::vector& proposal_digest, size_t index, const bls_public_key& pubkey, + const bls_signature& new_sig); void reset(size_t num_finalizers); }; @@ -165,12 +173,12 @@ namespace eosio::chain { bool is_quorum_met() const; // thread safe - std::pair add_vote(bool strong, - const std::vector&proposal_digest, - size_t index, - const bls_public_key&pubkey, - const bls_signature&sig, - uint64_t weight); + std::pair add_vote(bool strong, + const std::vector&proposal_digest, + size_t index, + const bls_public_key&pubkey, + const bls_signature&sig, + uint64_t weight); state_t state() const { std::lock_guard g(*_mtx); return _state; }; valid_quorum_certificate to_valid_quorum_certificate() const; @@ -198,18 +206,18 @@ namespace eosio::chain { votes_t _strong_votes; // 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, - uint64_t weight); + vote_status add_strong_vote(const std::vector& proposal_digest, + size_t index, + const bls_public_key& pubkey, + const bls_signature& sig, + uint64_t weight); // 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, - uint64_t weight); + vote_status add_weak_vote(const std::vector& proposal_digest, + size_t index, + const bls_public_key& pubkey, + const bls_signature& sig, + uint64_t weight); }; } //eosio::chain diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 5403b65866..1b91f21cfe 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -261,13 +261,17 @@ namespace eosio { bool verify_catchup( const connection_ptr& c, uint32_t num, const block_id_type& id ); // locks mutex public: + enum class closing_mode { + immediately, // closing connection immediately + handshake // sending handshake message + }; explicit sync_manager( uint32_t span, uint32_t sync_peer_limit, uint32_t min_blocks_distance ); static void send_handshakes(); bool syncing_from_peer() const { return sync_state == lib_catchup; } bool is_in_sync() const { return sync_state == in_sync; } void sync_reset_lib_num( const connection_ptr& conn, bool closing ); void sync_reassign_fetch( const connection_ptr& c, go_away_reason reason ); - void rejected_block( const connection_ptr& c, uint32_t blk_num ); + void rejected_block( const connection_ptr& c, uint32_t blk_num, closing_mode mode ); void sync_recv_block( const connection_ptr& c, const block_id_type& blk_id, uint32_t blk_num, bool blk_applied ); void recv_handshake( const connection_ptr& c, const handshake_message& msg, uint32_t nblk_combined_latency ); void sync_recv_notice( const connection_ptr& c, const notice_message& msg ); @@ -2437,18 +2441,22 @@ namespace eosio { } // called from connection strand - void sync_manager::rejected_block( const connection_ptr& c, uint32_t blk_num ) { + void sync_manager::rejected_block( const connection_ptr& c, uint32_t blk_num, closing_mode mode ) { c->block_status_monitor_.rejected(); fc::unique_lock g( sync_mtx ); sync_last_requested_num = 0; if (blk_num < sync_next_expected_num) { sync_next_expected_num = my_impl->get_chain_lib_num(); } - if( c->block_status_monitor_.max_events_violated()) { + if( mode == closing_mode::immediately || c->block_status_monitor_.max_events_violated()) { peer_wlog( c, "block ${bn} not accepted, closing connection", ("bn", blk_num) ); sync_source.reset(); g.unlock(); - c->close(); + if( mode == closing_mode::immediately ) { + c->close( false ); // do not reconnect + } else { + c->close(); + } } else { g.unlock(); peer_dlog(c, "rejected block ${bn}, sending handshake", ("bn", blk_num)); @@ -3691,8 +3699,22 @@ namespace eosio { ("bn", block_header::num_from_id(msg.proposal_id))("id", msg.proposal_id.str().substr(8,16)) ("t", msg.strong ? "strong" : "weak")("k", msg.finalizer_key.to_string().substr(8, 16))); controller& cc = my_impl->chain_plug->chain(); - if( cc.process_vote_message(msg) ) { - my_impl->bcast_vote_message(connection_id, msg); + + switch( cc.process_vote_message(msg) ) { + case vote_status::success: + my_impl->bcast_vote_message(connection_id, msg); + break; + case vote_status::unknown_public_key: + case vote_status::invalid_signature: // close peer immediately + close( false ); // do not reconnect after closing + break; + case vote_status::unknown_block: // track the failure + block_status_monitor_.rejected(); + break; + case vote_status::duplicate: // do nothing + break; + default: + assert(false); // should never happen } } @@ -3746,9 +3768,15 @@ namespace eosio { std::optional obt; bool exception = false; + sync_manager::closing_mode close_mode = sync_manager::closing_mode::handshake; try { // this may return null if block is not immediately ready to be processed obt = cc.create_block_handle( id, ptr ); + } catch( const invalid_qc_claim &ex) { + exception = true; + close_mode = sync_manager::closing_mode::immediately; + fc_wlog( logger, "invalid QC claim exception, connection ${cid}: #${n} ${id}...: ${m}", + ("cid", cid)("n", ptr->block_num())("id", id.str().substr(8,16))("m",ex.to_string())); } catch( const fc::exception& ex ) { exception = true; fc_ilog( logger, "bad block exception connection ${cid}: #${n} ${id}...: ${m}", @@ -3759,8 +3787,8 @@ namespace eosio { ("cid", cid)("n", ptr->block_num())("id", id.str().substr(8,16))); } if( exception ) { - c->strand.post( [c, id, blk_num=ptr->block_num()]() { - my_impl->sync_master->rejected_block( c, blk_num ); + c->strand.post( [c, id, blk_num=ptr->block_num(), close_mode]() { + my_impl->sync_master->rejected_block( c, blk_num, close_mode ); my_impl->dispatcher->rejected_block( id ); }); return; @@ -3873,7 +3901,7 @@ namespace eosio { } // reason==no_reason means accept_block() return false because we are producing, don't call rejected_block which sends handshake if( reason != no_reason ) { - sync_master->rejected_block( c, blk_num ); + sync_master->rejected_block( c, blk_num, sync_manager::closing_mode::handshake ); } dispatcher->rejected_block( blk_id ); }); diff --git a/unittests/block_state_tests.cpp b/unittests/block_state_tests.cpp index eb1295e41a..dfe074afa4 100644 --- a/unittests/block_state_tests.cpp +++ b/unittests/block_state_tests.cpp @@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(aggregate_vote_test) try { 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); vote_message vote{ block_id, strong, public_key[i], sig }; - BOOST_REQUIRE(bsp->aggregate_vote(vote).first); + BOOST_REQUIRE(bsp->aggregate_vote(vote).first == vote_status::success); } } @@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(aggregate_vote_test) try { bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1, bsp->active_finalizer_policy->max_weak_sum_before_weak_final() }; vote_message vote {block_id, true, public_key[0], private_key[1].sign(strong_digest_data) }; - BOOST_REQUIRE(!bsp->aggregate_vote(vote).first); + BOOST_REQUIRE(bsp->aggregate_vote(vote).first != vote_status::success); } { // duplicate votes @@ -70,8 +70,9 @@ BOOST_AUTO_TEST_CASE(aggregate_vote_test) try { bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1, bsp->active_finalizer_policy->max_weak_sum_before_weak_final() }; vote_message vote {block_id, true, public_key[0], private_key[0].sign(strong_digest_data) }; - BOOST_REQUIRE(bsp->aggregate_vote(vote).first); - BOOST_REQUIRE(!bsp->aggregate_vote(vote).first); + + BOOST_REQUIRE(bsp->aggregate_vote(vote).first == vote_status::success); // first time succeeds + BOOST_REQUIRE(bsp->aggregate_vote(vote).first != vote_status::success); // second time failed due to duplicate voting } { // public key does not exit in finalizer set @@ -84,7 +85,7 @@ BOOST_AUTO_TEST_CASE(aggregate_vote_test) try { bls_public_key new_public_key{ new_private_key.get_public_key() }; vote_message vote {block_id, true, new_public_key, private_key[0].sign(strong_digest_data) }; - BOOST_REQUIRE(!bsp->aggregate_vote(vote).first); + BOOST_REQUIRE(bsp->aggregate_vote(vote).first != vote_status::success); } } FC_LOG_AND_RETHROW(); @@ -129,7 +130,7 @@ void do_quorum_test(const std::vector& weights, if( to_vote[i] ) { auto sig = strong ? private_key[i].sign(strong_digest_data) : private_key[i].sign(weak_digest_data); vote_message vote{ block_id, strong, public_key[i], sig }; - BOOST_REQUIRE(bsp->aggregate_vote(vote).first); + BOOST_REQUIRE(bsp->aggregate_vote(vote).first == vote_status::success); } }