From dcb04cbcaf7b9e374ab6d24d8e604ab160f3d0d7 Mon Sep 17 00:00:00 2001 From: fcecin Date: Fri, 25 Aug 2023 15:31:10 -0300 Subject: [PATCH 01/16] set_finalizers host function (#1511) Work in progress. - Implemented host function (not tested); - Finalizer set types; - Placeholders for fc::crypto::blslib::bls_public_key operators == != and <; - Stub notify_set_finalizers signal to be connected to chain_plugin, to reach chain_pacemaker --- libraries/chain/controller.cpp | 8 + .../chain/include/eosio/chain/config.hpp | 4 + .../chain/include/eosio/chain/controller.hpp | 5 + .../include/eosio/chain/finalizer_set.hpp | 144 ++++++++++++++++++ .../eosio/chain/webassembly/interface.hpp | 9 ++ libraries/chain/webassembly/privileged.cpp | 30 ++++ .../include/fc/crypto/bls_public_key.hpp | 7 +- 7 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 libraries/chain/include/eosio/chain/finalizer_set.hpp diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 037dc6de50..b0feb1c9f3 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1990,6 +1990,10 @@ struct controller_impl { emit( self.new_hs_new_block_message, msg ); } + void set_finalizers_impl(uint64_t fthreshold, vector finalizers) { + emit( self.notify_set_finalizers, std::tie(fthreshold, finalizers) ); + } + /** * This method is called from other threads. The controller_impl should outlive those threads. * However, to avoid race conditions, it means that the behavior of this function should not change @@ -3313,6 +3317,10 @@ int64_t controller::set_proposed_producers( vector producers return version; } +void controller::set_finalizers( uint64_t fthreshold, vector finalizers ) { + my->set_finalizers_impl(fthreshold, finalizers); +} + const producer_authority_schedule& controller::active_producers()const { if( !(my->pending) ) return my->head->active_schedule; diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 6448c6ae59..c3f91d9cbe 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -130,6 +130,10 @@ const static int max_producers = 125; const static size_t maximum_tracked_dpos_confirmations = 1024; ///< static_assert(maximum_tracked_dpos_confirmations >= ((max_producers * 2 / 3) + 1) * producer_repetitions, "Settings never allow for DPOS irreversibility" ); +/** + * Maximum number of finalizers in the finalizer set + */ +const static int max_finalizers = max_producers; /** * The number of blocks produced per round is based upon all producers having a chance diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 934ed25dac..c75a3aa419 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -10,6 +10,8 @@ #include #include +#include + namespace chainbase { class database; } @@ -306,6 +308,8 @@ namespace eosio { namespace chain { int64_t set_proposed_producers( vector producers ); + void set_finalizers( uint64_t fthreshold, vector finalizers ); + bool light_validation_allowed() const; bool skip_auth_check()const; bool skip_trx_checks()const; @@ -356,6 +360,7 @@ namespace eosio { namespace chain { signal new_hs_vote_message; signal new_hs_new_view_message; signal new_hs_new_block_message; + signal&>)> notify_set_finalizers; /* signal pre_apply_block; diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp new file mode 100644 index 0000000000..5a6123617e --- /dev/null +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -0,0 +1,144 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace eosio::chain { + + struct shared_finalizer_authority { + shared_finalizer_authority() = delete; + shared_finalizer_authority( const shared_finalizer_authority& ) = default; + shared_finalizer_authority( shared_finalizer_authority&& ) = default; + shared_finalizer_authority& operator= ( shared_finalizer_authority && ) = default; + shared_finalizer_authority& operator= ( const shared_finalizer_authority & ) = default; + + shared_finalizer_authority( const name& finalizer_name, const uint64_t fweight, const fc::crypto::blslib::bls_public_key& public_key ) + :finalizer_name(finalizer_name) + ,fweight(fweight) + ,public_key(public_key) + {} + + name finalizer_name; + uint64_t fweight; + fc::crypto::blslib::bls_public_key public_key; + }; + + struct shared_finalizer_set { + shared_finalizer_set() = delete; + + explicit shared_finalizer_set( chainbase::allocator alloc ) + :finalizers(alloc){} + + shared_finalizer_set( const shared_finalizer_set& ) = default; + shared_finalizer_set( shared_finalizer_set&& ) = default; + shared_finalizer_set& operator= ( shared_finalizer_set && ) = default; + shared_finalizer_set& operator= ( const shared_finalizer_set & ) = default; + + uint32_t version = 0; ///< sequentially incrementing version number + uint64_t fthreshold = 0; // minimum finalizer fweight sum for block finalization + shared_vector finalizers; + }; + + struct finalizer_authority { + + name finalizer_name; + uint64_t fweight; // weight that this finalizer's vote has for meeting fthreshold + fc::crypto::blslib::bls_public_key public_key; + + auto to_shared(chainbase::allocator alloc) const { + return shared_finalizer_authority(finalizer_name, fweight, public_key); + } + + static auto from_shared( const shared_finalizer_authority& src ) { + finalizer_authority result; + result.finalizer_name = src.finalizer_name; + result.fweight = src.fweight; + result.public_key = src.public_key; + return result; + } + + /** + * ABI's for contracts expect variants to be serialized as a 2 entry array of + * [type-name, value]. + * + * This is incompatible with standard FC rules for + * static_variants which produce + * + * [ordinal, value] + * + * this method produces an appropriate variant for contracts where the authority field + * is correctly formatted + */ + fc::variant get_abi_variant() const; + + friend bool operator == ( const finalizer_authority& lhs, const finalizer_authority& rhs ) { + return tie( lhs.finalizer_name, lhs.fweight, lhs.public_key ) == tie( rhs.finalizer_name, rhs.fweight, rhs.public_key ); + } + friend bool operator != ( const finalizer_authority& lhs, const finalizer_authority& rhs ) { + return tie( lhs.finalizer_name, lhs.fweight, lhs.public_key ) != tie( rhs.finalizer_name, rhs.fweight, rhs.public_key ); + } + }; + + struct finalizer_set { + finalizer_set() = default; + + finalizer_set( uint32_t version, uint64_t fthreshold, std::initializer_list finalizers ) + :version(version) + ,fthreshold(fthreshold) + ,finalizers(finalizers) + {} + + auto to_shared(chainbase::allocator alloc) const { + auto result = shared_finalizer_set(alloc); + result.version = version; + result.fthreshold = fthreshold; + result.finalizers.clear(); + result.finalizers.reserve( finalizers.size() ); + for( const auto& f : finalizers ) { + result.finalizers.emplace_back(f.to_shared(alloc)); + } + return result; + } + + static auto from_shared( const shared_finalizer_set& src ) { + finalizer_set result; + result.version = src.version; + result.fthreshold = src.fthreshold; + result.finalizers.reserve( src.finalizers.size() ); + for( const auto& f : src.finalizers ) { + result.finalizers.emplace_back(finalizer_authority::from_shared(f)); + } + return result; + } + + uint32_t version = 0; ///< sequentially incrementing version number + uint64_t fthreshold; // vote fweight threshold to finalize blocks + vector finalizers; // Instant Finality voter set + + friend bool operator == ( const finalizer_set& a, const finalizer_set& b ) + { + if( a.version != b.version ) return false; + if( a.fthreshold != b.fthreshold ) return false; + if ( a.finalizers.size() != b.finalizers.size() ) return false; + for( uint32_t i = 0; i < a.finalizers.size(); ++i ) + if( ! (a.finalizers[i] == b.finalizers[i]) ) return false; + return true; + } + + friend bool operator != ( const finalizer_set& a, const finalizer_set& b ) + { + return !(a==b); + } + }; + +} /// eosio::chain + +FC_REFLECT( eosio::chain::finalizer_authority, (finalizer_name)(fweight)(public_key) ) +FC_REFLECT( eosio::chain::finalizer_set, (version)(fthreshold)(finalizers) ) +FC_REFLECT( eosio::chain::shared_finalizer_authority, (finalizer_name)(fweight)(public_key) ) +FC_REFLECT( eosio::chain::shared_finalizer_set, (version)(fthreshold)(finalizers) ) diff --git a/libraries/chain/include/eosio/chain/webassembly/interface.hpp b/libraries/chain/include/eosio/chain/webassembly/interface.hpp index 59fac5078a..28528e33f6 100644 --- a/libraries/chain/include/eosio/chain/webassembly/interface.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/interface.hpp @@ -173,6 +173,15 @@ namespace webassembly { */ int64_t set_proposed_producers_ex(uint64_t packed_producer_format, legacy_span packed_producer_schedule); + /** + * Submits a finalizer set change to Hotstuff. + * + * @ingroup privileged + * + * @param packed_finalizer_set - a serialized finalizer_set object. + */ + void set_finalizers(legacy_span packed_finalizer_set); + /** * Retrieve the blockchain config parameters. * diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index f9a8456745..c985fed132 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -150,6 +151,35 @@ namespace eosio { namespace chain { namespace webassembly { } } + void interface::set_finalizers(legacy_span packed_finalizer_set) { + EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_proposed_finalizers not allowed in a readonly transaction"); + fc::datastream ds( packed_finalizer_set.data(), packed_finalizer_set.size() ); + finalizer_set finset; + fc::raw::unpack(ds, finset); + vector & finalizers = finset.finalizers; + + EOS_ASSERT( finalizers.size() <= config::max_finalizers, wasm_execution_error, "Finalizer set exceeds the maximum finalizer count for this chain" ); + EOS_ASSERT( finalizers.size() > 0, wasm_execution_error, "Finalizer set cannot be empty" ); + + std::set unique_finalizer_keys; + std::set unique_finalizers; + uint64_t f_weight_sum = 0; + + for (const auto& f: finalizers) { + EOS_ASSERT( context.is_account(f.finalizer_name), wasm_execution_error, "Finalizer set includes a nonexisting account" ); + EOS_ASSERT( f.public_key.valid(), wasm_execution_error, "Finalizer set includes an invalid key" ); + f_weight_sum += f.fweight; + unique_finalizer_keys.insert(f.public_key); + unique_finalizers.insert(f.finalizer_name); + } + + EOS_ASSERT( finalizers.size() == unique_finalizers.size(), wasm_execution_error, "Duplicate finalizer name in finalizer set" ); + 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 treshold cannot be met by finalizer weights" ); + + context.control.set_finalizers( finset.fthreshold, std::move(finalizers) ); + } + uint32_t interface::get_blockchain_parameters_packed( legacy_span packed_blockchain_parameters ) const { auto& gpo = context.control.get_global_properties(); diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index b805252de3..79b83d51a7 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -60,9 +60,10 @@ namespace fc { namespace crypto { namespace blslib { friend std::ostream& operator<< (std::ostream& s, const bls_public_key& k); - //friend bool operator == ( const bls_public_key& p1, const bls_public_key& p2); - //friend bool operator != ( const bls_public_key& p1, const bls_public_key& p2); - //friend bool operator < ( const bls_public_key& p1, const bls_public_key& p2); +#warning FIXME/TODO: Must implement these operators. + friend bool operator == ( const bls_public_key& p1, const bls_public_key& p2) { return false; /*p1._pkey == p2._pkey;*/ } + friend bool operator != ( const bls_public_key& p1, const bls_public_key& p2) { return false; /*p1._pkey != p2._pkey;*/ } + friend bool operator < ( const bls_public_key& p1, const bls_public_key& p2) { return false; /*p1._pkey < p2._pkey;*/ } friend struct reflector; friend class bls_private_key; }; // bls_public_key From e27c8279e9785cc514b5d43d3456cca866e72036 Mon Sep 17 00:00:00 2001 From: fcecin Date: Fri, 25 Aug 2023 17:16:25 -0300 Subject: [PATCH 02/16] Fixes & get finalizer info to pacemaker - Storing set_finalizer data at controller - chain_pacemaker retrievies set_finalizer data on get_finalizers() (not using it and not thread-safe yet) - Fix legacy span - Fix remove signal stub - Fix finalizer name to string description - Fix missing finalizer_set intrinsic whitelist upon feature activation --- libraries/chain/controller.cpp | 21 ++++++++++++++---- .../chain/include/eosio/chain/controller.hpp | 3 +-- .../include/eosio/chain/finalizer_set.hpp | 22 +++++++++---------- .../eosio/chain/webassembly/interface.hpp | 2 +- libraries/chain/webassembly/privileged.cpp | 10 ++++----- libraries/hotstuff/chain_pacemaker.cpp | 19 ++++++++++++++++ .../eosio/hotstuff/chain_pacemaker.hpp | 3 ++- 7 files changed, 56 insertions(+), 24 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index b0feb1c9f3..cc855a1937 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -263,6 +263,10 @@ struct controller_impl { map< account_name, map > apply_handlers; unordered_map< builtin_protocol_feature_t, std::function, enum_hash > protocol_feature_activation_handlers; + // TODO: This probably wants to be something better; + // Storing when set_finalizers() is called; retrievable via get_finalizers() (called by chain_pacemaker) + uint64_t fthreshold; + vector finalizers; void pop_block() { auto prev = fork_db.get_block( head->header.previous ); @@ -1991,7 +1995,13 @@ struct controller_impl { } void set_finalizers_impl(uint64_t fthreshold, vector finalizers) { - emit( self.notify_set_finalizers, std::tie(fthreshold, finalizers) ); + this->fthreshold = fthreshold; + this->finalizers = finalizers; + } + + void get_finalizers_impl(uint64_t& fthreshold, vector& finalizers) { + fthreshold = this->fthreshold; + finalizers = this->finalizers; } /** @@ -3318,7 +3328,11 @@ int64_t controller::set_proposed_producers( vector producers } void controller::set_finalizers( uint64_t fthreshold, vector finalizers ) { - my->set_finalizers_impl(fthreshold, finalizers); + my->set_finalizers_impl(fthreshold, std::move(finalizers)); +} + +void controller::get_finalizers( uint64_t& fthreshold, vector& finalizers ) { + my->get_finalizers_impl(fthreshold, finalizers); } const producer_authority_schedule& controller::active_producers()const { @@ -3884,8 +3898,7 @@ void controller_impl::on_activation( template<> void controller_impl::on_activation() { db.modify( db.get(), [&]( auto& ps ) { -#warning host functions to set proposers, leaders, finalizers/validators - // FIXME/TODO: host functions to set proposers, leaders, finalizers/validators + add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "set_finalizers" ); } ); } diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index c75a3aa419..73e93689f5 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -309,6 +309,7 @@ namespace eosio { namespace chain { int64_t set_proposed_producers( vector producers ); void set_finalizers( uint64_t fthreshold, vector finalizers ); + void get_finalizers( uint64_t& fthreshold, vector& finalizers ); bool light_validation_allowed() const; bool skip_auth_check()const; @@ -360,7 +361,6 @@ namespace eosio { namespace chain { signal new_hs_vote_message; signal new_hs_new_view_message; signal new_hs_new_block_message; - signal&>)> notify_set_finalizers; /* signal pre_apply_block; @@ -400,7 +400,6 @@ namespace eosio { namespace chain { chainbase::database& mutable_db()const; std::unique_ptr my; - }; } } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index 5a6123617e..1acfa2374a 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -17,13 +17,13 @@ namespace eosio::chain { shared_finalizer_authority& operator= ( shared_finalizer_authority && ) = default; shared_finalizer_authority& operator= ( const shared_finalizer_authority & ) = default; - shared_finalizer_authority( const name& finalizer_name, const uint64_t fweight, const fc::crypto::blslib::bls_public_key& public_key ) - :finalizer_name(finalizer_name) + shared_finalizer_authority( const std::string& description, const uint64_t fweight, const fc::crypto::blslib::bls_public_key& public_key ) + :description(description) ,fweight(fweight) ,public_key(public_key) {} - name finalizer_name; + std::string description; uint64_t fweight; fc::crypto::blslib::bls_public_key public_key; }; @@ -46,17 +46,17 @@ namespace eosio::chain { struct finalizer_authority { - name finalizer_name; - uint64_t fweight; // weight that this finalizer's vote has for meeting fthreshold + std::string description; + uint64_t fweight; // weight that this finalizer's vote has for meeting fthreshold fc::crypto::blslib::bls_public_key public_key; auto to_shared(chainbase::allocator alloc) const { - return shared_finalizer_authority(finalizer_name, fweight, public_key); + return shared_finalizer_authority(description, fweight, public_key); } static auto from_shared( const shared_finalizer_authority& src ) { finalizer_authority result; - result.finalizer_name = src.finalizer_name; + result.description = src.description; result.fweight = src.fweight; result.public_key = src.public_key; return result; @@ -77,10 +77,10 @@ namespace eosio::chain { fc::variant get_abi_variant() const; friend bool operator == ( const finalizer_authority& lhs, const finalizer_authority& rhs ) { - return tie( lhs.finalizer_name, lhs.fweight, lhs.public_key ) == tie( rhs.finalizer_name, rhs.fweight, rhs.public_key ); + return tie( lhs.description, lhs.fweight, lhs.public_key ) == tie( rhs.description, rhs.fweight, rhs.public_key ); } friend bool operator != ( const finalizer_authority& lhs, const finalizer_authority& rhs ) { - return tie( lhs.finalizer_name, lhs.fweight, lhs.public_key ) != tie( rhs.finalizer_name, rhs.fweight, rhs.public_key ); + return tie( lhs.description, lhs.fweight, lhs.public_key ) != tie( rhs.description, rhs.fweight, rhs.public_key ); } }; @@ -138,7 +138,7 @@ namespace eosio::chain { } /// eosio::chain -FC_REFLECT( eosio::chain::finalizer_authority, (finalizer_name)(fweight)(public_key) ) +FC_REFLECT( eosio::chain::finalizer_authority, (description)(fweight)(public_key) ) FC_REFLECT( eosio::chain::finalizer_set, (version)(fthreshold)(finalizers) ) -FC_REFLECT( eosio::chain::shared_finalizer_authority, (finalizer_name)(fweight)(public_key) ) +FC_REFLECT( eosio::chain::shared_finalizer_authority, (description)(fweight)(public_key) ) FC_REFLECT( eosio::chain::shared_finalizer_set, (version)(fthreshold)(finalizers) ) diff --git a/libraries/chain/include/eosio/chain/webassembly/interface.hpp b/libraries/chain/include/eosio/chain/webassembly/interface.hpp index 28528e33f6..24dc555250 100644 --- a/libraries/chain/include/eosio/chain/webassembly/interface.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/interface.hpp @@ -180,7 +180,7 @@ namespace webassembly { * * @param packed_finalizer_set - a serialized finalizer_set object. */ - void set_finalizers(legacy_span packed_finalizer_set); + void set_finalizers(span packed_finalizer_set); /** * Retrieve the blockchain config parameters. diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index c985fed132..52f4b0d71d 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -151,7 +151,7 @@ namespace eosio { namespace chain { namespace webassembly { } } - void interface::set_finalizers(legacy_span packed_finalizer_set) { + void interface::set_finalizers(span packed_finalizer_set) { EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_proposed_finalizers not allowed in a readonly transaction"); fc::datastream ds( packed_finalizer_set.data(), packed_finalizer_set.size() ); finalizer_set finset; @@ -162,18 +162,18 @@ namespace eosio { namespace chain { namespace webassembly { EOS_ASSERT( finalizers.size() > 0, wasm_execution_error, "Finalizer set cannot be empty" ); std::set unique_finalizer_keys; - std::set unique_finalizers; +#warning REVIEW: Is checking for unique finalizer descriptions at all relevant? + std::set unique_finalizers; uint64_t f_weight_sum = 0; for (const auto& f: finalizers) { - EOS_ASSERT( context.is_account(f.finalizer_name), wasm_execution_error, "Finalizer set includes a nonexisting account" ); EOS_ASSERT( f.public_key.valid(), wasm_execution_error, "Finalizer set includes an invalid key" ); f_weight_sum += f.fweight; unique_finalizer_keys.insert(f.public_key); - unique_finalizers.insert(f.finalizer_name); + unique_finalizers.insert(f.description); } - EOS_ASSERT( finalizers.size() == unique_finalizers.size(), wasm_execution_error, "Duplicate finalizer name in finalizer set" ); + EOS_ASSERT( finalizers.size() == unique_finalizers.size(), wasm_execution_error, "Duplicate finalizer description in finalizer set" ); 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 treshold cannot be met by finalizer weights" ); diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index f5763150e9..d9f4d06305 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -235,6 +235,25 @@ 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 + // + uint64_t fthreshold; + vector finalizers; + _chain->get_finalizers(fthreshold, finalizers); + + // Old code: get eosio::name from the producer schedule const block_state_ptr& hbs = _chain->head_block_state(); const std::vector& pa_list = hbs->active_schedule.producers; std::vector pn_list; diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index b61015d0a6..f2451d267b 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -3,6 +3,8 @@ #include #include +#include + #include namespace eosio::chain { @@ -70,7 +72,6 @@ namespace eosio::hotstuff { uint32_t _quorum_threshold = 15; //FIXME/TODO: calculate from schedule fc::logger& _logger; - }; } // namespace eosio::hotstuff From 5aaad8913d31adcafa63600babed6b734eec10ae Mon Sep 17 00:00:00 2001 From: fcecin Date: Fri, 25 Aug 2023 19:05:09 -0300 Subject: [PATCH 03/16] Placeholder fix for bls_public_key operators - Working ==, != and < operators in bls_public_key to enable testing this branch --- libraries/libfc/include/fc/crypto/bls_public_key.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index 79b83d51a7..75033bfa16 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace fc { namespace crypto { namespace blslib { @@ -60,10 +61,9 @@ namespace fc { namespace crypto { namespace blslib { friend std::ostream& operator<< (std::ostream& s, const bls_public_key& k); -#warning FIXME/TODO: Must implement these operators. - friend bool operator == ( const bls_public_key& p1, const bls_public_key& p2) { return false; /*p1._pkey == p2._pkey;*/ } - friend bool operator != ( const bls_public_key& p1, const bls_public_key& p2) { return false; /*p1._pkey != p2._pkey;*/ } - friend bool operator < ( const bls_public_key& p1, const bls_public_key& p2) { return false; /*p1._pkey < p2._pkey;*/ } + friend bool operator == ( const bls_public_key& p1, const bls_public_key& p2) { return p1._pkey.equal(p2._pkey); } + friend bool operator != ( const bls_public_key& p1, const bls_public_key& p2) { return !p1._pkey.equal(p2._pkey); } + friend bool operator < ( const bls_public_key& p1, const bls_public_key& p2) { return bls12_381::scalar::cmp(p1._pkey.x.d, p2._pkey.x.d) < 0; } friend struct reflector; friend class bls_private_key; }; // bls_public_key From ee8eff1d980fc5494212e9841ee96a88417351db Mon Sep 17 00:00:00 2001 From: Fabiana Cecin Date: Fri, 25 Aug 2023 22:09:34 -0300 Subject: [PATCH 04/16] controller::get_finalizer returns finalizer info Co-authored-by: Gregory Popovitch --- libraries/chain/controller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index cc855a1937..7908af0122 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -3331,8 +3331,8 @@ void controller::set_finalizers( uint64_t fthreshold, vectorset_finalizers_impl(fthreshold, std::move(finalizers)); } -void controller::get_finalizers( uint64_t& fthreshold, vector& finalizers ) { - my->get_finalizers_impl(fthreshold, finalizers); +std::pair> controller::get_finalizers() const { + return my->get_finalizers_impl(); } const producer_authority_schedule& controller::active_producers()const { From 1cc704b3bff3b6a4c28aba3077ccab843a8810dc Mon Sep 17 00:00:00 2001 From: Fabiana Cecin Date: Fri, 25 Aug 2023 22:34:25 -0300 Subject: [PATCH 05/16] Remove vector copy Co-authored-by: Gregory Popovitch --- libraries/chain/controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 7908af0122..cfca0bcaab 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1996,7 +1996,7 @@ struct controller_impl { void set_finalizers_impl(uint64_t fthreshold, vector finalizers) { this->fthreshold = fthreshold; - this->finalizers = finalizers; + this->finalizers = std::move(finalizers); } void get_finalizers_impl(uint64_t& fthreshold, vector& finalizers) { From 83183dda611af70d12e28b8dee36826c31b96730 Mon Sep 17 00:00:00 2001 From: fcecin Date: Sat, 26 Aug 2023 00:05:24 -0300 Subject: [PATCH 06/16] Small fixes - Tie up get_finalizer return value changes - Better operator< for bls_public_key --- libraries/chain/controller.cpp | 5 ++--- libraries/chain/include/eosio/chain/controller.hpp | 2 +- libraries/hotstuff/chain_pacemaker.cpp | 4 +--- libraries/libfc/include/fc/crypto/bls_public_key.hpp | 3 +-- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index cfca0bcaab..d33560c770 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1999,9 +1999,8 @@ struct controller_impl { this->finalizers = std::move(finalizers); } - void get_finalizers_impl(uint64_t& fthreshold, vector& finalizers) { - fthreshold = this->fthreshold; - finalizers = this->finalizers; + std::pair> get_finalizers_impl() { + return { fthreshold, finalizers }; } /** diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 73e93689f5..8236ba354e 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -309,7 +309,7 @@ namespace eosio { namespace chain { int64_t set_proposed_producers( vector producers ); void set_finalizers( uint64_t fthreshold, vector finalizers ); - void get_finalizers( uint64_t& fthreshold, vector& finalizers ); + std::pair> get_finalizers() const; bool light_validation_allowed() const; bool skip_auth_check()const; diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index d9f4d06305..54d952622f 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -249,9 +249,7 @@ namespace eosio { namespace hotstuff { // - 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 // - uint64_t fthreshold; - vector finalizers; - _chain->get_finalizers(fthreshold, finalizers); + auto [threshold, finalizers] = _chain->get_finalizers(); // Old code: get eosio::name from the producer schedule const block_state_ptr& hbs = _chain->head_block_state(); diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index 75033bfa16..da99acf537 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -7,7 +7,6 @@ #include #include #include -#include namespace fc { namespace crypto { namespace blslib { @@ -63,7 +62,7 @@ namespace fc { namespace crypto { namespace blslib { friend std::ostream& operator<< (std::ostream& s, const bls_public_key& k); friend bool operator == ( const bls_public_key& p1, const bls_public_key& p2) { return p1._pkey.equal(p2._pkey); } friend bool operator != ( const bls_public_key& p1, const bls_public_key& p2) { return !p1._pkey.equal(p2._pkey); } - friend bool operator < ( const bls_public_key& p1, const bls_public_key& p2) { return bls12_381::scalar::cmp(p1._pkey.x.d, p2._pkey.x.d) < 0; } + friend bool operator < ( const bls_public_key& p1, const bls_public_key& p2) { return p1._pkey.affine().x.cmp(p2._pkey.affine().x) < 0; } friend struct reflector; friend class bls_private_key; }; // bls_public_key From c9fec694e07380c4d0b04941fc4744f60052864e Mon Sep 17 00:00:00 2001 From: Fabiana Cecin Date: Sat, 26 Aug 2023 08:29:58 -0300 Subject: [PATCH 07/16] Refactor finalizer_authority Co-authored-by: Gregory Popovitch --- libraries/chain/include/eosio/chain/finalizer_set.hpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index 1acfa2374a..77cf7d9063 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -55,11 +55,7 @@ namespace eosio::chain { } static auto from_shared( const shared_finalizer_authority& src ) { - finalizer_authority result; - result.description = src.description; - result.fweight = src.fweight; - result.public_key = src.public_key; - return result; + return finalizer_authority { src.description, src.fweight, src.public_key }; } /** From 3b3f55a1c8952ed9bfd37bacb324fc84b2fb6878 Mon Sep 17 00:00:00 2001 From: Fabiana Cecin Date: Sat, 26 Aug 2023 08:31:08 -0300 Subject: [PATCH 08/16] Refactor finalizer_authority Co-authored-by: Gregory Popovitch --- libraries/chain/include/eosio/chain/finalizer_set.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index 77cf7d9063..55b02965a7 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -76,7 +76,7 @@ namespace eosio::chain { return tie( lhs.description, lhs.fweight, lhs.public_key ) == tie( rhs.description, rhs.fweight, rhs.public_key ); } friend bool operator != ( const finalizer_authority& lhs, const finalizer_authority& rhs ) { - return tie( lhs.description, lhs.fweight, lhs.public_key ) != tie( rhs.description, rhs.fweight, rhs.public_key ); + return !(lhs == rhs); } }; From 02841abd2a713bbbb9ce5058912423db520984dc Mon Sep 17 00:00:00 2001 From: fcecin Date: Sat, 26 Aug 2023 12:55:56 -0300 Subject: [PATCH 09/16] Misc fixes - Fix breaking libtester w/ finalizer set fwd decl - Remove finalizer_authority::get_abi_variant - Fix init fthreshold in controller - Add const to controller get_finalizer_impl() --- libraries/chain/controller.cpp | 5 +++-- .../chain/include/eosio/chain/controller.hpp | 3 +-- .../chain/include/eosio/chain/finalizer_set.hpp | 15 +-------------- libraries/chain/webassembly/privileged.cpp | 2 +- 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index d33560c770..cf81e2c7e2 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -265,7 +266,7 @@ struct controller_impl { // TODO: This probably wants to be something better; // Storing when set_finalizers() is called; retrievable via get_finalizers() (called by chain_pacemaker) - uint64_t fthreshold; + uint64_t fthreshold = 0; vector finalizers; void pop_block() { @@ -1999,7 +2000,7 @@ struct controller_impl { this->finalizers = std::move(finalizers); } - std::pair> get_finalizers_impl() { + std::pair> get_finalizers_impl() const { return { fthreshold, finalizers }; } diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 8236ba354e..a0f5b78d5a 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -10,8 +10,6 @@ #include #include -#include - namespace chainbase { class database; } @@ -31,6 +29,7 @@ namespace eosio { namespace chain { using hs_vote_message_ptr = std::shared_ptr; using hs_new_view_message_ptr = std::shared_ptr; using hs_new_block_message_ptr = std::shared_ptr; + struct finalizer_authority; class authorization_manager; diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index 55b02965a7..5d669fd44a 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -23,6 +23,7 @@ namespace eosio::chain { ,public_key(public_key) {} +#warning FIXME: Must change std::string to shared_string. std::string description; uint64_t fweight; fc::crypto::blslib::bls_public_key public_key; @@ -58,20 +59,6 @@ namespace eosio::chain { return finalizer_authority { src.description, src.fweight, src.public_key }; } - /** - * ABI's for contracts expect variants to be serialized as a 2 entry array of - * [type-name, value]. - * - * This is incompatible with standard FC rules for - * static_variants which produce - * - * [ordinal, value] - * - * this method produces an appropriate variant for contracts where the authority field - * is correctly formatted - */ - fc::variant get_abi_variant() const; - friend bool operator == ( const finalizer_authority& lhs, const finalizer_authority& rhs ) { return tie( lhs.description, lhs.fweight, lhs.public_key ) == tie( rhs.description, rhs.fweight, rhs.public_key ); } diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index 52f4b0d71d..b2a471d425 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -175,7 +175,7 @@ namespace eosio { namespace chain { namespace webassembly { EOS_ASSERT( finalizers.size() == unique_finalizers.size(), wasm_execution_error, "Duplicate finalizer description in finalizer set" ); 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 treshold cannot be met by finalizer weights" ); + 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.fthreshold, std::move(finalizers) ); } From dba1f3a5ec8d49f2336302ff9b7f36f617873bb6 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 28 Aug 2023 13:37:25 -0500 Subject: [PATCH 10/16] GH-1541 Add thread safety to chain_pacemaker access of chain state --- libraries/chain/controller.cpp | 24 +++---- .../chain/include/eosio/chain/controller.hpp | 5 +- libraries/chain/webassembly/privileged.cpp | 3 +- libraries/hotstuff/chain_pacemaker.cpp | 67 ++++++++----------- .../include/eosio/hotstuff/base_pacemaker.hpp | 2 - .../eosio/hotstuff/chain_pacemaker.hpp | 16 +++-- libraries/hotstuff/qc_chain.cpp | 1 + plugins/chain_plugin/chain_plugin.cpp | 4 +- 8 files changed, 58 insertions(+), 64 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index cf81e2c7e2..2efbe13ab5 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -264,10 +264,8 @@ struct controller_impl { map< account_name, map > apply_handlers; unordered_map< builtin_protocol_feature_t, std::function, enum_hash > protocol_feature_activation_handlers; - // TODO: This probably wants to be something better; - // Storing when set_finalizers() is called; retrievable via get_finalizers() (called by chain_pacemaker) - uint64_t fthreshold = 0; - vector finalizers; + // TODO: This probably wants to be something better; store in chainbase and/or block_state + finalizer_set current_finalizer_set; void pop_block() { auto prev = fork_db.get_block( head->header.previous ); @@ -1995,13 +1993,9 @@ struct controller_impl { emit( self.new_hs_new_block_message, msg ); } - void set_finalizers_impl(uint64_t fthreshold, vector finalizers) { - this->fthreshold = fthreshold; - this->finalizers = std::move(finalizers); - } - - std::pair> get_finalizers_impl() const { - return { fthreshold, finalizers }; + void set_finalizers_impl(const finalizer_set fin_set) { + // TODO store in chainbase + current_finalizer_set = fin_set; } /** @@ -3327,12 +3321,12 @@ int64_t controller::set_proposed_producers( vector producers return version; } -void controller::set_finalizers( uint64_t fthreshold, vector finalizers ) { - my->set_finalizers_impl(fthreshold, std::move(finalizers)); +void controller::set_finalizers( const finalizer_set& fin_set ) { + my->set_finalizers_impl(fin_set); } -std::pair> controller::get_finalizers() const { - return my->get_finalizers_impl(); +const finalizer_set& controller::get_finalizers() const { + return my->current_finalizer_set; } 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 a0f5b78d5a..29e471951e 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -30,6 +30,7 @@ namespace eosio { namespace chain { using hs_new_view_message_ptr = std::shared_ptr; using hs_new_block_message_ptr = std::shared_ptr; struct finalizer_authority; + struct finalizer_set; class authorization_manager; @@ -307,8 +308,8 @@ namespace eosio { namespace chain { int64_t set_proposed_producers( vector producers ); - void set_finalizers( uint64_t fthreshold, vector finalizers ); - std::pair> get_finalizers() const; + void set_finalizers( const finalizer_set& fin_set ); + const finalizer_set& get_finalizers() const; 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 b2a471d425..6ff8bf9713 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -158,6 +158,7 @@ namespace eosio { namespace chain { namespace webassembly { fc::raw::unpack(ds, finset); vector & finalizers = finset.finalizers; + // TODO: check version and increment it or verify correct EOS_ASSERT( finalizers.size() <= config::max_finalizers, wasm_execution_error, "Finalizer set exceeds the maximum finalizer count for this chain" ); EOS_ASSERT( finalizers.size() > 0, wasm_execution_error, "Finalizer set cannot be empty" ); @@ -177,7 +178,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.fthreshold, std::move(finalizers) ); + context.control.set_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 54d952622f..db3e673d37 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -105,18 +105,12 @@ namespace eosio { namespace hotstuff { _qc_chain("default"_n, this, std::move(my_producers), logger), _logger(logger) { - } - - // Called internally by the chain_pacemaker to decide whether it should do something or not, based on feature activation. - // Only methods called by the outside need to call this; methods called by qc_chain only don't need to check for enable(). - bool chain_pacemaker::enabled() const { - return _chain->is_builtin_activated( builtin_protocol_feature_t::instant_finality ); + _accepted_block_connection = chain->accepted_block.connect( [this]( const block_state_ptr& blk ) { + on_accepted_block( blk ); + } ); } void chain_pacemaker::get_state(finalizer_state& fs) const { - if (! enabled()) - return; - // lock-free state version check uint64_t current_state_version = _qc_chain.get_state_version(); if (_state_cache_version != current_state_version) { @@ -141,12 +135,6 @@ namespace eosio { namespace hotstuff { fs = _state_cache; } - name chain_pacemaker::get_proposer() { - const block_state_ptr& hbs = _chain->head_block_state(); - name n = hbs->header.producer; - return n; - } - name chain_pacemaker::debug_leader_remap(name n) { /* // FIXME/REMOVE: simple device to test proposer/leader @@ -212,9 +200,22 @@ namespace eosio { namespace hotstuff { return n; } + // called from main thread + void chain_pacemaker::on_accepted_block( const block_state_ptr& blk ) { + std::scoped_lock g( _chain_state_mutex ); + _head_block_state = blk; + _finalizer_set = _chain->get_finalizers(); // TODO get from chainbase or from block_state + } + + name chain_pacemaker::get_proposer() { + std::scoped_lock g( _chain_state_mutex ); + return _head_block_state->header.producer; + } + name chain_pacemaker::get_leader() { - const block_state_ptr& hbs = _chain->head_block_state(); - name n = hbs->header.producer; + std::unique_lock g( _chain_state_mutex ); + name n = _head_block_state->header.producer; + g.unlock(); // FIXME/REMOVE: testing leader/proposer separation n = debug_leader_remap(n); @@ -223,10 +224,11 @@ namespace eosio { namespace hotstuff { } name chain_pacemaker::get_next_leader() { - const block_state_ptr& hbs = _chain->head_block_state(); - block_timestamp_type next_block_time = hbs->header.timestamp.next(); - producer_authority p_auth = hbs->get_scheduled_producer(next_block_time); + std::unique_lock g( _chain_state_mutex ); + block_timestamp_type next_block_time = _head_block_state->header.timestamp.next(); + producer_authority p_auth = _head_block_state->get_scheduled_producer(next_block_time); name n = p_auth.producer_name; + g.unlock(); // FIXME/REMOVE: testing leader/proposer separation n = debug_leader_remap(n); @@ -249,11 +251,11 @@ namespace eosio { namespace hotstuff { // - 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 // - auto [threshold, finalizers] = _chain->get_finalizers(); + std::unique_lock g( _chain_state_mutex ); + const auto& fin_set = _chain->get_finalizers(); // TODO use // Old code: get eosio::name from the producer schedule - const block_state_ptr& hbs = _chain->head_block_state(); - const std::vector& pa_list = hbs->active_schedule.producers; + const std::vector& pa_list = _head_block_state->active_schedule.producers; std::vector pn_list; pn_list.reserve(pa_list.size()); std::transform(pa_list.begin(), pa_list.end(), @@ -263,17 +265,16 @@ namespace eosio { namespace hotstuff { } block_id_type chain_pacemaker::get_current_block_id() { - return _chain->head_block_id(); + std::scoped_lock g( _chain_state_mutex ); + return _head_block_state->id; } uint32_t chain_pacemaker::get_quorum_threshold() { return _quorum_threshold; } + // called from the main application thread void chain_pacemaker::beat() { - if (! enabled()) - return; - csc prof("beat"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); @@ -302,9 +303,6 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::on_hs_proposal_msg(const hs_proposal_message& msg) { - if (! enabled()) - return; - csc prof("prop"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); @@ -313,9 +311,6 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::on_hs_vote_msg(const hs_vote_message& msg) { - if (! enabled()) - return; - csc prof("vote"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); @@ -324,9 +319,6 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::on_hs_new_block_msg(const hs_new_block_message& msg) { - if (! enabled()) - return; - csc prof("nblk"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); @@ -335,9 +327,6 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::on_hs_new_view_msg(const hs_new_view_message& msg) { - if (! enabled()) - return; - csc prof("view"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); diff --git a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp index 7b264b28dc..7fce189948 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp @@ -30,8 +30,6 @@ namespace eosio::hotstuff { virtual chain::block_id_type get_current_block_id() = 0; - //hotstuff getters. todo : implement relevant setters as host functions -#warning hotstuff getters. todo : implement relevant setters as host functions virtual chain::name get_proposer() = 0; virtual chain::name get_leader() = 0; virtual chain::name get_next_leader() = 0; diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index f2451d267b..299273b314 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -5,6 +5,8 @@ #include +#include + #include namespace eosio::chain { @@ -45,14 +47,14 @@ namespace eosio::hotstuff { void send_hs_new_view_msg(const hs_new_view_message& msg, name id); void send_hs_new_block_msg(const hs_new_block_message& msg, name id); + private: + void on_accepted_block( const block_state_ptr& blk ); + private: //FIXME/REMOVE: for testing/debugging only name debug_leader_remap(name n); - // Check if consensus upgrade feature is activated - bool enabled() const; - // This serializes all messages (high-level requests) to the qc_chain core. // For maximum safety, the qc_chain core will only process one request at a time. // These requests can come directly from the net threads, or indirectly from a @@ -66,7 +68,13 @@ namespace eosio::hotstuff { mutable finalizer_state _state_cache; mutable std::atomic _state_cache_version = 0; - chain::controller* _chain = nullptr; + chain::controller* _chain = nullptr; // TODO will not be needed once this is merged with PR#1559 + + mutable std::mutex _chain_state_mutex; + block_state_ptr _head_block_state; + finalizer_set _finalizer_set; + + boost::signals2::scoped_connection _accepted_block_connection; qc_chain _qc_chain; diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 94d43cdb2b..5bc1989664 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -674,6 +674,7 @@ namespace eosio { namespace hotstuff { } // Invoked when we could perhaps make a proposal to the network (or to ourselves, if we are the leader). + // Called from the main application thread void qc_chain::on_beat(){ // Non-proposing leaders do not care about on_beat(), because leaders react to a block proposal diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 404803ea8b..c3a383da51 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2692,7 +2692,9 @@ void chain_plugin::notify_hs_new_block_message( const hs_new_block_message& msg }; void chain_plugin::notify_hs_block_produced() { - my->_chain_pacemaker->beat(); + if (chain().is_builtin_activated( builtin_protocol_feature_t::instant_finality )) { + my->_chain_pacemaker->beat(); + } } fc::variant chain_plugin::get_log_trx_trace(const transaction_trace_ptr& trx_trace ) const { From cb8bc49c14c52a2972002d7b894124cee3fb7394 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 28 Aug 2023 14:31:44 -0500 Subject: [PATCH 11/16] GH-1541 minor cleanup --- libraries/chain/controller.cpp | 2 +- libraries/hotstuff/chain_pacemaker.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 2efbe13ab5..b396fb3d18 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1993,7 +1993,7 @@ struct controller_impl { emit( self.new_hs_new_block_message, msg ); } - void set_finalizers_impl(const finalizer_set fin_set) { + void set_finalizers_impl(const finalizer_set& fin_set) { // TODO store in chainbase current_finalizer_set = fin_set; } diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index db3e673d37..fc986080f2 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -227,8 +227,8 @@ namespace eosio { namespace hotstuff { std::unique_lock g( _chain_state_mutex ); block_timestamp_type next_block_time = _head_block_state->header.timestamp.next(); producer_authority p_auth = _head_block_state->get_scheduled_producer(next_block_time); - name n = p_auth.producer_name; g.unlock(); + name n = p_auth.producer_name; // FIXME/REMOVE: testing leader/proposer separation n = debug_leader_remap(n); From a7fc539f12e60b8cfb714f8999a1ccd400df2101 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 28 Aug 2023 14:48:27 -0500 Subject: [PATCH 12/16] GH-1541 minor cleanup --- libraries/chain/include/eosio/chain/finalizer_set.hpp | 2 +- libraries/hotstuff/chain_pacemaker.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index 5d669fd44a..a31668cf6c 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -100,7 +100,7 @@ namespace eosio::chain { } uint32_t version = 0; ///< sequentially incrementing version number - uint64_t fthreshold; // vote fweight threshold to finalize blocks + uint64_t fthreshold = 0; // vote fweight threshold to finalize blocks vector finalizers; // Instant Finality voter set friend bool operator == ( const finalizer_set& a, const finalizer_set& b ) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index fc986080f2..1f61a72ed2 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -204,6 +204,7 @@ 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 } @@ -253,9 +254,11 @@ namespace eosio { namespace hotstuff { // 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(); // Old code: get eosio::name from the producer schedule - const std::vector& pa_list = _head_block_state->active_schedule.producers; + const std::vector& pa_list = hbs->active_schedule.producers; std::vector pn_list; pn_list.reserve(pa_list.size()); std::transform(pa_list.begin(), pa_list.end(), From 7f4bcf8a1b70477493cbea174ccf2a58adeebedc Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 28 Aug 2023 15:36:49 -0500 Subject: [PATCH 13/16] GH-1541 make sure head_block_state is initialized --- libraries/hotstuff/chain_pacemaker.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 1f61a72ed2..d0d2389931 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -108,6 +108,7 @@ namespace eosio { namespace hotstuff { _accepted_block_connection = chain->accepted_block.connect( [this]( const block_state_ptr& blk ) { on_accepted_block( blk ); } ); + _head_block_state = chain->head_block_state(); } void chain_pacemaker::get_state(finalizer_state& fs) const { From 7447c157a9e4978cb5c100ef0998a51b7c001d48 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 29 Aug 2023 07:30:53 -0500 Subject: [PATCH 14/16] GH-1541 make sure head_block_state is initialized --- libraries/chain/include/eosio/chain/finalizer_set.hpp | 2 +- plugins/chain_plugin/chain_plugin.cpp | 1 - plugins/producer_plugin/producer_plugin.cpp | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index a31668cf6c..42dc355b1b 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -48,7 +48,7 @@ namespace eosio::chain { struct finalizer_authority { std::string description; - uint64_t fweight; // weight that this finalizer's vote has for meeting fthreshold + uint64_t fweight = 0; // weight that this finalizer's vote has for meeting fthreshold fc::crypto::blslib::bls_public_key public_key; auto to_shared(chainbase::allocator alloc) const { diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index c3a383da51..11fb9faa1b 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1128,7 +1128,6 @@ void chain_plugin_impl::plugin_startup() { try { EOS_ASSERT( chain_config->read_mode != db_read_mode::IRREVERSIBLE || !accept_transactions, plugin_config_exception, "read-mode = irreversible. transactions should not be enabled by enable_accept_transactions" ); - EOS_ASSERT( _chain_pacemaker, plugin_config_exception, "chain_pacemaker not initialization" ); try { auto shutdown = [](){ return app().quit(); }; auto check_shutdown = [](){ return app().is_quiting(); }; diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 4384c52c56..054068b25a 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -1326,8 +1326,6 @@ void producer_plugin_impl::plugin_initialize(const boost::program_options::varia _snapshot_scheduler.set_db_path(_snapshots_dir); _snapshot_scheduler.set_snapshots_path(_snapshots_dir); - - chain_plug->create_pacemaker(_producers); } void producer_plugin::plugin_initialize(const boost::program_options::variables_map& options) { @@ -1360,6 +1358,8 @@ void producer_plugin_impl::plugin_startup() { EOS_ASSERT(_producers.empty() || chain_plug->accept_transactions(), plugin_config_exception, "node cannot have any producer-name configured because no block production is possible with no [api|p2p]-accepted-transactions"); + chain_plug->create_pacemaker(_producers); + _accepted_block_connection.emplace(chain.accepted_block.connect([this](const auto& bsp) { on_block(bsp); })); _accepted_block_header_connection.emplace(chain.accepted_block_header.connect([this](const auto& bsp) { on_block_header(bsp); })); _irreversible_block_connection.emplace( From 683750a38f0360f2cffd46c501cc927354908a44 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 29 Aug 2023 09:47:09 -0500 Subject: [PATCH 15/16] chain_pacemaker now created in startup. --- plugins/net_plugin/net_plugin.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 07cd52f3a3..a8bb78dc00 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -4152,17 +4152,17 @@ namespace eosio { chain_plug->enable_accept_transactions(); } - chain_plug->register_pacemaker_bcast_function( - [my = shared_from_this()](const hs_message& s) { - my->bcast_hs_message(s); - } ); - } FC_LOG_AND_RETHROW() } void net_plugin_impl::plugin_startup() { fc_ilog( logger, "my node_id is ${id}", ("id", node_id )); + chain_plug->register_pacemaker_bcast_function( + [my = shared_from_this()](const hs_message& s) { + my->bcast_hs_message(s); + } ); + producer_plug = app().find_plugin(); set_producer_accounts(producer_plug->producer_accounts()); From 36a60e11defd132c89a83dd25aff47718eb6e99a Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 29 Aug 2023 20:04:21 -0500 Subject: [PATCH 16/16] Remove unneeded/unused shared versions --- .../include/eosio/chain/finalizer_set.hpp | 68 ------------------- 1 file changed, 68 deletions(-) diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index 42dc355b1b..ca5630ade1 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -10,55 +10,12 @@ namespace eosio::chain { - struct shared_finalizer_authority { - shared_finalizer_authority() = delete; - shared_finalizer_authority( const shared_finalizer_authority& ) = default; - shared_finalizer_authority( shared_finalizer_authority&& ) = default; - shared_finalizer_authority& operator= ( shared_finalizer_authority && ) = default; - shared_finalizer_authority& operator= ( const shared_finalizer_authority & ) = default; - - shared_finalizer_authority( const std::string& description, const uint64_t fweight, const fc::crypto::blslib::bls_public_key& public_key ) - :description(description) - ,fweight(fweight) - ,public_key(public_key) - {} - -#warning FIXME: Must change std::string to shared_string. - std::string description; - uint64_t fweight; - fc::crypto::blslib::bls_public_key public_key; - }; - - struct shared_finalizer_set { - shared_finalizer_set() = delete; - - explicit shared_finalizer_set( chainbase::allocator alloc ) - :finalizers(alloc){} - - shared_finalizer_set( const shared_finalizer_set& ) = default; - shared_finalizer_set( shared_finalizer_set&& ) = default; - shared_finalizer_set& operator= ( shared_finalizer_set && ) = default; - shared_finalizer_set& operator= ( const shared_finalizer_set & ) = default; - - uint32_t version = 0; ///< sequentially incrementing version number - uint64_t fthreshold = 0; // minimum finalizer fweight sum for block finalization - shared_vector finalizers; - }; - struct finalizer_authority { std::string description; uint64_t fweight = 0; // weight that this finalizer's vote has for meeting fthreshold fc::crypto::blslib::bls_public_key public_key; - auto to_shared(chainbase::allocator alloc) const { - return shared_finalizer_authority(description, fweight, public_key); - } - - static auto from_shared( const shared_finalizer_authority& src ) { - return finalizer_authority { src.description, src.fweight, src.public_key }; - } - friend bool operator == ( const finalizer_authority& lhs, const finalizer_authority& rhs ) { return tie( lhs.description, lhs.fweight, lhs.public_key ) == tie( rhs.description, rhs.fweight, rhs.public_key ); } @@ -76,29 +33,6 @@ namespace eosio::chain { ,finalizers(finalizers) {} - auto to_shared(chainbase::allocator alloc) const { - auto result = shared_finalizer_set(alloc); - result.version = version; - result.fthreshold = fthreshold; - result.finalizers.clear(); - result.finalizers.reserve( finalizers.size() ); - for( const auto& f : finalizers ) { - result.finalizers.emplace_back(f.to_shared(alloc)); - } - return result; - } - - static auto from_shared( const shared_finalizer_set& src ) { - finalizer_set result; - result.version = src.version; - result.fthreshold = src.fthreshold; - result.finalizers.reserve( src.finalizers.size() ); - for( const auto& f : src.finalizers ) { - result.finalizers.emplace_back(finalizer_authority::from_shared(f)); - } - return result; - } - uint32_t version = 0; ///< sequentially incrementing version number uint64_t fthreshold = 0; // vote fweight threshold to finalize blocks vector finalizers; // Instant Finality voter set @@ -123,5 +57,3 @@ namespace eosio::chain { FC_REFLECT( eosio::chain::finalizer_authority, (description)(fweight)(public_key) ) FC_REFLECT( eosio::chain::finalizer_set, (version)(fthreshold)(finalizers) ) -FC_REFLECT( eosio::chain::shared_finalizer_authority, (description)(fweight)(public_key) ) -FC_REFLECT( eosio::chain::shared_finalizer_set, (version)(fthreshold)(finalizers) )