diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 83c7777f61..edc929fa40 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -331,6 +331,15 @@ struct block_data_t { }, v); } + block_state_ptr fork_db_fetch_bsp_by_num(uint32_t block_num) const { + return std::visit(overloaded{ + [](const block_data_legacy_t&) -> block_state_ptr { return nullptr; }, + [&](const block_data_new_t& bd) -> block_state_ptr { + auto bsp = bd.fork_db.search_on_branch(bd.fork_db.head()->id(), block_num); + return bsp; } + }, v); + } + template R apply(F& f) { if constexpr (std::is_same_v) @@ -1053,6 +1062,7 @@ struct controller_impl { named_thread_pool thread_pool; deep_mind_handler* deep_mind_logger = nullptr; bool okay_to_print_integrity_hash_on_stop = false; + bls_key_map_t node_finalizer_keys; thread_local static platform_timer timer; // a copy for main thread and each read-only thread #if defined(EOSIO_EOS_VM_RUNTIME_ENABLED) || defined(EOSIO_EOS_VM_JIT_RUNTIME_ENABLED) @@ -3000,6 +3010,29 @@ struct controller_impl { } FC_CAPTURE_AND_RETHROW(); } /// apply_block + void create_and_send_vote_msg(const block_state_ptr& bsp) { +#warning use decide_vote() for strong after it is implementd by https://github.com/AntelopeIO/leap/issues/2070 + bool strong = true; + + // A vote is created and signed by each finalizer configured on the node that + // in active finalizer policy + for (const auto& f: bsp->active_finalizer_policy->finalizers) { + auto it = node_finalizer_keys.find( f.public_key ); + if( it != node_finalizer_keys.end() ) { + const auto& private_key = it->second; + const auto& digest = bsp->compute_finalizer_digest(); + + auto sig = private_key.sign(std::vector(digest.data(), digest.data() + digest.data_size())); + + // construct the vote message + hs_vote_message vote{ bsp->id(), strong, private_key.get_public_key(), sig }; + + // net plugin subscribed this signal. it will broadcast the vote message + // on receiving the signal + emit( self.voted_block, vote ); + } + } + } // thread safe, expected to be called from thread other than the main thread block_token create_block_state_i( const block_id_type& id, const signed_block_ptr& b, const block_header_state_legacy& prev ) { @@ -3024,6 +3057,18 @@ struct controller_impl { return block_token{bsp}; } + void integrate_received_qc_to_block(const block_id_type& id, const signed_block_ptr& b) { +#warning validate received QC before integrate it: https://github.com/AntelopeIO/leap/issues/2071 + // extract QC from block extensions + auto block_exts = b->validate_and_extract_extensions(); + if( block_exts.count(quorum_certificate_extension::extension_id()) > 0 ) { + const auto& qc_ext = std::get(block_exts. lower_bound(quorum_certificate_extension::extension_id())->second); + auto last_qc_block_bsp = block_data.fork_db_fetch_bsp_by_num( qc_ext.qc.block_height ); +#warning a mutex might be needed for updating valid_pc + last_qc_block_bsp->valid_qc = qc_ext.qc.qc; + } + } + // thread safe, expected to be called from thread other than the main thread block_token create_block_state_i( const block_id_type& id, const signed_block_ptr& b, const block_header_state& prev ) { auto trx_mroot = calculate_trx_merkle( b->transactions, true ); @@ -3044,6 +3089,12 @@ struct controller_impl { EOS_ASSERT( id == bsp->id(), block_validate_exception, "provided id ${id} does not match block id ${bid}", ("id", id)("bid", bsp->id()) ); + + create_and_send_vote_msg(bsp); + + // integrate the received QC into the claimed block + integrate_received_qc_to_block(id, b); + return block_token{bsp}; } @@ -3605,6 +3656,12 @@ struct controller_impl { wasmif.code_block_num_last_used(code_hash, vm_type, vm_version, block_num); } + void set_node_finalizer_keys(const bls_pub_priv_key_map_t& finalizer_keys) { + for (const auto& k : finalizer_keys) { + node_finalizer_keys[bls_public_key{k.first}] = bls_private_key{k.second}; + } + } + bool irreversible_mode() const { return read_mode == db_read_mode::IRREVERSIBLE; } const block_id_type& fork_db_head_block_id() const { return block_data.fork_db_head_block_id(irreversible_mode()); } uint32_t fork_db_head_block_num() const { return block_data.fork_db_head_block_num(irreversible_mode()); } @@ -4646,6 +4703,10 @@ void controller::code_block_num_last_used(const digest_type& code_hash, uint8_t return my->code_block_num_last_used(code_hash, vm_type, vm_version, block_num); } +void controller::set_node_finalizer_keys(const bls_pub_priv_key_map_t& finalizer_keys) { + my->set_node_finalizer_keys(finalizer_keys); +} + /// Protocol feature activation handlers: template<> diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index f18e3137a7..138a847f3a 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -67,7 +67,8 @@ struct block_header_state { // ------ functions ----------------------------------------------------------------- - digest_type compute_finalizer_digest() const; +#warning TDDO https://github.com/AntelopeIO/leap/issues/2080 + digest_type compute_finalizer_digest() const { return id; }; block_timestamp_type timestamp() const { return header.timestamp; } account_name producer() const { return header.producer; } const block_id_type& previous() const { return header.previous; } diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index df01872a5b..402209b563 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -375,6 +375,7 @@ namespace eosio::chain { signal accepted_block; signal irreversible_block; signal)> applied_transaction; + signal voted_block; const apply_handler* find_apply_handler( account_name contract, scope_name scope, action_name act )const; wasm_interface& get_wasm_interface(); @@ -396,6 +397,7 @@ namespace eosio::chain { void set_to_read_window(); bool is_write_window() const; void code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, uint32_t block_num); + void set_node_finalizer_keys(const bls_pub_priv_key_map_t& finalizer_keys); private: friend class apply_context; diff --git a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp index 2bd78ac800..bf8a159f73 100644 --- a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp +++ b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp @@ -16,9 +16,10 @@ namespace eosio::chain::plugin_interface { namespace channels { using rejected_block = channel_decl; using accepted_block_header = channel_decl; - using accepted_block = channel_decl; - using irreversible_block = channel_decl; + using accepted_block = channel_decl; + using irreversible_block = channel_decl; using applied_transaction = channel_decl; + using voted_block = channel_decl; } namespace methods { diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 9665397071..f0dff2408b 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -534,6 +534,7 @@ namespace eosio { void on_accepted_block_header( const signed_block_ptr& block, const block_id_type& id ); void on_accepted_block(); + void on_voted_block ( const hs_vote_message& vote ); void transaction_ack(const std::pair&); void on_irreversible_block( const block_id_type& id, uint32_t block_num ); @@ -3940,6 +3941,11 @@ namespace eosio { on_active_schedule(chain_plug->chain().active_producers()); } + // called from application thread + void net_plugin_impl::on_voted_block(const hs_vote_message& vote) { + bcast_hs_message(std::nullopt, chain::hs_message{ vote }); + } + void net_plugin_impl::bcast_hs_message( const std::optional& exclude_peer, const chain::hs_message& msg ) { fc_dlog(logger, "sending hs msg: ${msg}", ("msg", msg)); @@ -4366,6 +4372,9 @@ namespace eosio { my->on_irreversible_block( id, block->block_num() ); } ); + cc.voted_block.connect( [my = shared_from_this()]( const hs_vote_message& vote ) { + my->on_voted_block(vote); + } ); } { diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index a65bafa471..f2478176f2 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -492,7 +492,7 @@ class producer_plugin_impl : public std::enable_shared_from_this _signature_providers; - chain::bls_pub_priv_key_map_t _finalizer_keys; // public, private + chain::bls_pub_priv_key_map_t _finalizer_keys; // public, private std::set _producers; boost::asio::deadline_timer _timer; block_timing_util::producer_watermarks _producer_watermarks; @@ -1339,6 +1339,9 @@ 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.set_node_finalizer_keys(_finalizer_keys); + +#warning TODO remove create_pacemaker chain.create_pacemaker(_producers, std::move(_finalizer_keys), hotstuff_logger); _finalizer_keys.clear();