From 07e05f00c1eb4476c3be5d692401a186c2ac87d2 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 1 Sep 2023 15:06:13 -0500 Subject: [PATCH] GH-1523 WIP: adding proposed finalizer_set to block_header_state and block_header extension. --- libraries/chain/block_header.cpp | 25 ++++++++++++++ libraries/chain/block_header_state.cpp | 1 + libraries/chain/controller.cpp | 30 ++++++++++------ .../include/eosio/chain/abi_serializer.hpp | 7 ++++ .../include/eosio/chain/block_header.hpp | 6 +++- .../eosio/chain/block_header_state.hpp | 5 ++- .../chain/include/eosio/chain/controller.hpp | 4 +-- libraries/chain/webassembly/privileged.cpp | 2 +- libraries/hotstuff/chain_pacemaker.cpp | 34 ++++++++++--------- .../eosio/hotstuff/chain_pacemaker.hpp | 4 ++- 10 files changed, 86 insertions(+), 32 deletions(-) diff --git a/libraries/chain/block_header.cpp b/libraries/chain/block_header.cpp index eef0f5bee3..9a614173af 100644 --- a/libraries/chain/block_header.cpp +++ b/libraries/chain/block_header.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -64,4 +65,28 @@ namespace eosio { namespace chain { return results; } + std::optional block_header::extract_header_extension(uint16_t extension_id)const { + using decompose_t = block_header_extension_types::decompose_t; + + for( size_t i = 0; i < header_extensions.size(); ++i ) { + const auto& e = header_extensions[i]; + auto id = e.first; + + if (id != extension_id) + continue; + + block_header_extension ext; + + auto match = decompose_t::extract( id, e.second, ext ); + EOS_ASSERT( match, invalid_block_header_extension, + "Block header extension with id type ${id} is not supported", + ("id", id) + ); + + return ext; + } + + return {}; + } + } } diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index b7cd3036ac..e809e6d393 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -65,6 +65,7 @@ namespace eosio { namespace chain { result.valid_block_signing_authority = proauth.authority; result.producer = proauth.producer_name; + result.last_proposed_finalizer_set_generation = last_proposed_finalizer_set_generation; result.blockroot_merkle = blockroot_merkle; result.blockroot_merkle.append( id ); diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 1fa7cbb1aa..888d8dc379 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -1904,6 +1905,18 @@ struct controller_impl { block_ptr->transactions = std::move( bb._pending_trx_receipts ); + if (bb._pending_block_header_state.proposed_finalizer_set) { + // proposed_finalizer_set can't be set until builtin_protocol_feature_t::instant_finality activated + finalizer_set& fin_set = *bb._pending_block_header_state.proposed_finalizer_set; + ++bb._pending_block_header_state.last_proposed_finalizer_set_generation; + fin_set.generation = bb._pending_block_header_state.last_proposed_finalizer_set_generation; + emplace_extension( + block_ptr->header_extensions, + hs_finalizer_set_extension::extension_id(), + fc::raw::pack( hs_finalizer_set_extension{ std::move(fin_set) } ) + ); + } + auto id = block_ptr->calculate_id(); // Update TaPoS table: @@ -1977,10 +1990,11 @@ struct controller_impl { pending->push(); } - void set_finalizers_impl(const finalizer_set& fin_set) { - // TODO store in chainbase - current_finalizer_set = fin_set; - ++current_finalizer_set.generation; + void set_proposed_finalizers(const finalizer_set& fin_set) { + assert(pending); // has to exist and be building_block since called from host function + auto& bb = std::get(pending->_block_stage); + + bb._pending_block_header_state.proposed_finalizer_set.emplace(fin_set); } /** @@ -3290,12 +3304,8 @@ int64_t controller::set_proposed_producers( vector producers return version; } -void controller::set_finalizers( const finalizer_set& fin_set ) { - my->set_finalizers_impl(fin_set); -} - -const finalizer_set& controller::get_finalizers() const { - return my->current_finalizer_set; +void controller::set_proposed_finalizers( const finalizer_set& fin_set ) { + my->set_proposed_finalizers(fin_set); } const producer_authority_schedule& controller::active_producers()const { diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index 3cad62bcf5..a9eb4c3b75 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -676,6 +676,13 @@ namespace impl { std::get(header_exts.lower_bound(producer_schedule_change_extension::extension_id())->second); mvo("new_producer_schedule", new_producer_schedule); } + if (header_exts.count(hs_finalizer_set_extension::extension_id())) { + // TODO: Will not compile without including finalizer_authority.hpp which includes bls12-381. + // Should we store the bls_public_key in compressed form? +// const auto& finalizer_set_extension = +// std::get(header_exts.lower_bound(hs_finalizer_set_extension::extension_id())->second); +// mvo("proposed_finalizer_set", finalizer_set_extension); + } mvo("producer_signature", block.producer_signature); add(mvo, "transactions", block.transactions, resolver, ctx); diff --git a/libraries/chain/include/eosio/chain/block_header.hpp b/libraries/chain/include/eosio/chain/block_header.hpp index f245841777..8bb7976b76 100644 --- a/libraries/chain/include/eosio/chain/block_header.hpp +++ b/libraries/chain/include/eosio/chain/block_header.hpp @@ -2,7 +2,9 @@ #include #include #include +#include +#include #include namespace eosio { namespace chain { @@ -17,7 +19,8 @@ namespace eosio { namespace chain { using block_header_extension_types = detail::block_header_extension_types< protocol_feature_activation, - producer_schedule_change_extension + producer_schedule_change_extension, + hs_finalizer_set_extension >; using block_header_extension = block_header_extension_types::block_header_extension_t; @@ -68,6 +71,7 @@ namespace eosio { namespace chain { static uint32_t num_from_id(const block_id_type& id); flat_multimap validate_and_extract_header_extensions()const; + std::optional extract_header_extension(uint16_t extension_id)const; }; diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index 5b4d64ce48..060c1ee943 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,7 @@ namespace detail { uint32_t dpos_proposed_irreversible_blocknum = 0; uint32_t dpos_irreversible_blocknum = 0; producer_authority_schedule active_schedule; + uint32_t last_proposed_finalizer_set_generation = 0; // TODO: Add to snapshot_block_header_state_v3 incremental_merkle blockroot_merkle; flat_map producer_to_last_produced; flat_map producer_to_last_implied_irb; @@ -74,6 +76,7 @@ namespace detail { struct pending_block_header_state : public detail::block_header_state_common { protocol_feature_activation_set_ptr prev_activated_protocol_features; detail::schedule_info prev_pending_schedule; + std::optional proposed_finalizer_set; // set by set_finalizer host function bool was_pending_promoted = false; block_id_type previous; account_name producer; @@ -143,7 +146,6 @@ struct block_header_state : public detail::block_header_state_common { const vector& )>& validator, bool skip_validate_signee = false )const; - bool has_pending_producers()const { return pending_schedule.schedule.producers.size(); } uint32_t calc_dpos_last_irreversible( account_name producer_of_next_block )const; producer_authority get_scheduled_producer( block_timestamp_type t )const; @@ -164,6 +166,7 @@ FC_REFLECT( eosio::chain::detail::block_header_state_common, (dpos_proposed_irreversible_blocknum) (dpos_irreversible_blocknum) (active_schedule) + (last_proposed_finalizer_set_generation) (blockroot_merkle) (producer_to_last_produced) (producer_to_last_implied_irb) diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 7f7dede8f0..5c16868f97 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -293,8 +293,8 @@ namespace eosio { namespace chain { int64_t set_proposed_producers( vector producers ); - void set_finalizers( const finalizer_set& fin_set ); - const finalizer_set& get_finalizers() const; + // called by host function set_finalizers + void set_proposed_finalizers( const finalizer_set& fin_set ); bool light_validation_allowed() const; bool skip_auth_check()const; diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index ec704da324..5aa052e4e8 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -194,7 +194,7 @@ namespace eosio { namespace chain { namespace webassembly { EOS_ASSERT( finalizers.size() == unique_finalizer_keys.size(), wasm_execution_error, "Duplicate finalizer bls key in finalizer set" ); EOS_ASSERT( finset.fthreshold > f_weight_sum / 2, wasm_execution_error, "Finalizer set threshold cannot be met by finalizer weights" ); - context.control.set_finalizers( finset ); + context.control.set_proposed_finalizers( finset ); } uint32_t interface::get_blockchain_parameters_packed( legacy_span packed_blockchain_parameters ) const { diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 1e55bda11a..3110458214 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -1,4 +1,5 @@ #include +#include #include // comment this out to remove the core profiler @@ -108,6 +109,9 @@ namespace eosio { namespace hotstuff { _accepted_block_connection = chain->accepted_block.connect( [this]( const block_state_ptr& blk ) { on_accepted_block( blk ); } ); + _irreversible_block_connection = chain->irreversible_block.connect( [this]( const block_state_ptr& blk ) { + on_irreversible_block( blk ); + } ); _head_block_state = chain->head_block_state(); } @@ -211,8 +215,17 @@ namespace eosio { namespace hotstuff { void chain_pacemaker::on_accepted_block( const block_state_ptr& blk ) { std::scoped_lock g( _chain_state_mutex ); _head_block_state = blk; - // TODO only update local cache if changed, check version or use != - _finalizer_set = _chain->get_finalizers(); // TODO get from chainbase or from block_state + } + + // called from main thread + void chain_pacemaker::on_irreversible_block( const block_state_ptr& blk ) { + if (!blk->block->header_extensions.empty()) { + std::optional ext = blk->block->extract_header_extension(hs_finalizer_set_extension::extension_id()); + if (ext) { + std::scoped_lock g( _chain_state_mutex ); + _active_finalizer_set = std::move(std::get(*ext)); + } + } } name chain_pacemaker::get_proposer() { @@ -246,21 +259,10 @@ namespace eosio { namespace hotstuff { std::vector chain_pacemaker::get_finalizers() { -#warning FIXME: Use new finalizer list in pacemaker/qc_chain. - // Every time qc_chain wants to know what the finalizers are, we get it from the controller, which - // is where it's currently stored. - // - // TODO: - // - solve threading. for this particular case, I don't think using _chain-> is a big deal really; - // set_finalizers is called once in a blue moon, and this could be solved by a simple mutex even - // if it is the main thread that is waiting for a lock. But maybe there's a better way to do this - // overall. - // - use this information in qc_chain and delete the old code below - // - list of string finalizer descriptions instead of eosio name now - // - also return the keys for each finalizer, not just name/description so qc_chain can use them - // +#warning FIXME: Use _active_finalizer_set in pacemaker/qc_chain. + // _active_finalizer_set should be used + std::unique_lock g( _chain_state_mutex ); - const auto& fin_set = _chain->get_finalizers(); // TODO use block_state_ptr hbs = _head_block_state; g.unlock(); diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index a16a583a7f..70320adc11 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -47,6 +47,7 @@ namespace eosio::hotstuff { private: void on_accepted_block( const block_state_ptr& blk ); + void on_irreversible_block( const block_state_ptr& blk ); void on_hs_proposal_msg(const hs_proposal_message& msg); //consensus msg event handler void on_hs_vote_msg(const hs_vote_message& msg); //confirmation msg event handler @@ -74,9 +75,10 @@ namespace eosio::hotstuff { mutable std::mutex _chain_state_mutex; block_state_ptr _head_block_state; - finalizer_set _finalizer_set; + finalizer_set _active_finalizer_set; boost::signals2::scoped_connection _accepted_block_connection; + boost::signals2::scoped_connection _irreversible_block_connection; qc_chain _qc_chain; std::function bcast_hs_message;