diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 4a6161269c..b50c95dfab 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -1,24 +1,29 @@ #include #include #include +#include #include #include namespace eosio::chain { producer_authority block_header_state::get_scheduled_producer(block_timestamp_type t) const { - return detail::get_scheduled_producer(proposer_policy->proposer_schedule.producers, t); + return detail::get_scheduled_producer(active_proposer_policy->proposer_schedule.producers, t); +} + +const vector& block_header_state::get_new_protocol_feature_activations()const { + return detail::get_new_protocol_feature_activations(header_exts); } #warning Add last_proposed_finalizer_policy_generation to snapshot_block_header_state_v3, see header file TODO -block_header_state_core block_header_state_core::next(const uint32_t last_qc_block_num, bool is_last_qc_strong) const { +block_header_state_core block_header_state_core::next(qc_info_t incoming) const { // no state change if last_qc_block_num is the same - if (last_qc_block_num == this->last_qc_block_num) { + if (incoming.last_qc_block_num == this->last_qc_block_num) { return {*this}; } - EOS_ASSERT(last_qc_block_num > this->last_qc_block_num, block_validate_exception, + EOS_ASSERT(incoming.last_qc_block_num > this->last_qc_block_num, block_validate_exception, "new last_qc_block_num must be greater than old last_qc_block_num"); auto old_last_qc_block_num = this->last_qc_block_num; @@ -26,7 +31,7 @@ block_header_state_core block_header_state_core::next(const uint32_t last_qc_blo block_header_state_core result{*this}; - if (is_last_qc_strong) { + if (incoming.is_last_qc_strong) { // last QC is strong. We can progress forward. // block with old final_on_strong_qc_block_num becomes irreversible @@ -47,7 +52,7 @@ block_header_state_core block_header_state_core::next(const uint32_t last_qc_blo } // new last_qc_block_num is always the input last_qc_block_num. - result.last_qc_block_num = last_qc_block_num; + result.last_qc_block_num = incoming.last_qc_block_num; return result; } @@ -61,37 +66,138 @@ block_header_state block_header_state::next(block_header_state_input& input) con result.header = block_header { .timestamp = input.timestamp, // [greg todo] do we have to do the slot++ stuff from the legacy version? .producer = input.producer, + .confirmed = hs_block_confirmed, // todo: consider 0 instead .previous = input.parent_id, .transaction_mroot = input.transaction_mroot, .action_mroot = input.action_mroot, - //.schedule_version = ?, [greg todo] - //.new_producers = ? [greg todo] + .schedule_version = header.schedule_version }; - // core - // ---- - if (input.qc_info) - result.core = core.next(input.qc_info->last_qc_block_num, input.qc_info->is_last_qc_strong); - else - result.core = core; - - // add block header extensions + // activated protocol features // --------------------------- + if (!input.new_protocol_feature_activations.empty()) { + result.activated_protocol_features = std::make_shared( + *activated_protocol_features, input.new_protocol_feature_activations); + } else { + result.activated_protocol_features = activated_protocol_features; + } + + // block_header_state_core + // ----------------------- + result.core = input.qc_info ? core.next(*input.qc_info) : core; + + // proposal_mtree and finality_mtree + // --------------------------------- + // [greg todo] ?? + + // proposer policy + // --------------- + result.active_proposer_policy = active_proposer_policy; + + if(!proposer_policies.empty()) { + auto it = proposer_policies.begin(); + if (it->first <= input.timestamp) { + result.active_proposer_policy = it->second; + result.header.schedule_version = header.schedule_version + 1; + result.active_proposer_policy->proposer_schedule.version = result.header.schedule_version; + result.proposer_policies = { ++it, proposer_policies.end() }; + } else { + result.proposer_policies = proposer_policies; + } + } + + if (input.new_proposer_policy) { + // called when assembling the block + result.proposer_policies[result.header.timestamp] = input.new_proposer_policy; + } + + // finalizer policy + // ---------------- + result.active_finalizer_policy = active_finalizer_policy; + + // [greg todo] correct support for new finalizer_policy activation using finalizer_policies map + if (input.new_finalizer_policy) ++input.new_finalizer_policy->generation; - std::optional qc_info = input.qc_info; - if (!qc_info) { - // [greg todo]: copy the one from the previous block (look in header.header_extensions) + + // add IF block header extension + // ----------------------------- + uint16_t if_ext_id = instant_finality_extension::extension_id(); + auto if_entry = header_exts.lower_bound(if_ext_id); + auto& if_ext = std::get(if_entry->second); + + instant_finality_extension new_if_ext {if_ext.qc_info, + std::move(input.new_finalizer_policy), + std::move(input.new_proposer_policy)}; + if (input.qc_info) + new_if_ext.qc_info = *input.qc_info; + + emplace_extension(result.header.header_extensions, if_ext_id, fc::raw::pack(new_if_ext)); + result.header_exts.emplace(if_ext_id, std::move(new_if_ext)); + + // add protocol_feature_activation extension + // ----------------------------------------- + if (!input.new_protocol_feature_activations.empty()) { + uint16_t ext_id = protocol_feature_activation::extension_id(); + protocol_feature_activation pfa_ext{.protocol_features = std::move(input.new_protocol_feature_activations)}; + + emplace_extension(result.header.header_extensions, ext_id, fc::raw::pack(pfa_ext)); + result.header_exts.emplace(ext_id, std::move(pfa_ext)); } - - emplace_extension(result.header.header_extensions, instant_finality_extension::extension_id(), - fc::raw::pack(instant_finality_extension{qc_info, - std::move(input.new_finalizer_policy), - std::move(input.new_proposer_policy)})); - + + // Finally update block id from header + // ----------------------------------- + result.id = result.header.calculate_id(); + return result; } +/** + * Transitions the current header state into the next header state given the supplied signed block header. + * + * Given a signed block header, generate the expected template based upon the header time, + * then validate that the provided header matches the template. + * + * If the header specifies new_producers then apply them accordingly. + */ +block_header_state block_header_state::next(const signed_block_header& h, const protocol_feature_set& pfs, + validator_t& validator) const { + auto producer = detail::get_scheduled_producer(active_proposer_policy->proposer_schedule.producers, h.timestamp).producer_name; + + EOS_ASSERT( h.previous == id, unlinkable_block_exception, "previous mismatch" ); + EOS_ASSERT( h.producer == producer, wrong_producer, "wrong producer specified" ); + + auto exts = h.validate_and_extract_header_extensions(); + + // retrieve protocol_feature_activation from incoming block header extension + // ------------------------------------------------------------------------- + vector new_protocol_feature_activations; + if( exts.count(protocol_feature_activation::extension_id() > 0) ) { + auto pfa_entry = exts.lower_bound(protocol_feature_activation::extension_id()); + auto& pfa_ext = std::get(pfa_entry->second); + new_protocol_feature_activations = std::move(pfa_ext.protocol_features); + } + + // retrieve instant_finality_extension data from block header extension + // -------------------------------------------------------------------- + EOS_ASSERT(exts.count(instant_finality_extension::extension_id() > 0), misc_exception, + "Instant Finality Extension is expected to be present in all block headers after switch to IF"); + auto if_entry = exts.lower_bound(instant_finality_extension::extension_id()); + auto& if_ext = std::get(if_entry->second); + + building_block_input bb_input{ + .parent_id = id, + .timestamp = h.timestamp, + .producer = producer, + .new_protocol_feature_activations = std::move(new_protocol_feature_activations) + }; + + block_header_state_input bhs_input{ + bb_input, h.transaction_mroot, h.action_mroot, if_ext.new_proposer_policy, if_ext.new_finalizer_policy, + if_ext.qc_info}; + + return next(bhs_input); +} } // namespace eosio::chain \ No newline at end of file diff --git a/libraries/chain/block_header_state_legacy.cpp b/libraries/chain/block_header_state_legacy.cpp index 615df6b06d..7595d2d5f2 100644 --- a/libraries/chain/block_header_state_legacy.cpp +++ b/libraries/chain/block_header_state_legacy.cpp @@ -293,7 +293,7 @@ namespace eosio::chain { if( maybe_new_producer_schedule ) { result.pending_schedule.schedule = std::move(*maybe_new_producer_schedule); - result.pending_schedule.schedule_hash = std::move(*maybe_new_producer_schedule_hash); + result.pending_schedule.schedule_hash = *maybe_new_producer_schedule_hash; result.pending_schedule.schedule_lib_num = block_number; } else { if( was_pending_promoted ) { @@ -301,7 +301,7 @@ namespace eosio::chain { } else { result.pending_schedule.schedule = std::move( prev_pending_schedule.schedule ); } - result.pending_schedule.schedule_hash = std::move( prev_pending_schedule.schedule_hash ); + result.pending_schedule.schedule_hash = prev_pending_schedule.schedule_hash ; result.pending_schedule.schedule_lib_num = prev_pending_schedule.schedule_lib_num; } @@ -369,13 +369,12 @@ namespace eosio::chain { */ block_header_state_legacy block_header_state_legacy::next( const signed_block_header& h, - vector&& _additional_signatures, + vector&& additional_signatures, const protocol_feature_set& pfs, - bool hotstuff_activated, validator_t& validator, bool skip_validate_signee )const { - return next( h.timestamp, h.confirmed ).finish_next( h, std::move(_additional_signatures), pfs, validator, skip_validate_signee ); + return next( h.timestamp, h.confirmed ).finish_next( h, std::move(additional_signatures), pfs, validator, skip_validate_signee ); } digest_type block_header_state_legacy::sig_digest()const { @@ -430,15 +429,10 @@ namespace eosio::chain { } /** - * Reference cannot outlive *this. Assumes header_exts is not mutated after instatiation. + * Reference cannot outlive *this. Assumes header_exts is not mutated after instantiation. */ const vector& block_header_state_legacy::get_new_protocol_feature_activations()const { - static const vector no_activations{}; - - if( header_exts.count(protocol_feature_activation::extension_id()) == 0 ) - return no_activations; - - return std::get(header_exts.lower_bound(protocol_feature_activation::extension_id())->second).protocol_features; + return detail::get_new_protocol_feature_activations(header_exts); } block_header_state_legacy::block_header_state_legacy( legacy::snapshot_block_header_state_v2&& snapshot ) @@ -452,10 +446,10 @@ namespace eosio::chain { producer_to_last_implied_irb = std::move(snapshot.producer_to_last_implied_irb); valid_block_signing_authority = block_signing_authority_v0{ 1, {{std::move(snapshot.block_signing_key), 1}} }; confirm_count = std::move(snapshot.confirm_count); - id = std::move(snapshot.id); + id = snapshot.id; header = std::move(snapshot.header); pending_schedule.schedule_lib_num = snapshot.pending_schedule.schedule_lib_num; - pending_schedule.schedule_hash = std::move(snapshot.pending_schedule.schedule_hash); + pending_schedule.schedule_hash = snapshot.pending_schedule.schedule_hash; pending_schedule.schedule = producer_authority_schedule( snapshot.pending_schedule.schedule ); activated_protocol_features = std::move(snapshot.activated_protocol_features); } diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index 4c43eadc12..67a40ebcc3 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -1,106 +1,34 @@ #include +#include #include namespace eosio::chain { - namespace { - constexpr auto additional_sigs_eid = additional_block_signatures_extension::extension_id(); +block_state::block_state(const block_header_state& prev, signed_block_ptr b, const protocol_feature_set& pfs, + const validator_t& validator, bool skip_validate_signee) + : block_header_state(prev.next(*b, pfs, validator)) + , block(std::move(b)) +{} + +block_state::block_state(const block_header_state& bhs, deque&& trx_metas, + deque&& trx_receipts) + : block_header_state(bhs) + , block(std::make_shared(signed_block_header{bhs.header})) // [greg todo] do we need signatures? + , pub_keys_recovered(true) // probably not needed + , cached_trxs(std::move(trx_metas)) +{} + +deque block_state::extract_trxs_metas() { + pub_keys_recovered = false; + auto result = std::move(cached_trxs); + cached_trxs.clear(); + return result; +} + +void block_state::set_trxs_metas( deque&& trxs_metas, bool keys_recovered ) { + pub_keys_recovered = keys_recovered; + cached_trxs = std::move( trxs_metas ); +} - /** - * Given a complete signed block, extract the validated additional signatures if present; - * - * @param b complete signed block - * @param pfs protocol feature set for digest access - * @param pfa activated protocol feature set to determine if extensions are allowed - * @return the list of additional signatures - * @throws if additional signatures are present before being supported by protocol feature activations - */ - vector extract_additional_signatures( const signed_block_ptr& b, - const protocol_feature_set& pfs, - const protocol_feature_activation_set_ptr& pfa ) - { - auto exts = b->validate_and_extract_extensions(); - - if ( exts.count(additional_sigs_eid) > 0 ) { - auto& additional_sigs = std::get(exts.lower_bound(additional_sigs_eid)->second); - - return std::move(additional_sigs.signatures); - } - - return {}; - } - - /** - * Given a pending block header state, wrap the promotion to a block header state such that additional signatures - * can be allowed based on activations *prior* to the promoted block and properly injected into the signed block - * that is previously constructed and mutated by the promotion - * - * This cleans up lifetime issues involved with accessing activated protocol features and moving from the - * pending block header state - * - * @param cur the pending block header state to promote - * @param b the signed block that will receive signatures during this process - * @param pfs protocol feature set for digest access - * @param extras all the remaining parameters that pass through - * @return the block header state - * @throws if the block was signed with multiple signatures before the extension is allowed - */ - - template - block_header_state inject_additional_signatures(block_header_state&& cur, - signed_block& b, - const protocol_feature_set& pfs, - Extras&& ... extras) - { - - block_header_state result; -#if 0 - result = std::move(cur).finish_next(b, pfs, std::forward(extras)...); - auto pfa = cur.prev_activated_protocol_features; - - if (!result.additional_signatures.empty()) { - bool wtmsig_enabled = detail::is_builtin_activated(pfa, pfs, builtin_protocol_feature_t::wtmsig_block_signatures); - - EOS_ASSERT(wtmsig_enabled, block_validate_exception, - "Block has multiple signatures before activation of WTMsig Block Signatures"); - - // as an optimization we don't copy this out into the legitimate extension structure as it serializes - // the same way as the vector of signatures - static_assert(fc::reflector::total_member_count == 1); - static_assert(std::is_same_v>); - - emplace_extension(b.block_extensions, additional_sigs_eid, fc::raw::pack( result.additional_signatures )); - } -#endif - return result; - } - - } -#if 0 - - block_state::block_state(const block_header_state& prev, - signed_block_ptr b, - const protocol_feature_set& pfs, - bool hotstuff_activated, - const validator_t& validator, - bool skip_validate_signee - ) - :block_header_state( prev.next( *b, extract_additional_signatures(b, pfs, prev.activated_protocol_features), pfs, hotstuff_activated, validator, skip_validate_signee ) ) - ,block( std::move(b) ) - {} - - block_state::block_state(pending_block_header_state&& cur, - signed_block_ptr&& b, - deque&& trx_metas, - const protocol_feature_set& pfs, - const validator_t& validator, - const signer_callback_type& signer - ) - :block_header_state( inject_additional_signatures( std::move(cur), *b, pfs, validator, signer ) ) - ,block( std::move(b) ) - ,_pub_keys_recovered( true ) // called by produce_block so signature recovery of trxs must have been done - ,_cached_trxs( std::move(trx_metas) ) - {} -#endif } /// eosio::chain diff --git a/libraries/chain/block_state_legacy.cpp b/libraries/chain/block_state_legacy.cpp index a3b11aadf7..100744e11c 100644 --- a/libraries/chain/block_state_legacy.cpp +++ b/libraries/chain/block_state_legacy.cpp @@ -7,30 +7,6 @@ namespace eosio { namespace chain { namespace { constexpr auto additional_sigs_eid = additional_block_signatures_extension::extension_id(); - /** - * Given a complete signed block, extract the validated additional signatures if present; - * - * @param b complete signed block - * @param pfs protocol feature set for digest access - * @param pfa activated protocol feature set to determine if extensions are allowed - * @return the list of additional signatures - * @throws if additional signatures are present before being supported by protocol feature activations - */ - vector extract_additional_signatures( const signed_block_ptr& b, - const protocol_feature_set& pfs, - const protocol_feature_activation_set_ptr& pfa ) - { - auto exts = b->validate_and_extract_extensions(); - - if ( exts.count(additional_sigs_eid) > 0 ) { - auto& additional_sigs = std::get(exts.lower_bound(additional_sigs_eid)->second); - - return std::move(additional_sigs.signatures); - } - - return {}; - } - /** * Given a pending block header state, wrap the promotion to a block header state such that additional signatures * can be allowed based on activations *prior* to the promoted block and properly injected into the signed block @@ -78,11 +54,10 @@ namespace eosio { namespace chain { block_state_legacy::block_state_legacy( const block_header_state_legacy& prev, signed_block_ptr b, const protocol_feature_set& pfs, - bool hotstuff_activated, const validator_t& validator, bool skip_validate_signee ) - :block_header_state_legacy( prev.next( *b, extract_additional_signatures(b, pfs, prev.activated_protocol_features), pfs, hotstuff_activated, validator, skip_validate_signee ) ) + :block_header_state_legacy( prev.next( *b, detail::extract_additional_signatures(b), pfs, validator, skip_validate_signee ) ) ,block( std::move(b) ) {} diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index d5b2857a14..63e1aa500c 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -101,7 +102,7 @@ class maybe_session { _session->push(); } - maybe_session& operator = ( maybe_session&& mv ) { + maybe_session& operator=( maybe_session&& mv ) noexcept { if (mv._session) { _session.emplace(std::move(*mv._session)); mv._session.reset(); @@ -116,12 +117,11 @@ class maybe_session { std::optional _session; }; -template +template struct block_data_gen_t { public: using bs = bsp::element_type; - using bhs = bhsp::element_type; - using fork_db_t = fork_database; + using fork_db_t = fork_database; bsp head; fork_db_t fork_db; @@ -165,8 +165,8 @@ struct block_data_gen_t { } }; -using block_data_legacy_t = block_data_gen_t; -using block_data_new_t = block_data_gen_t; +using block_data_legacy_t = block_data_gen_t; +using block_data_new_t = block_data_gen_t; struct block_data_t { using block_data_variant = std::variant; @@ -184,9 +184,14 @@ struct block_data_t { const producer_authority_schedule& head_active_schedule_auth() { return std::visit([](const auto& bd) -> const producer_authority_schedule& { return bd.head->active_schedule_auth(); }, v); } - - const producer_authority_schedule& head_pending_schedule_auth() { - return std::visit([](const auto& bd) -> const producer_authority_schedule& { return bd.head->pending_schedule_auth(); }, v); + + const producer_authority_schedule* head_pending_schedule_auth_legacy() { + return std::visit(overloaded{ + [](const block_data_legacy_t& bd) -> const producer_authority_schedule* { + return bd.head->pending_schedule_auth(); + }, + [](const block_data_new_t&) -> const producer_authority_schedule* { return nullptr; } + }, v); } const block_id_type& head_block_id() const { @@ -201,6 +206,29 @@ struct block_data_t { return std::visit([](const auto& bd) -> const signed_block_ptr& { return bd.head->block; }, v); } + void replace_producer_keys( const public_key_type& key ) { + ilog("Replace producer keys with ${k}", ("k", key)); + + std::visit( + overloaded{ + [&](const block_data_legacy_t& bd) { + auto version = bd.head->pending_schedule.schedule.version; + bd.head->pending_schedule = {}; + bd.head->pending_schedule.schedule.version = version; + for (auto& prod: bd.head->active_schedule.producers ) { + ilog("${n}", ("n", prod.producer_name)); + std::visit([&](auto &auth) { + auth.threshold = 1; + auth.keys = {key_weight{key, 1}}; + }, prod.authority); + } + }, + [](const block_data_new_t&) { + // TODO IF: add instant-finality implementation, will need to replace finalizers as well + } + }, v); + } + // --------------- access fork_db head ---------------------------------------------------------------------- bool fork_db_has_head() const { return std::visit([&](const auto& bd) { return !!bd.fork_db_head(); }, v); @@ -249,8 +277,8 @@ struct block_data_t { }, v); } - template - R apply(F &f) { + template + R apply(F& f) { if constexpr (std::is_same_v) std::visit([&](auto& bd) { bd.template apply(f); }, v); else @@ -260,11 +288,12 @@ struct block_data_t { template R apply_dpos(F& f) { if constexpr (std::is_same_v) - std::visit(overloaded{[&](block_data_legacy_t& bd) { bd.template apply(f); }, - [&](block_data_new_t& bd) {}}, v); + std::visit(overloaded{[&](block_data_legacy_t& bd) { bd.template apply(f); }, [&](block_data_new_t& bd) {}}, + v); else return std::visit(overloaded{[&](block_data_legacy_t& bd) -> R { return bd.template apply(f); }, - [&](block_data_new_t& bd) -> R { return {}; }}, v); + [&](block_data_new_t& bd) -> R { return {}; }}, + v); } }; @@ -300,8 +329,20 @@ struct completed_block { return std::visit([](const auto& bsp) -> const producer_authority_schedule& { return bsp->active_schedule_auth(); }, bsp); } - const producer_authority_schedule& pending_producers() const { - return std::visit([](const auto& bsp) -> const producer_authority_schedule& { return bsp->pending_schedule_auth();}, bsp); + const producer_authority_schedule* next_producers() const { + return std::visit(overloaded{ + [](const block_state_legacy_ptr& bsp) -> const producer_authority_schedule* { return bsp->pending_schedule_auth();}, + [](const block_state_ptr& bsp) -> const producer_authority_schedule* { + return bsp->proposer_policies.empty() ? nullptr : &bsp->proposer_policies.begin()->second->proposer_schedule; + } + }, bsp); + } + + const producer_authority_schedule* pending_producers_legacy() const { + return std::visit(overloaded{ + [](const block_state_legacy_ptr& bsp) -> const producer_authority_schedule* { return &bsp->pending_schedule.schedule; }, + [](const block_state_ptr&) -> const producer_authority_schedule* { return nullptr; } + }, bsp); } bool is_protocol_feature_activated(const digest_type& digest) const { @@ -406,26 +447,45 @@ struct assembled_block { v); } + const block_header& header() const { + return std::visit( + overloaded{[](const assembled_block_dpos& ab) -> const block_header& { return *ab.unsigned_block; }, + [](const assembled_block_if& ab) -> const block_header& { return ab.bhs.header; }}, + v); + } + const producer_authority_schedule& active_producers() const { return std::visit(overloaded{[](const assembled_block_dpos& ab) -> const producer_authority_schedule& { return ab.pending_block_header_state.active_schedule; }, [](const assembled_block_if& ab) -> const producer_authority_schedule& { - static producer_authority_schedule pas; return pas; // [greg todo] + return ab.bhs.active_schedule_auth(); }}, v); } - using opt_pas = const std::optional; + const producer_authority_schedule* next_producers() const { + return std::visit(overloaded{ + [](const assembled_block_dpos& ab) -> const producer_authority_schedule* { + return ab.new_producer_authority_cache.has_value() ? &ab.new_producer_authority_cache.value() : nullptr; + }, + [](const assembled_block_if& ab) -> const producer_authority_schedule* { + return ab.bhs.proposer_policies.empty() ? nullptr : &ab.bhs.proposer_policies.begin()->second->proposer_schedule; + } + }, + v); + } - opt_pas& pending_producers() const { - return std::visit( - overloaded{[](const assembled_block_dpos& ab) -> opt_pas& { return ab.new_producer_authority_cache; }, - [](const assembled_block_if& ab) -> opt_pas& { - static opt_pas empty; - return empty; // [greg todo] - }}, - v); + const producer_authority_schedule* pending_producers_legacy() const { + return std::visit(overloaded{ + [](const assembled_block_dpos& ab) -> const producer_authority_schedule* { + return ab.new_producer_authority_cache.has_value() ? &ab.new_producer_authority_cache.value() : nullptr; + }, + [](const assembled_block_if&) -> const producer_authority_schedule* { + return nullptr; + } + }, + v); } const block_signing_authority& pending_block_signing_authority() const { @@ -445,10 +505,12 @@ struct assembled_block { std::move(ab.pending_block_header_state), std::move(ab.unsigned_block), std::move(ab.trx_metas), pfs, validator, signer); - return completed_block{block_state_legacy_ptr{std::move(bsp)}}; + return completed_block{std::move(bsp)}; }, [&](assembled_block_if& ab) { - return completed_block{}; /* [greg todo] */ + auto bsp = std::make_shared(ab.bhs, std::move(ab.trx_metas), + std::move(ab.trx_receipts)); + return completed_block{std::move(bsp)}; }}, v); } @@ -532,7 +594,7 @@ struct building_block { const uint32_t block_num; // Cached: parent.block_num() + 1 // Members below (as well as non-const members of building_block_common) start from initial state and are mutated as the block is built. - std::optional new_proposer_policy; + std::shared_ptr new_proposer_policy; building_block_if(const block_header_state& parent, const building_block_input& input) : building_block_common(input.new_protocol_feature_activations) @@ -541,7 +603,7 @@ struct building_block { , timestamp(input.timestamp) , active_producer_authority{input.producer, [&]() -> block_signing_authority { - const auto& pas = parent.proposer_policy->proposer_schedule; + const auto& pas = parent.active_proposer_policy->proposer_schedule; for (const auto& pa : pas.producers) if (pa.producer_name == input.producer) return pa.authority; @@ -549,7 +611,7 @@ struct building_block { return {}; }()} , prev_activated_protocol_features(parent.activated_protocol_features) - , active_proposer_policy(parent.proposer_policy) + , active_proposer_policy(parent.active_proposer_policy) , block_num(parent.block_num() + 1) {} bool is_protocol_feature_activated(const digest_type& digest) const { @@ -558,6 +620,14 @@ struct building_block { uint32_t get_block_num() const { return block_num; } + uint32_t get_next_proposer_schedule_version() const { + if (!parent.proposer_policies.empty()) { + return (--parent.proposer_policies.end())->second->proposer_schedule.version + 1; + } + assert(active_proposer_policy); + return active_proposer_policy->proposer_schedule.version + 1; + } + }; std::variant v; @@ -568,13 +638,13 @@ struct building_block { v(building_block_dpos(prev, when, num_prev_blocks_to_confirm, new_protocol_feature_activations)) {} - bool is_dpos() const { return std::holds_alternative(v); } - // if constructor - building_block(const block_header_state& prev, const building_block_input& bbi) : - v(building_block_if(prev, bbi)) + building_block(const block_header_state& prev, const building_block_input& input) : + v(building_block_if(prev, input)) {} + bool is_dpos() const { return std::holds_alternative(v); } + template R apply_dpos(F&& f) { if constexpr (std::is_same_v) @@ -599,6 +669,19 @@ struct building_block { std::visit([&](auto& bb) { bb.new_finalizer_policy = fin_pol; }, v); } + int64_t set_proposed_producers( std::vector producers ) { + return std::visit( + overloaded{[](building_block_dpos&) -> int64_t { return -1; }, + [&](building_block_if& bb) -> int64_t { + bb.new_proposer_policy = std::make_shared(); + bb.new_proposer_policy->active_time = detail::get_next_next_round_block_time(bb.timestamp); + bb.new_proposer_policy->proposer_schedule.producers = std::move(producers); + bb.new_proposer_policy->proposer_schedule.version = bb.get_next_proposer_schedule_version(); + return bb.new_proposer_policy->proposer_schedule.version; + }}, + v); + } + deque extract_trx_metas() { return std::visit([](auto& bb) { return std::move(bb.pending_trx_metas); }, v); } @@ -681,15 +764,30 @@ struct building_block { v); } - const producer_authority_schedule& pending_producers() const { - return std::visit(overloaded{[](const building_block_dpos& bb) -> const producer_authority_schedule& { + const producer_authority_schedule* next_producers() const { + return std::visit(overloaded{[](const building_block_dpos& bb) -> const producer_authority_schedule* { if (bb.new_pending_producer_schedule) - return *bb.new_pending_producer_schedule; - return bb.pending_block_header_state.prev_pending_schedule.schedule; + return &bb.new_pending_producer_schedule.value(); + return &bb.pending_block_header_state.prev_pending_schedule.schedule; }, - [](const building_block_if& bb) -> const producer_authority_schedule& { - static producer_authority_schedule empty; - return empty; // [greg todo] + [](const building_block_if& bb) -> const producer_authority_schedule* { + if (!bb.parent.proposer_policies.empty()) + return &bb.parent.proposer_policies.begin()->second->proposer_schedule; + if (bb.new_proposer_policy) + return &bb.new_proposer_policy->proposer_schedule; + return nullptr; + }}, + v); + } + + const producer_authority_schedule* pending_producers_legacy() const { + return std::visit(overloaded{[](const building_block_dpos& bb) -> const producer_authority_schedule* { + if (bb.new_pending_producer_schedule) + return &bb.new_pending_producer_schedule.value(); + return &bb.pending_block_header_state.prev_pending_schedule.schedule; + }, + [](const building_block_if&) -> const producer_authority_schedule* { + return nullptr; }}, v); } @@ -761,7 +859,7 @@ struct building_block { }; block_header_state_input bhs_input{ - bb_input, transaction_mroot, action_mroot, bb.new_proposer_policy, bb.new_finalizer_policy, + bb_input, transaction_mroot, action_mroot, std::move(bb.new_proposer_policy), std::move(bb.new_finalizer_policy), qc_data ? qc_data->qc_info : std::optional{} }; assembled_block::assembled_block_if ab{bb.active_producer_authority, bb.parent.next(bhs_input), @@ -778,21 +876,28 @@ struct building_block { using block_stage_type = std::variant; struct pending_state { - pending_state( maybe_session&& s, - const block_header_state_legacy& prev, - block_timestamp_type when, - uint16_t num_prev_blocks_to_confirm, - const vector& new_protocol_feature_activations ) - :_db_session( std::move(s) ) - ,_block_stage( building_block( prev, when, num_prev_blocks_to_confirm, new_protocol_feature_activations ) ) - {} - maybe_session _db_session; block_stage_type _block_stage; controller::block_status _block_status = controller::block_status::ephemeral; std::optional _producer_block_id; controller::block_report _block_report{}; + pending_state(maybe_session&& s, + const block_header_state_legacy& prev, + block_timestamp_type when, + uint16_t num_prev_blocks_to_confirm, + const vector& new_protocol_feature_activations) + :_db_session(std::move(s)) + ,_block_stage(building_block(prev, when, num_prev_blocks_to_confirm, new_protocol_feature_activations)) + {} + + pending_state(maybe_session&& s, + const block_header_state& prev, + const building_block_input& input) : + _db_session(std::move(s)), + _block_stage(building_block(prev, input)) + {} + deque extract_trx_metas() { return std::visit([](auto& stage) { return stage.extract_trx_metas(); }, _block_stage); } @@ -830,18 +935,19 @@ struct pending_state { [](const auto& stage) -> const producer_authority_schedule& { return stage.active_producers(); }, _block_stage); } - -#if 0 - // [greg todo] maybe we don't need this and we can have the implementation in controller::pending_producers() - const producer_authority_schedule& pending_producers() const { + + const producer_authority_schedule* pending_producers_legacy() const { return std::visit( - overloaded{ - [](const building_block& bb) -> const producer_authority_schedule& { return bb.pending_producers(); }, - [](const assembled_block& ab) -> const producer_authority_schedule& { return ab.pending_producers(); }, - [](const completed_block& cb) -> const producer_authority_schedule& { return cb.pending_producers(); }}, + [](const auto& stage) -> const producer_authority_schedule* { return stage.pending_producers_legacy(); }, _block_stage); } -#endif + + const producer_authority_schedule* next_producers()const { + return std::visit( + [](const auto& stage) -> const producer_authority_schedule* { return stage.next_producers(); }, + _block_stage); + } + }; struct controller_impl { @@ -896,6 +1002,8 @@ struct controller_impl { map< account_name, map > apply_handlers; unordered_map< builtin_protocol_feature_t, std::function, enum_hash > protocol_feature_activation_handlers; + int64_t set_proposed_producers( vector producers ); + int64_t set_proposed_producers_legacy( vector producers ); void pop_block() { uint32_t prev_block_num = block_data.pop_block(); @@ -930,7 +1038,7 @@ struct controller_impl { cfg.state_size, false, cfg.db_map_mode ), blog( cfg.blocks_dir, cfg.blog ), block_data(block_data_t::block_data_variant{ - std::in_place_type, // [greg todo] create correct type depending on whether IF activated + std::in_place_type, // initial state is always dpos std::filesystem::path{cfg.blocks_dir / config::reversible_blocks_dir_name}}), resource_limits( db, [&s](bool is_trx_transient) { return s.get_deep_mind_logger(is_trx_transient); }), authorization( s, db ), @@ -1147,12 +1255,13 @@ struct controller_impl { std::exception_ptr except_ptr; auto replay_blog = [&](auto& fork_db, auto& head) { + using BSP = std::decay_t; if( blog_head && start_block_num <= blog_head->block_num() ) { ilog( "existing block log, attempting to replay from ${s} to ${n} blocks", ("s", start_block_num)("n", blog_head->block_num()) ); try { while( auto next = blog.read_block_by_num( head->block_num() + 1 ) ) { - replay_push_block( next, controller::block_status::irreversible ); + replay_push_block( next, controller::block_status::irreversible ); if( check_shutdown() ) break; if( next->block_num() % 500 == 0 ) { ilog( "${n} of ${head}", ("n", next->block_num())("head", blog_head->block_num()) ); @@ -1199,7 +1308,7 @@ struct controller_impl { if( check_shutdown() ) break; if( (*i)->block_num() <= head_block_num ) continue; ++rev; - replay_push_block( (*i)->block, controller::block_status::validated ); + replay_push_block( (*i)->block, controller::block_status::validated ); } ilog( "${n} reversible blocks replayed", ("n",rev) ); } @@ -1401,7 +1510,7 @@ struct controller_impl { ) { wlog( "applying branch from fork database ending with block: ${id}", ("id", pending_head->id()) ); controller::block_report br; - maybe_switch_forks( br, pending_head, controller::block_status::complete, forked_branch_callback{}, trx_meta_cache_lookup{} ); + maybe_switch_forks( br, pending_head, controller::block_status::complete, {}, trx_meta_cache_lookup{} ); } } }; @@ -1498,7 +1607,7 @@ struct controller_impl { section.add_row(chain_snapshot_header(), db); }); - // [greg todo] add snapshot support for new (IF) block_state section +#warning todo: add snapshot support for new (IF) block_state section auto write_block_state_section = [&](auto& fork_db, auto& head) { snapshot->write_section("eosio::chain::block_state", [&]( auto §ion ) { section.template add_row(*head, db); @@ -1552,7 +1661,7 @@ struct controller_impl { header.validate(); }); - // [greg todo] add snapshot support for new (IF) block_state section +#warning todo: add snapshot support for new (IF) block_state section auto read_block_state_section = [&](auto& fork_db, auto& head) { /// load and upgrade the block header state block_header_state_legacy head_header_state; using v2 = legacy::snapshot_block_header_state_v2; @@ -2344,26 +2453,26 @@ struct controller_impl { dm_logger->on_start_block(head_block_num() + 1); } - auto guard_pending = fc::make_scoped_exit([this, head_block_num=head_block_num()](){ + auto guard_pending = fc::make_scoped_exit([this, head_block_num=head_block_num()]() { protocol_features.popped_blocks_to( head_block_num ); pending.reset(); }); - //building_block_input bbi{ head->id(), when, head->get_scheduled_producer(when), std::move(new_protocol_feature_activations) }; - // [greg todo] build IF `building_block` below if not in dpos mode. - // we'll need a different `building_block` constructor for IF mode - auto update_pending = [&](auto& fork_db, auto& head) { - if (!self.skip_db_sessions(s)) { - EOS_ASSERT( db.revision() == head_block_num(), database_exception, "db revision is not on par with head block", + auto update_pending = [&](fork_db_t& fork_db, bsp& head) { + EOS_ASSERT( self.skip_db_sessions(s) || + db.revision() == head_block_num(), database_exception, "db revision is not on par with head block", ("db.revision()", db.revision())("controller_head_block", head_block_num())("fork_db_head_block", fork_db_head_block_num()) ); - - pending.emplace( maybe_session(db), *head, when, confirm_block_count, new_protocol_feature_activations ); - } else { - pending.emplace( maybe_session(), *head, when, confirm_block_count, new_protocol_feature_activations ); + maybe_session session = self.skip_db_sessions(s) ? maybe_session() : maybe_session(db); + if constexpr (std::is_same_v) + pending.emplace(std::move(session), *head, when, confirm_block_count, new_protocol_feature_activations); + else { + building_block_input bbi{ head->id(), when, head->get_scheduled_producer(when).producer_name, + new_protocol_feature_activations }; + pending.emplace(std::move(session), *head, bbi); } }; - block_data.apply_dpos(update_pending); + block_data.apply(update_pending); pending->_block_status = s; pending->_producer_block_id = producer_block_id; @@ -2372,8 +2481,7 @@ struct controller_impl { // block status is either ephemeral or incomplete. Modify state of speculative block only if we are building a // speculative incomplete block (otherwise we need clean state for head mode, ephemeral block) - if ( pending->_block_status != controller::block_status::ephemeral ) - { + if ( pending->_block_status != controller::block_status::ephemeral ) { const auto& pso = db.get(); auto num_preactivated_protocol_features = pso.preactivated_protocol_features.size(); @@ -2440,6 +2548,7 @@ struct controller_impl { const auto& gpo = self.get_global_properties(); if (!hs_active) { +#warning todo: how do we update the producer_schedule after the switch to IF? bb.apply_dpos([&](building_block::building_block_dpos& bb_dpos) { pending_block_header_state_legacy& pbhs = bb_dpos.pending_block_header_state; @@ -2512,40 +2621,44 @@ struct controller_impl { EOS_ASSERT( std::holds_alternative(pending->_block_stage), block_validate_exception, "already called finalize_block"); try { - // [greg todo] move the merkle computation inside assemble_block. - auto& bb = std::get(pending->_block_stage); - - // Update resource limits: - resource_limits.process_account_limit_updates(); - const auto& chain_config = self.get_global_properties().configuration; - uint64_t CPU_TARGET = EOS_PERCENT(chain_config.max_block_cpu_usage, chain_config.target_block_cpu_usage_pct); - resource_limits.set_block_parameters( - { CPU_TARGET, chain_config.max_block_cpu_usage, config::block_cpu_usage_average_window_ms / config::block_interval_ms, config::maximum_elastic_resource_multiplier, {99, 100}, {1000, 999}}, - {EOS_PERCENT(chain_config.max_block_net_usage, chain_config.target_block_net_usage_pct), chain_config.max_block_net_usage, config::block_size_average_window_ms / config::block_interval_ms, config::maximum_elastic_resource_multiplier, {99, 100}, {1000, 999}} - ); - resource_limits.process_block_usage(bb.block_num()); - - auto assembled_block = - bb.assemble_block(thread_pool.get_executor(), protocol_features.get_protocol_feature_set(), block_data); - - // Update TaPoS table: - create_block_summary( assembled_block.id() ); + auto& bb = std::get(pending->_block_stage); - pending->_block_stage = std::move(assembled_block); + // Update resource limits: + resource_limits.process_account_limit_updates(); + const auto& chain_config = self.get_global_properties().configuration; + resource_limits.set_block_parameters( + { EOS_PERCENT(chain_config.max_block_cpu_usage, chain_config.target_block_cpu_usage_pct), + chain_config.max_block_cpu_usage, + config::block_cpu_usage_average_window_ms / config::block_interval_ms, + config::maximum_elastic_resource_multiplier, {99, 100}, {1000, 999}}, + { EOS_PERCENT(chain_config.max_block_net_usage, chain_config.target_block_net_usage_pct), + chain_config.max_block_net_usage, + config::block_size_average_window_ms / config::block_interval_ms, + config::maximum_elastic_resource_multiplier, {99, 100}, {1000, 999}} + ); + resource_limits.process_block_usage(bb.block_num()); + + auto assembled_block = + bb.assemble_block(thread_pool.get_executor(), protocol_features.get_protocol_feature_set(), block_data); + + // Update TaPoS table: + create_block_summary( assembled_block.id() ); + + pending->_block_stage = std::move(assembled_block); - /* - ilog( "finalized block ${n} (${id}) at ${t} by ${p} (${signing_key}); schedule_version: ${v} lib: ${lib} #dtrxs: ${ndtrxs} ${np}", - ("n",pbhs.block_num()) - ("id",id) - ("t",pbhs.timestamp) - ("p",pbhs.producer) - ("signing_key", pbhs.block_signing_key) - ("v",pbhs.active_schedule_version) - ("lib",pbhs.dpos_irreversible_blocknum) - ("ndtrxs",db.get_index().size()) - ("np",block_ptr->new_producers) - ); - */ + /* + ilog( "finalized block ${n} (${id}) at ${t} by ${p} (${signing_key}); schedule_version: ${v} lib: ${lib} #dtrxs: ${ndtrxs} ${np}", + ("n",pbhs.block_num()) + ("id",id) + ("t",pbhs.timestamp) + ("p",pbhs.producer) + ("signing_key", pbhs.block_signing_key) + ("v",pbhs.active_schedule_version) + ("lib",pbhs.dpos_irreversible_blocknum) + ("ndtrxs",db.get_index().size()) + ("np",block_ptr->new_producers) + ); + */ } FC_CAPTURE_AND_RETHROW() @@ -2580,8 +2693,8 @@ struct controller_impl { emit( self.accepted_block, std::tie(bsp->block, bsp->id()) ); - if constexpr (std::is_same_v>) {\ - // [greg todo] support deep_mind_logger even when in IF mode + if constexpr (std::is_same_v>) { +#warning todo: support deep_mind_logger even when in IF mode // at block level, no transaction specific logging is possible if (auto* dm_logger = get_deep_mind_logger(false)) { dm_logger->on_accepted_block(bsp); @@ -2676,9 +2789,9 @@ struct controller_impl { void report_block_header_diff( const block_header& b, const block_header& ab ) { #define EOS_REPORT(DESC,A,B) \ - if( A != B ) { \ - elog("${desc}: ${bv} != ${abv}", ("desc", DESC)("bv", A)("abv", B)); \ - } + if( A != B ) { \ + elog("${desc}: ${bv} != ${abv}", ("desc", DESC)("bv", A)("abv", B)); \ + } EOS_REPORT( "timestamp", b.timestamp, ab.timestamp ) EOS_REPORT( "producer", b.producer, ab.producer ) @@ -2695,11 +2808,9 @@ struct controller_impl { template void apply_block( controller::block_report& br, const BSP& bsp, controller::block_status s, - const trx_meta_cache_lookup& trx_lookup ) - { try { + const trx_meta_cache_lookup& trx_lookup ) { try { - // [greg todo] remove `if`, `lambda` and `apply_dpos`, and make code work for both versions of BSP - if constexpr (std::is_same_v) { + try { auto do_the_work = [&](auto& fork_db, auto& head) { auto start = fc::time_point::now(); const signed_block_ptr& b = bsp->block; @@ -2735,7 +2846,8 @@ struct controller_impl { } else { packed_transaction_ptr ptrx( b, &pt ); // alias signed_block_ptr auto fut = transaction_metadata::start_recover_keys( - std::move( ptrx ), thread_pool.get_executor(), chain_id, fc::microseconds::maximum(), transaction_metadata::trx_type::input ); + std::move( ptrx ), thread_pool.get_executor(), chain_id, fc::microseconds::maximum(), + transaction_metadata::trx_type::input ); trx_metas.emplace_back( transaction_metadata_ptr{}, std::move( fut ) ); } } @@ -2749,37 +2861,39 @@ struct controller_impl { for( const auto& receipt : b->transactions ) { auto num_pending_receipts = trx_receipts.size(); if( std::holds_alternative(receipt.trx) ) { - const auto& trx_meta = ( use_bsp_cached ? bsp->trxs_metas().at( packed_idx ) - : ( !!std::get<0>( trx_metas.at( packed_idx ) ) ? - std::get<0>( trx_metas.at( packed_idx ) ) - : std::get<1>( trx_metas.at( packed_idx ) ).get() ) ); - trace = push_transaction( trx_meta, fc::time_point::maximum(), fc::microseconds::maximum(), receipt.cpu_usage_us, true, 0 ); + const auto& trx_meta = (use_bsp_cached ? bsp->trxs_metas().at(packed_idx) + : (!!std::get<0>(trx_metas.at(packed_idx)) + ? std::get<0>(trx_metas.at(packed_idx)) + : std::get<1>(trx_metas.at(packed_idx)).get())); + trace = push_transaction(trx_meta, fc::time_point::maximum(), fc::microseconds::maximum(), + receipt.cpu_usage_us, true, 0); ++packed_idx; } else if( std::holds_alternative(receipt.trx) ) { - trace = push_scheduled_transaction( std::get(receipt.trx), fc::time_point::maximum(), fc::microseconds::maximum(), receipt.cpu_usage_us, true ); + trace = push_scheduled_transaction(std::get(receipt.trx), fc::time_point::maximum(), + fc::microseconds::maximum(), receipt.cpu_usage_us, true); } else { EOS_ASSERT( false, block_validate_exception, "encountered unexpected receipt type" ); } - bool transaction_failed = trace && trace->except; - bool transaction_can_fail = receipt.status == transaction_receipt_header::hard_fail && std::holds_alternative(receipt.trx); + bool transaction_failed = trace && trace->except; + bool transaction_can_fail = receipt.status == transaction_receipt_header::hard_fail && + std::holds_alternative(receipt.trx); + if( transaction_failed && !transaction_can_fail) { edump((*trace)); throw *trace->except; } - EOS_ASSERT( trx_receipts.size() > 0, - block_validate_exception, "expected a receipt, block_num ${bn}, block_id ${id}, receipt ${e}", - ("bn", b->block_num())("id", producer_block_id)("e", receipt) - ); - EOS_ASSERT( trx_receipts.size() == num_pending_receipts + 1, - block_validate_exception, "expected receipt was not added, block_num ${bn}, block_id ${id}, receipt ${e}", - ("bn", b->block_num())("id", producer_block_id)("e", receipt) - ); + EOS_ASSERT(trx_receipts.size() > 0, block_validate_exception, + "expected a receipt, block_num ${bn}, block_id ${id}, receipt ${e}", + ("bn", b->block_num())("id", producer_block_id)("e", receipt)); + EOS_ASSERT(trx_receipts.size() == num_pending_receipts + 1, block_validate_exception, + "expected receipt was not added, block_num ${bn}, block_id ${id}, receipt ${e}", + ("bn", b->block_num())("id", producer_block_id)("e", receipt)); const transaction_receipt_header& r = trx_receipts.back(); - EOS_ASSERT( r == static_cast(receipt), - block_validate_exception, "receipt does not match, ${lhs} != ${rhs}", - ("lhs", r)("rhs", static_cast(receipt)) ); + EOS_ASSERT(r == static_cast(receipt), block_validate_exception, + "receipt does not match, ${lhs} != ${rhs}", + ("lhs", r)("rhs", static_cast(receipt))); } finalize_block(); @@ -2789,12 +2903,11 @@ struct controller_impl { if( producer_block_id != ab.id() ) { elog( "Validation block id does not match producer block id" ); - // [greg todo] also call `report_block_header_diff in IF mode once we have a signed_block - ab.apply_dpos([&](assembled_block::assembled_block_dpos& ab) { report_block_header_diff( *b, *ab.unsigned_block ); }); + report_block_header_diff(*b, ab.header()); // this implicitly asserts that all header fields (less the signature) are identical - EOS_ASSERT( producer_block_id == ab.id(), block_validate_exception, "Block ID does not match", - ("producer_block_id", producer_block_id)("validator_block_id", ab.id()) ); + EOS_ASSERT(producer_block_id == ab.id(), block_validate_exception, "Block ID does not match", + ("producer_block_id", producer_block_id)("validator_block_id", ab.id())); } if( !use_bsp_cached ) { @@ -2807,23 +2920,23 @@ struct controller_impl { commit_block(s); br.total_time = fc::time_point::now() - start; }; - block_data.apply_dpos(do_the_work); + block_data.apply(do_the_work); + return; + } catch ( const std::bad_alloc& ) { + throw; + } catch ( const boost::interprocess::bad_alloc& ) { + throw; + } catch ( const fc::exception& e ) { + edump((e.to_detail_string())); + abort_block(); + throw; + } catch ( const std::exception& e ) { + edump((e.what())); + abort_block(); + throw; } - return; - } catch ( const std::bad_alloc& ) { - throw; - } catch ( const boost::interprocess::bad_alloc& ) { - throw; - } catch ( const fc::exception& e ) { - edump((e.to_detail_string())); - abort_block(); - throw; - } catch ( const std::exception& e ) { - edump((e.what())); - abort_block(); - throw; - } - } FC_CAPTURE_AND_RETHROW() } /// apply_block + } FC_CAPTURE_AND_RETHROW(); + } /// apply_block // thread safe, expected to be called from thread other than the main thread @@ -2843,7 +2956,6 @@ struct controller_impl { prev, b, protocol_features.get_protocol_feature_set(), - b->confirmed == hs_block_confirmed, // is hotstuff enabled for block [this]( block_timestamp_type timestamp, const flat_set& cur_features, const vector& new_features ) @@ -2895,9 +3007,10 @@ struct controller_impl { return block_data.apply_dpos(f); } + template void push_block( controller::block_report& br, - const block_state_legacy_ptr& bsp, - const forked_branch_callback& forked_branch_cb, + const BSP& bsp, + const forked_branch_callback_t& forked_branch_cb, const trx_meta_cache_lookup& trx_lookup ) { controller::block_status s = controller::block_status::complete; @@ -2917,7 +3030,8 @@ struct controller_impl { } auto do_push = [&](auto& fork_db, auto& head) { - fork_db.add( bsp ); + if constexpr (std::is_same_v>) + fork_db.add( bsp ); if (self.is_trusted_producer(b->producer)) { trusted_producer_light_validation = true; @@ -2926,18 +3040,19 @@ struct controller_impl { emit( self.accepted_block_header, std::tie(bsp->block, bsp->id()) ); if( read_mode != db_read_mode::IRREVERSIBLE ) { - maybe_switch_forks( br, fork_db.pending_head(), s, forked_branch_cb, trx_lookup ); + if constexpr (std::is_same_v>) + maybe_switch_forks( br, fork_db.pending_head(), s, forked_branch_cb, trx_lookup ); } else { log_irreversible(); } }; - block_data.apply_dpos(do_push); // [greg todo] make it work with apply() - `push_block` taking block_state_legacy_ptr - // and forked_branch_callback + block_data.apply(do_push); } FC_LOG_AND_RETHROW( ) } + template void replay_push_block( const signed_block_ptr& b, controller::block_status s ) { self.validate_db_available_size(); @@ -2955,53 +3070,49 @@ struct controller_impl { } const bool skip_validate_signee = !conf.force_all_checks; + validator_t validator = [this](block_timestamp_type timestamp, const flat_set& cur_features, + const vector& new_features) { + check_protocol_features(timestamp, cur_features, new_features); + }; auto do_push = [&](auto& fork_db, auto& head) { - auto bsp = std::make_shared( - *head, - b, - protocol_features.get_protocol_feature_set(), - b->confirmed == hs_block_confirmed, // is hotstuff enabled for block - [this]( block_timestamp_type timestamp, - const flat_set& cur_features, - const vector& new_features ) - { check_protocol_features( timestamp, cur_features, new_features ); }, - skip_validate_signee - ); + if constexpr (std::is_same_v>) { + auto bsp = std::make_shared( + *head, b, protocol_features.get_protocol_feature_set(), validator, skip_validate_signee); - if( s != controller::block_status::irreversible ) { - fork_db.add( bsp, true ); - } + if (s != controller::block_status::irreversible) { + fork_db.add(bsp, true); + } - emit( self.accepted_block_header, std::tie(bsp->block, bsp->id()) ); + emit(self.accepted_block_header, std::tie(bsp->block, bsp->id())); - controller::block_report br; - if( s == controller::block_status::irreversible ) { - apply_block( br, bsp, s, trx_meta_cache_lookup{} ); + controller::block_report br; + if (s == controller::block_status::irreversible) { + apply_block(br, bsp, s, trx_meta_cache_lookup{}); - // On replay, log_irreversible is not called and so no irreversible_block signal is emitted. - // So emit it explicitly here. - emit( self.irreversible_block, std::tie(bsp->block, bsp->id()) ); + // On replay, log_irreversible is not called and so no irreversible_block signal is emitted. + // So emit it explicitly here. + emit(self.irreversible_block, std::tie(bsp->block, bsp->id())); - if (!self.skip_db_sessions(s)) { - db.commit(bsp->block_num()); + if (!self.skip_db_sessions(s)) { + db.commit(bsp->block_num()); + } + } else { + EOS_ASSERT(read_mode != db_read_mode::IRREVERSIBLE, block_validate_exception, + "invariant failure: cannot replay reversible blocks while in irreversible mode"); + maybe_switch_forks(br, bsp, s, {}, trx_meta_cache_lookup{}); } - - } else { - EOS_ASSERT( read_mode != db_read_mode::IRREVERSIBLE, block_validate_exception, - "invariant failure: cannot replay reversible blocks while in irreversible mode" ); - maybe_switch_forks( br, bsp, s, forked_branch_callback{}, trx_meta_cache_lookup{} ); } }; - - block_data.apply_dpos(do_push); // [greg todo] make it work with apply() - need block_state constructor + + block_data.apply(do_push); } FC_LOG_AND_RETHROW( ) } template void maybe_switch_forks( controller::block_report& br, const BSP& new_head, controller::block_status s, - const forked_branch_callback& forked_branch_cb, const trx_meta_cache_lookup& trx_lookup ) + const forked_branch_callback_t& forked_branch_cb, const trx_meta_cache_lookup& trx_lookup ) { auto do_maybe_switch_forks = [&](auto& fork_db, auto& head) { bool head_changed = true; @@ -3030,7 +3141,9 @@ struct controller_impl { EOS_ASSERT( self.head_block_id() == branches.second.back()->header.previous, fork_database_exception, "loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail - if( forked_branch_cb ) forked_branch_cb( branches.second ); + if( forked_branch_cb ) + if constexpr (std::is_same_v>) + forked_branch_cb(branches.second); } for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr ) { @@ -3094,7 +3207,7 @@ struct controller_impl { log_irreversible(); }; - block_data.apply_dpos(do_maybe_switch_forks); // [greg todo] + block_data.apply(do_maybe_switch_forks); } /// push_block @@ -3680,6 +3793,15 @@ block_state_legacy_ptr controller::create_block_state( const block_id_type& id, void controller::push_block( controller::block_report& br, const block_state_legacy_ptr& bsp, + const forked_branch_callback_legacy& forked_branch_cb, + const trx_meta_cache_lookup& trx_lookup ) +{ + validate_db_available_size(); + my->push_block( br, bsp, forked_branch_cb, trx_lookup ); +} + +void controller::push_block( controller::block_report& br, + const block_state_ptr& bsp, const forked_branch_callback& forked_branch_cb, const trx_meta_cache_lookup& trx_lookup ) { @@ -3687,6 +3809,7 @@ void controller::push_block( controller::block_report& br, my->push_block( br, bsp, forked_branch_cb, trx_lookup ); } + transaction_trace_ptr controller::push_transaction( const transaction_metadata_ptr& trx, fc::time_point block_deadline, fc::microseconds max_transaction_time, uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time, @@ -3932,10 +4055,28 @@ void controller::write_snapshot( const snapshot_writer_ptr& snapshot ) { } int64_t controller::set_proposed_producers( vector producers ) { - const auto& gpo = get_global_properties(); + assert(my->pending); + if (my->pending->is_dpos()) { + return my->set_proposed_producers_legacy(std::move(producers)); + } else { + return my->set_proposed_producers(std::move(producers)); + } +} + +int64_t controller_impl::set_proposed_producers( vector producers ) { + // TODO: zero out gpo.proposed_schedule_block_num and gpo.proposed_schedule on instant finality enabled + if (producers.empty()) + return -1; + + auto& bb = std::get(pending->_block_stage); + return bb.set_proposed_producers(std::move(producers)); +} + +int64_t controller_impl::set_proposed_producers_legacy( vector producers ) { + const auto& gpo = self.get_global_properties(); auto cur_block_num = head_block_num() + 1; - if( producers.size() == 0 && is_builtin_activated( builtin_protocol_feature_t::disallow_empty_producer_schedule ) ) { + if( producers.size() == 0 && self.is_builtin_activated( builtin_protocol_feature_t::disallow_empty_producer_schedule ) ) { return -1; } @@ -3953,17 +4094,18 @@ int64_t controller::set_proposed_producers( vector producers decltype(sch.producers.cend()) end; decltype(end) begin; - const auto& pending_sch = pending_producers(); + const auto* pending_sch = self.pending_producers_legacy(); + assert(pending_sch); // can't be null during dpos - if( pending_sch.producers.size() == 0 ) { - const auto& active_sch = active_producers(); + if( pending_sch->producers.size() == 0 ) { + const auto& active_sch = self.active_producers(); begin = active_sch.producers.begin(); end = active_sch.producers.end(); sch.version = active_sch.version + 1; } else { - begin = pending_sch.producers.begin(); - end = pending_sch.producers.end(); - sch.version = pending_sch.version + 1; + begin = pending_sch->producers.begin(); + end = pending_sch->producers.end(); + sch.version = pending_sch->version + 1; } if( std::equal( producers.begin(), producers.end(), begin, end ) ) @@ -3975,7 +4117,7 @@ int64_t controller::set_proposed_producers( vector producers ilog( "proposed producer schedule with version ${v}", ("v", version) ); - my->db.modify( gpo, [&]( auto& gp ) { + db.modify( gpo, [&]( auto& gp ) { gp.proposed_schedule_block_num = cur_block_num; gp.proposed_schedule = sch; }); @@ -4015,6 +4157,7 @@ const producer_authority_schedule& controller::active_producers()const { if( !(my->pending) ) return my->block_data.head_active_schedule_auth(); +#warning todo: support active/pending_producers correctly when in IF mode (see assembled_block and completed_block stages) return my->pending->active_producers(); } @@ -4022,25 +4165,14 @@ const producer_authority_schedule& controller::head_active_producers()const { return my->block_data.head_active_schedule_auth(); } -const producer_authority_schedule& controller::pending_producers()const { - if( !(my->pending) ) - return my->block_data.head_pending_schedule_auth(); // [greg todo] implement pending_producers correctly for IF mode - - if( std::holds_alternative(my->pending->_block_stage) ) - return std::get(my->pending->_block_stage).pending_producers(); - - if( std::holds_alternative(my->pending->_block_stage) ) { - const auto& pp = std::get(my->pending->_block_stage).pending_producers(); - if( pp ) { - return *pp; - } - } +const producer_authority_schedule* controller::pending_producers_legacy()const { + if( !(my->pending) ) + return my->block_data.head_pending_schedule_auth_legacy(); - const auto& bb = std::get(my->pending->_block_stage); - return bb.pending_producers(); + return my->pending->pending_producers_legacy(); } -std::optional controller::proposed_producers()const { +std::optional controller::proposed_producers_legacy()const { const auto& gpo = get_global_properties(); if( !gpo.proposed_schedule_block_num ) return std::optional(); @@ -4048,6 +4180,10 @@ std::optional controller::proposed_producers()const return producer_authority_schedule::from_shared(gpo.proposed_schedule); } +const producer_authority_schedule* controller::next_producers()const { + return my->pending->next_producers(); +} + bool controller::light_validation_allowed() const { if (!my->pending || my->in_trx_requiring_checks) { return false; @@ -4391,26 +4527,14 @@ std::optional controller::extract_chain_id_from_db( const path& s void controller::replace_producer_keys( const public_key_type& key ) { ilog("Replace producer keys with ${k}", ("k", key)); + // can be done even after instant-finality, will be no-op then mutable_db().modify( db().get(), [&]( auto& gp ) { gp.proposed_schedule_block_num = {}; gp.proposed_schedule.version = 0; gp.proposed_schedule.producers.clear(); }); - - auto replace_keys = [&key](auto& fork_db, auto& head) { - auto version = head->pending_schedule.schedule.version; - head->pending_schedule = {}; - head->pending_schedule.schedule.version = version; - for (auto& prod: head->active_schedule.producers ) { - ilog("${n}", ("n", prod.producer_name)); - std::visit([&](auto &auth) { - auth.threshold = 1; - auth.keys = {key_weight{key, 1}}; - }, prod.authority); - } - }; - my->block_data.apply_dpos(replace_keys); // [greg todo]: make it work with `apply` instead of `apply_dpos` + my->block_data.replace_producer_keys(key); } void controller::replace_account_keys( name account, name permission, const public_key_type& key ) { diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 7c1c62a2d8..6431c7d5f1 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -15,13 +15,13 @@ namespace eosio::chain { using boost::multi_index_container; using namespace boost::multi_index; - template - const uint32_t fork_database::magic_number = 0x30510FDB; + template + const uint32_t fork_database::magic_number = 0x30510FDB; - template - const uint32_t fork_database::min_supported_version = 2; - template - const uint32_t fork_database::max_supported_version = 2; + template + const uint32_t fork_database::min_supported_version = 2; + template + const uint32_t fork_database::max_supported_version = 2; /** * History: @@ -42,12 +42,13 @@ namespace eosio::chain { return std::pair(lhs.irreversible_blocknum(), lhs.block_num()) > std::pair(rhs.irreversible_blocknum(), rhs.block_num()); } - template // either [block_state_legacy_ptr, block_state_ptr], same with block_header_state_ptr + template // either [block_state_legacy_ptr, block_state_ptr], same with block_header_state_ptr struct fork_database_impl { using bs = bsp::element_type; + using bhsp = bs::bhsp_t; using bhs = bhsp::element_type; - using fork_database_t = fork_database; + using fork_database_t = fork_database; using branch_type = fork_database_t::branch_type; using branch_type_pair = fork_database_t::branch_type_pair; @@ -89,20 +90,20 @@ namespace eosio::chain { }; - template - fork_database::fork_database( const std::filesystem::path& data_dir ) - :my( new fork_database_impl( data_dir ) ) + template + fork_database::fork_database( const std::filesystem::path& data_dir ) + :my( new fork_database_impl( data_dir ) ) {} - template - void fork_database::open( validator_t& validator ) { + template + void fork_database::open( validator_t& validator ) { std::lock_guard g( my->mtx ); my->open_impl( validator ); } - template - void fork_database_impl::open_impl( validator_t& validator ) { + template + void fork_database_impl::open_impl( validator_t& validator ) { if (!std::filesystem::is_directory(datadir)) std::filesystem::create_directories(datadir); @@ -177,14 +178,14 @@ namespace eosio::chain { } } - template - void fork_database::close() { + template + void fork_database::close() { std::lock_guard g( my->mtx ); my->close_impl(); } - template - void fork_database_impl::close_impl() { + template + void fork_database_impl::close_impl() { auto fork_db_dat = datadir / config::forkdb_filename; if( !root ) { @@ -251,19 +252,19 @@ namespace eosio::chain { index.clear(); } - template - fork_database::~fork_database() { + template + fork_database::~fork_database() { my->close_impl(); } - template - void fork_database::reset( const bhs& root_bhs ) { + template + void fork_database::reset( const bhs& root_bhs ) { std::lock_guard g( my->mtx ); my->reset_impl(root_bhs); } - template - void fork_database_impl::reset_impl( const bhs& root_bhs ) { + template + void fork_database_impl::reset_impl( const bhs& root_bhs ) { index.clear(); root = std::make_shared(); static_cast(*root) = root_bhs; @@ -271,14 +272,14 @@ namespace eosio::chain { head = root; } - template - void fork_database::rollback_head_to_root() { + template + void fork_database::rollback_head_to_root() { std::lock_guard g( my->mtx ); my->rollback_head_to_root_impl(); } - template - void fork_database_impl::rollback_head_to_root_impl() { + template + void fork_database_impl::rollback_head_to_root_impl() { auto& by_id_idx = index.template get(); auto itr = by_id_idx.begin(); while (itr != by_id_idx.end()) { @@ -290,14 +291,14 @@ namespace eosio::chain { head = root; } - template - void fork_database::advance_root( const block_id_type& id ) { + template + void fork_database::advance_root( const block_id_type& id ) { std::lock_guard g( my->mtx ); my->advance_root_impl( id ); } - template - void fork_database_impl::advance_root_impl( const block_id_type& id ) { + template + void fork_database_impl::advance_root_impl( const block_id_type& id ) { EOS_ASSERT( root, fork_database_exception, "root not yet set" ); auto new_root = get_block_impl( id ); @@ -330,14 +331,14 @@ namespace eosio::chain { root = new_root; } - template - bhsp fork_database::get_block_header( const block_id_type& id ) const { + template + fork_database::bhsp fork_database::get_block_header( const block_id_type& id ) const { std::shared_lock g( my->mtx ); return my->get_block_header_impl( id ); } - template - bhsp fork_database_impl::get_block_header_impl( const block_id_type& id ) const { + template + fork_database_impl::bhsp fork_database_impl::get_block_header_impl( const block_id_type& id ) const { if( root->id() == id ) { return root; } @@ -349,8 +350,8 @@ namespace eosio::chain { return bhsp(); } - template - void fork_database_impl::add_impl(const bsp& n, bool ignore_duplicate, bool validate, validator_t& validator) { + template + void fork_database_impl::add_impl(const bsp& n, bool ignore_duplicate, bool validate, validator_t& validator) { EOS_ASSERT( root, fork_database_exception, "root not yet set" ); EOS_ASSERT( n, fork_database_exception, "attempt to add null block state" ); @@ -382,8 +383,8 @@ namespace eosio::chain { } } - template - void fork_database::add( const bsp& n, bool ignore_duplicate ) { + template + void fork_database::add( const bsp& n, bool ignore_duplicate ) { std::lock_guard g( my->mtx ); my->add_impl( n, ignore_duplicate, false, []( block_timestamp_type timestamp, @@ -393,20 +394,20 @@ namespace eosio::chain { ); } - template - bsp fork_database::root() const { + template + bsp fork_database::root() const { std::shared_lock g( my->mtx ); return my->root; } - template - bsp fork_database::head() const { + template + bsp fork_database::head() const { std::shared_lock g( my->mtx ); return my->head; } - template - bsp fork_database::pending_head() const { + template + bsp fork_database::pending_head() const { std::shared_lock g( my->mtx ); const auto& indx = my->index.template get(); @@ -419,17 +420,17 @@ namespace eosio::chain { return my->head; } - template - fork_database::branch_type - fork_database::fetch_branch(const block_id_type& h, + template + fork_database::branch_type + fork_database::fetch_branch(const block_id_type& h, uint32_t trim_after_block_num) const { std::shared_lock g(my->mtx); return my->fetch_branch_impl(h, trim_after_block_num); } - template - fork_database::branch_type - fork_database_impl::fetch_branch_impl(const block_id_type& h, uint32_t trim_after_block_num) const { + template + fork_database::branch_type + fork_database_impl::fetch_branch_impl(const block_id_type& h, uint32_t trim_after_block_num) const { branch_type result; for (auto s = get_block_impl(h); s; s = get_block_impl(s->previous())) { if (s->block_num() <= trim_after_block_num) @@ -439,14 +440,14 @@ namespace eosio::chain { return result; } - template - bsp fork_database::search_on_branch( const block_id_type& h, uint32_t block_num ) const { + template + bsp fork_database::search_on_branch( const block_id_type& h, uint32_t block_num ) const { std::shared_lock g( my->mtx ); return my->search_on_branch_impl( h, block_num ); } - template - bsp fork_database_impl::search_on_branch_impl( const block_id_type& h, uint32_t block_num ) const { + template + bsp fork_database_impl::search_on_branch_impl( const block_id_type& h, uint32_t block_num ) const { for( auto s = get_block_impl(h); s; s = get_block_impl( s->previous() ) ) { if( s->block_num() == block_num ) return s; @@ -459,16 +460,16 @@ namespace eosio::chain { * Given two head blocks, return two branches of the fork graph that * end with a common ancestor (same prior block) */ - template - fork_database::branch_type_pair - fork_database::fetch_branch_from(const block_id_type& first, const block_id_type& second) const { + template + fork_database::branch_type_pair + fork_database::fetch_branch_from(const block_id_type& first, const block_id_type& second) const { std::shared_lock g(my->mtx); return my->fetch_branch_from_impl(first, second); } - template - fork_database::branch_type_pair - fork_database_impl::fetch_branch_from_impl(const block_id_type& first, const block_id_type& second) const { + template + fork_database::branch_type_pair + fork_database_impl::fetch_branch_from_impl(const block_id_type& first, const block_id_type& second) const { pair result; auto first_branch = (first == root->id()) ? root : get_block_impl(first); auto second_branch = (second == root->id()) ? root : get_block_impl(second); @@ -527,14 +528,14 @@ namespace eosio::chain { } /// fetch_branch_from_impl /// remove all of the invalid forks built off of this id including this id - template - void fork_database::remove( const block_id_type& id ) { + template + void fork_database::remove( const block_id_type& id ) { std::lock_guard g( my->mtx ); return my->remove_impl( id ); } - template - void fork_database_impl::remove_impl( const block_id_type& id ) { + template + void fork_database_impl::remove_impl( const block_id_type& id ) { deque remove_queue{id}; const auto& previdx = index.template get(); const auto& head_id = head->id(); @@ -555,14 +556,14 @@ namespace eosio::chain { } } - template - void fork_database::mark_valid( const bsp& h ) { + template + void fork_database::mark_valid( const bsp& h ) { std::lock_guard g( my->mtx ); my->mark_valid_impl( h ); } - template - void fork_database_impl::mark_valid_impl( const bsp& h ) { + template + void fork_database_impl::mark_valid_impl( const bsp& h ) { if( h->is_valid() ) return; auto& by_id_idx = index.template get(); @@ -582,14 +583,14 @@ namespace eosio::chain { } } - template - bsp fork_database::get_block(const block_id_type& id) const { + template + bsp fork_database::get_block(const block_id_type& id) const { std::shared_lock g( my->mtx ); return my->get_block_impl(id); } - template - bsp fork_database_impl::get_block_impl(const block_id_type& id) const { + template + bsp fork_database_impl::get_block_impl(const block_id_type& id) const { auto itr = index.find( id ); if( itr != index.end() ) return *itr; @@ -597,10 +598,10 @@ namespace eosio::chain { } // do class instantiations - template class fork_database; - template class fork_database; + template class fork_database; + template class fork_database; - template struct fork_database_impl; - template struct fork_database_impl; + template struct fork_database_impl; + template struct fork_database_impl; } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/block_header.hpp b/libraries/chain/include/eosio/chain/block_header.hpp index 1670ec6131..6f9d9e0393 100644 --- a/libraries/chain/include/eosio/chain/block_header.hpp +++ b/libraries/chain/include/eosio/chain/block_header.hpp @@ -7,7 +7,7 @@ #include #include -namespace eosio { namespace chain { +namespace eosio::chain { namespace detail { template @@ -26,6 +26,8 @@ namespace eosio { namespace chain { using block_header_extension = block_header_extension_types::block_header_extension_t; using header_extension_multimap = flat_multimap; + using validator_t = const std::function&, const vector&)>; + // totem for block_header.confirmed that indicates hotstuff consensus is active constexpr uint16_t hs_block_confirmed = std::numeric_limits::max(); @@ -84,7 +86,7 @@ namespace eosio { namespace chain { signature_type producer_signature; }; -} } /// namespace eosio::chain +} /// namespace eosio::chain FC_REFLECT(eosio::chain::block_header, (timestamp)(producer)(confirmed)(previous) diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index da9e525041..2780d1b709 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -29,7 +29,7 @@ struct qc_data_t { struct block_header_state_input : public building_block_input { digest_type transaction_mroot; // Comes from std::get(building_block::trx_mroot_or_receipt_digests) digest_type action_mroot; // Compute root from building_block::action_receipt_digests - std::optional new_proposer_policy; // Comes from building_block::new_proposer_policy + std::shared_ptr new_proposer_policy; // Comes from building_block::new_proposer_policy std::optional new_finalizer_policy; // Comes from building_block::new_finalizer_policy std::optional qc_info; // Comes from traversing branch from parent and calling get_best_qc() // assert(qc->block_num <= num_from_id(previous)); @@ -41,7 +41,7 @@ struct block_header_state_core { std::optional last_qc_block_num; // uint32_t finalizer_policy_generation; // - block_header_state_core next(uint32_t last_qc_block_num, bool is_last_qc_strong) const; + block_header_state_core next(qc_info_t incoming) const; }; struct block_header_state { @@ -54,33 +54,39 @@ struct block_header_state { incremental_merkle_tree proposal_mtree; incremental_merkle_tree finality_mtree; - finalizer_policy_ptr finalizer_policy; // finalizer set + threshold + generation, supports `digest()` - proposer_policy_ptr proposer_policy; // producer authority schedule, supports `digest()` + finalizer_policy_ptr active_finalizer_policy; // finalizer set + threshold + generation, supports `digest()` + proposer_policy_ptr active_proposer_policy; // producer authority schedule, supports `digest()` - flat_map proposer_policies; + // block time when proposer_policy will become active + flat_map proposer_policies; flat_map finalizer_policies; + + // ------ data members caching information available elsewhere ---------------------- + header_extension_multimap header_exts; // redundant with the data stored in header + + // ------ functions ----------------------------------------------------------------- digest_type compute_finalizer_digest() const; block_timestamp_type timestamp() const { return header.timestamp; } account_name producer() const { return header.producer; } const block_id_type& previous() const { return header.previous; } uint32_t block_num() const { return block_header::num_from_id(previous()) + 1; } - const producer_authority_schedule& active_schedule_auth() const { return proposer_policy->proposer_schedule; } - const producer_authority_schedule& pending_schedule_auth() const { return proposer_policies.rbegin()->second->proposer_schedule; } // [greg todo] - + const producer_authority_schedule& active_schedule_auth() const { return active_proposer_policy->proposer_schedule; } + block_header_state next(block_header_state_input& data) const; - + + block_header_state next(const signed_block_header& h, const protocol_feature_set& pfs, validator_t& validator) const; + // block descending from this need the provided qc in the block extension bool is_needed(const quorum_certificate& qc) const { return !core.last_qc_block_num || qc.block_height > *core.last_qc_block_num; } flat_set get_activated_protocol_features() const { return activated_protocol_features->protocol_features; } - detail::schedule_info prev_pending_schedule() const; + const vector& get_new_protocol_feature_activations() const; producer_authority get_scheduled_producer(block_timestamp_type t) const; uint32_t active_schedule_version() const; - std::optional& new_pending_producer_schedule() { static std::optional x; return x; } // [greg todo] signed_block_header make_block_header(const checksum256_type& transaction_mroot, const checksum256_type& action_mroot, const std::optional& new_producers, diff --git a/libraries/chain/include/eosio/chain/block_header_state_legacy.hpp b/libraries/chain/include/eosio/chain/block_header_state_legacy.hpp index d653bca2e5..6f7a3153d9 100644 --- a/libraries/chain/include/eosio/chain/block_header_state_legacy.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state_legacy.hpp @@ -75,8 +75,6 @@ namespace detail { } -using validator_t = const std::function&, const vector&)>; - struct pending_block_header_state_legacy : public detail::block_header_state_legacy_common { protocol_feature_activation_set_ptr prev_activated_protocol_features; detail::schedule_info prev_pending_schedule; @@ -167,7 +165,6 @@ struct block_header_state_legacy : public detail::block_header_state_legacy_comm block_header_state_legacy next( const signed_block_header& h, vector&& additional_signatures, const protocol_feature_set& pfs, - bool hotstuff_activated, validator_t& validator, bool skip_validate_signee = false )const; diff --git a/libraries/chain/include/eosio/chain/block_header_state_utils.hpp b/libraries/chain/include/eosio/chain/block_header_state_utils.hpp index 91237d4709..72c700bca9 100644 --- a/libraries/chain/include/eosio/chain/block_header_state_utils.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state_utils.hpp @@ -1,7 +1,9 @@ #pragma once #include "eosio/chain/protocol_feature_manager.hpp" +#include #include + namespace eosio::chain::detail { inline bool is_builtin_activated(const protocol_feature_activation_set_ptr& pfa, @@ -12,10 +14,10 @@ namespace eosio::chain::detail { return digest && protocol_features.find(*digest) != protocol_features.end(); } - inline uint32_t get_next_next_round_block_num(block_timestamp_type t, uint32_t block_num) { + inline block_timestamp_type get_next_next_round_block_time( block_timestamp_type t) { auto index = t.slot % config::producer_repetitions; // current index in current round - // (increment to the end of this round ) + next round - return block_num + (config::producer_repetitions - index) + config::producer_repetitions; + // (increment to the end of this round ) + next round + return block_timestamp_type{t.slot + (config::producer_repetitions - index) + config::producer_repetitions}; } inline producer_authority get_scheduled_producer(const vector& producers, block_timestamp_type t) { @@ -24,4 +26,35 @@ namespace eosio::chain::detail { return producers[index]; } + constexpr auto additional_sigs_eid = additional_block_signatures_extension::extension_id(); + + /** + * Given a complete signed block, extract the validated additional signatures if present; + * + * @param b complete signed block + * @return the list of additional signatures + */ + inline vector extract_additional_signatures(const signed_block_ptr& b) { + auto exts = b->validate_and_extract_extensions(); + + if (exts.count(additional_sigs_eid) > 0) { + auto& additional_sigs = std::get(exts.lower_bound(additional_sigs_eid)->second); + return std::move(additional_sigs.signatures); + } + + return {}; + } + + /** + * Reference cannot outlive header_exts. Assumes header_exts is not mutated after instantiation. + */ + inline const vector& get_new_protocol_feature_activations(const header_extension_multimap& header_exts) { + static const vector no_activations{}; + + if( header_exts.count(protocol_feature_activation::extension_id()) == 0 ) + return no_activations; + + return std::get(header_exts.lower_bound(protocol_feature_activation::extension_id())->second).protocol_features; + } + } /// namespace eosio::chain diff --git a/libraries/chain/include/eosio/chain/block_state.hpp b/libraries/chain/include/eosio/chain/block_state.hpp index 6c98e1f2f1..3e853db596 100644 --- a/libraries/chain/include/eosio/chain/block_state.hpp +++ b/libraries/chain/include/eosio/chain/block_state.hpp @@ -7,32 +7,47 @@ namespace eosio::chain { - struct block_state : public block_header_state { // block_header_state provides parent link - // ------ data members ------------------------------------------------------------- - signed_block_ptr block; - bool validated; // We have executed the block's trxs and verified that action merkle root (block id) matches. - digest_type finalizer_digest; - pending_quorum_certificate pending_qc; // where we accumulate votes we receive - std::optional valid_qc; // qc received from the network +struct block_state : public block_header_state { // block_header_state provides parent link + // ------ data members ------------------------------------------------------------- + signed_block_ptr block; + bool validated; // We have executed the block's trxs and verified that action merkle root (block id) matches. + digest_type strong_digest; // finalizer_digest (strong, cached so we can quickly validate votes) + digest_type weak_digest; // finalizer_digest (weak, cached so we can quickly validate votes) + pending_quorum_certificate pending_qc; // where we accumulate votes we receive + std::optional valid_qc; // best qc received from the network inside block extension - // ------ data members caching information available elsewhere ---------------------- - block_id_type cached_id; // cache of block_header_state::header.calculate_id() (indexed on this field) - header_extension_multimap header_exts; // redundant with the data stored in header - - // ------ functions ----------------------------------------------------------------- - const block_id_type& id() const { return cached_id; } - const block_id_type& previous() const { return block_header_state::previous(); } - uint32_t block_num() const { return block_header_state::block_num(); } - block_timestamp_type timestamp() const { return block_header_state::timestamp(); } - const extensions_type& header_extensions() const { return block_header_state::header.header_extensions; } - bool is_valid() const { return validated; } - void set_valid(bool b) { validated = b; } - uint32_t irreversible_blocknum() const { return 0; } // [greg todo] equivalent of dpos_irreversible_blocknum + // ------ data members caching information available elsewhere ---------------------- + bool pub_keys_recovered = false; + deque cached_trxs; + + // ------ functions ----------------------------------------------------------------- + const block_id_type& id() const { return block_header_state::id; } + const block_id_type& previous() const { return block_header_state::previous(); } + uint32_t block_num() const { return block_header_state::block_num(); } + block_timestamp_type timestamp() const { return block_header_state::timestamp(); } + const extensions_type& header_extensions() const { return block_header_state::header.header_extensions; } + bool is_valid() const { return validated; } + void set_valid(bool b) { validated = b; } + uint32_t irreversible_blocknum() const { return 0; } // [greg todo] equivalent of dpos_irreversible_blocknum - protocol_feature_activation_set_ptr get_activated_protocol_features() const { return block_header_state::activated_protocol_features; } - deque extract_trxs_metas() { return {}; }; // [greg todo] see impl in block_state_legacy.hpp - }; + protocol_feature_activation_set_ptr get_activated_protocol_features() const { return block_header_state::activated_protocol_features; } + bool is_pub_keys_recovered() const { return pub_keys_recovered; } + deque extract_trxs_metas(); + void set_trxs_metas(deque&& trxs_metas, bool keys_recovered); + const deque& trxs_metas() const { return cached_trxs; } + + using bhs_t = block_header_state; + using bhsp_t = block_header_state_ptr; + + block_state() = default; + + block_state(const block_header_state& prev, signed_block_ptr b, const protocol_feature_set& pfs, + const validator_t& validator, bool skip_validate_signee); + + block_state(const block_header_state& bhs, deque&& trx_metas, + deque&& trx_receipts); +}; using block_state_ptr = std::shared_ptr; diff --git a/libraries/chain/include/eosio/chain/block_state_legacy.hpp b/libraries/chain/include/eosio/chain/block_state_legacy.hpp index b8c1876f21..fc267d813c 100644 --- a/libraries/chain/include/eosio/chain/block_state_legacy.hpp +++ b/libraries/chain/include/eosio/chain/block_state_legacy.hpp @@ -5,13 +5,15 @@ #include #include -namespace eosio { namespace chain { +namespace eosio::chain { struct block_state_legacy : public block_header_state_legacy { + using bhs_t = block_header_state_legacy; + using bhsp_t = block_header_state_legacy_ptr; + block_state_legacy( const block_header_state_legacy& prev, signed_block_ptr b, const protocol_feature_set& pfs, - bool hotstuff_activated, const validator_t& validator, bool skip_validate_signee ); @@ -42,7 +44,7 @@ namespace eosio { namespace chain { protocol_feature_activation_set_ptr get_activated_protocol_features() const { return activated_protocol_features; } const producer_authority_schedule& active_schedule_auth() const { return block_header_state_legacy_common::active_schedule; } - const producer_authority_schedule& pending_schedule_auth() const { return block_header_state_legacy::pending_schedule.schedule; } + const producer_authority_schedule* pending_schedule_auth() const { return &block_header_state_legacy::pending_schedule.schedule; } const deque& trxs_metas() const { return _cached_trxs; } @@ -74,6 +76,6 @@ namespace eosio { namespace chain { using block_state_legacy_ptr = std::shared_ptr; -} } /// namespace eosio::chain +} /// namespace eosio::chain FC_REFLECT_DERIVED( eosio::chain::block_state_legacy, (eosio::chain::block_header_state_legacy), (block)(validated) ) diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index b563e4a5ca..2941b55280 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -51,10 +51,18 @@ namespace eosio::chain { using resource_limits::resource_limits_manager; using apply_handler = std::function; - using fork_database_legacy = fork_database; - using branch_type = typename fork_database_legacy::branch_type; - - using forked_branch_callback = std::function; + template + using branch_type_t = fork_database::branch_type; + + using branch_type_legacy = branch_type_t; + using branch_type = branch_type_t; + + template + using forked_branch_callback_t = std::function&)>; + + using forked_branch_callback_legacy = forked_branch_callback_t; + using forked_branch_callback = forked_branch_callback_t; + // lookup transaction_metadata via supplied function to avoid re-creation using trx_meta_cache_lookup = std::function; @@ -192,6 +200,11 @@ namespace eosio::chain { */ void push_block( block_report& br, const block_state_legacy_ptr& bsp, + const forked_branch_callback_legacy& cb, + const trx_meta_cache_lookup& trx_lookup ); + + void push_block( block_report& br, + const block_state_ptr& bsp, const forked_branch_callback& cb, const trx_meta_cache_lookup& trx_lookup ); @@ -250,8 +263,13 @@ namespace eosio::chain { const producer_authority_schedule& active_producers()const; const producer_authority_schedule& head_active_producers()const; - const producer_authority_schedule& pending_producers()const; - std::optional proposed_producers()const; + // pending for pre-instant-finality, next proposed that will take affect, null if none are pending/proposed + const producer_authority_schedule* next_producers()const; + // post-instant-finality this always returns empty std::optional + std::optional proposed_producers_legacy()const; + // pre-instant-finality this always returns a valid producer_authority_schedule + // post-instant-finality this always returns nullptr + const producer_authority_schedule* pending_producers_legacy()const; // Called by qc_chain to indicate the current irreversible block num // After hotstuff is activated, this should be called on startup by qc_chain diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index b2967d9f67..cdd1d13fab 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -7,7 +7,7 @@ namespace eosio::chain { using boost::signals2::signal; - template + template struct fork_database_impl; /** @@ -21,11 +21,13 @@ namespace eosio::chain { * * An internal mutex is used to provide thread-safety. */ - template // either [block_state_legacy_ptr, block_state_ptr], same with block_header_state_ptr + template // either block_state_legacy_ptr or block_state_ptr class fork_database { public: using bs = bsp::element_type; + using bhsp = bs::bhsp_t; using bhs = bhsp::element_type; + using bsp_t = bsp; using branch_type = deque; using branch_type_pair = pair; @@ -97,9 +99,9 @@ namespace eosio::chain { static const uint32_t max_supported_version; private: - unique_ptr> my; + unique_ptr> my; }; - using fork_database_legacy = fork_database; + using fork_database_legacy = fork_database; } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/hotstuff/instant_finality_extension.hpp b/libraries/chain/include/eosio/chain/hotstuff/instant_finality_extension.hpp index a663e16f9d..a535414285 100644 --- a/libraries/chain/include/eosio/chain/hotstuff/instant_finality_extension.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff/instant_finality_extension.hpp @@ -17,7 +17,7 @@ struct instant_finality_extension : fc::reflect_init { instant_finality_extension() = default; instant_finality_extension(std::optional qc_info, std::optional new_finalizer_policy, - std::optional new_proposer_policy) : + std::shared_ptr new_proposer_policy) : qc_info(qc_info), new_finalizer_policy(std::move(new_finalizer_policy)), new_proposer_policy(std::move(new_proposer_policy)) @@ -25,9 +25,9 @@ struct instant_finality_extension : fc::reflect_init { void reflector_init(); - std::optional qc_info; - std::optional new_finalizer_policy; - std::optional new_proposer_policy; + std::optional qc_info; + std::optional new_finalizer_policy; + std::shared_ptr new_proposer_policy; }; } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/unapplied_transaction_queue.hpp b/libraries/chain/include/eosio/chain/unapplied_transaction_queue.hpp index 4480c06abc..4a28f9eb51 100644 --- a/libraries/chain/include/eosio/chain/unapplied_transaction_queue.hpp +++ b/libraries/chain/include/eosio/chain/unapplied_transaction_queue.hpp @@ -133,10 +133,11 @@ class unapplied_transaction_queue { } } - void add_forked( const branch_type& forked_branch ) { + template + void add_forked( const BRANCH_TYPE& forked_branch ) { // forked_branch is in reverse order for( auto ritr = forked_branch.rbegin(), rend = forked_branch.rend(); ritr != rend; ++ritr ) { - const block_state_legacy_ptr& bsptr = *ritr; + const auto& bsptr = *ritr; for( auto itr = bsptr->trxs_metas().begin(), end = bsptr->trxs_metas().end(); itr != end; ++itr ) { const auto& trx = *itr; auto insert_itr = queue.insert( { trx, trx_enum_type::forked } ); diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index e2297de848..eeabf71061 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -467,15 +467,15 @@ namespace eosio { namespace testing { } tester(controller::config config, const genesis_state& genesis) { - init(config, genesis); + init(std::move(config), genesis); } tester(controller::config config) { - init(config); + init(std::move(config)); } tester(controller::config config, protocol_feature_set&& pfs, const genesis_state& genesis) { - init(config, std::move(pfs), genesis); + init(std::move(config), std::move(pfs), genesis); } tester(const fc::temp_directory& tempdir, bool use_genesis) { @@ -608,7 +608,7 @@ namespace eosio { namespace testing { auto sb = _produce_block(skip_time, false); auto bsf = validating_node->create_block_state_future( sb->calculate_id(), sb ); controller::block_report br; - validating_node->push_block( br, bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{} ); + validating_node->push_block( br, bsf.get(), {}, trx_meta_cache_lookup{} ); return sb; } @@ -620,7 +620,7 @@ namespace eosio { namespace testing { void validate_push_block(const signed_block_ptr& sb) { auto bsf = validating_node->create_block_state_future( sb->calculate_id(), sb ); controller::block_report br; - validating_node->push_block( br, bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{} ); + validating_node->push_block( br, bsf.get(), {}, trx_meta_cache_lookup{} ); } signed_block_ptr produce_empty_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms) )override { @@ -628,7 +628,7 @@ namespace eosio { namespace testing { auto sb = _produce_block(skip_time, true); auto bsf = validating_node->create_block_state_future( sb->calculate_id(), sb ); controller::block_report br; - validating_node->push_block( br, bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{} ); + validating_node->push_block( br, bsf.get(), {}, trx_meta_cache_lookup{} ); return sb; } diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index e002c1507e..b5e35533cb 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -205,32 +205,32 @@ namespace eosio { namespace testing { } void base_tester::init(controller::config config, const snapshot_reader_ptr& snapshot) { - cfg = config; + cfg = std::move(config); open(snapshot); } void base_tester::init(controller::config config, const genesis_state& genesis) { - cfg = config; + cfg = std::move(config); open(genesis); } void base_tester::init(controller::config config) { - cfg = config; + cfg = std::move(config); open(default_genesis().compute_chain_id()); } void base_tester::init(controller::config config, protocol_feature_set&& pfs, const snapshot_reader_ptr& snapshot) { - cfg = config; + cfg = std::move(config); open(std::move(pfs), snapshot); } void base_tester::init(controller::config config, protocol_feature_set&& pfs, const genesis_state& genesis) { - cfg = config; + cfg = std::move(config); open(std::move(pfs), genesis); } void base_tester::init(controller::config config, protocol_feature_set&& pfs) { - cfg = config; + cfg = std::move(config); open(std::move(pfs), default_genesis().compute_chain_id()); } @@ -379,7 +379,7 @@ namespace eosio { namespace testing { auto bsf = control->create_block_state_future(b->calculate_id(), b); unapplied_transactions.add_aborted( control->abort_block() ); controller::block_report br; - control->push_block( br, bsf.get(), [this]( const branch_type& forked_branch ) { + control->push_block( br, bsf.get(), [this]( const branch_type_legacy& forked_branch ) { unapplied_transactions.add_forked( forked_branch ); }, [this]( const transaction_id_type& id ) { return unapplied_transactions.get_trx( id ); @@ -1118,7 +1118,7 @@ namespace eosio { namespace testing { auto bsf = b.control->create_block_state_future( block->calculate_id(), block ); b.control->abort_block(); controller::block_report br; - b.control->push_block(br, bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{}); //, eosio::chain::validation_steps::created_block); + b.control->push_block(br, bsf.get(), {}, trx_meta_cache_lookup{}); //, eosio::chain::validation_steps::created_block); } } }; diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index ee3a564499..56761924a6 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1800,9 +1800,9 @@ read_only::get_producers( const read_only::get_producers_params& params, const f read_only::get_producer_schedule_result read_only::get_producer_schedule( const read_only::get_producer_schedule_params& p, const fc::time_point& ) const { read_only::get_producer_schedule_result result; to_variant(db.active_producers(), result.active); - if(!db.pending_producers().producers.empty()) - to_variant(db.pending_producers(), result.pending); - auto proposed = db.proposed_producers(); + if (const auto* pending = db.next_producers()) // not applicable for instant-finality + to_variant(*pending, result.pending); + auto proposed = db.proposed_producers_legacy(); // empty for instant-finality if(proposed && !proposed->producers.empty()) to_variant(*proposed, result.proposed); return result; diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index bf8f7d0a07..967686ef4f 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -3929,7 +3929,9 @@ namespace eosio { } void net_plugin_impl::on_accepted_block() { - on_pending_schedule(chain_plug->chain().pending_producers()); + if (const auto* next_producers = chain_plug->chain().next_producers()) { + on_pending_schedule(*next_producers); + } on_active_schedule(chain_plug->chain().active_producers()); } diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 559d6e53af..182534b0f1 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -715,7 +715,7 @@ class producer_plugin_impl : public std::enable_shared_from_this block3 constexpr auto block3_input_last_qc_block_num = 2u; - auto block3_bhs_core = block2_bhs_core.next(block3_input_last_qc_block_num, true); + auto block3_bhs_core = block2_bhs_core.next({block3_input_last_qc_block_num, true}); // last_final_block_num should be the same as old one BOOST_REQUIRE_EQUAL(block3_bhs_core.last_final_block_num, block2_last_final_block_num); // final_on_strong_qc_block_num should be same as old one @@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(block_header_state_core_3_chain_transition_test) // block3 --> block4 constexpr auto block4_input_last_qc_block_num = 3u; - auto block4_bhs_core = block3_bhs_core.next(block4_input_last_qc_block_num, true); + auto block4_bhs_core = block3_bhs_core.next({block4_input_last_qc_block_num, true}); // last_final_block_num should not change BOOST_REQUIRE_EQUAL(block4_bhs_core.last_final_block_num, block2_last_final_block_num); // final_on_strong_qc_block_num should be block3's last_qc_block_num @@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(block_header_state_core_3_chain_transition_test) // block4 --> block5 constexpr auto block5_input_last_qc_block_num = 4u; - auto block5_bhs_core = block4_bhs_core.next(block5_input_last_qc_block_num, true); + auto block5_bhs_core = block4_bhs_core.next({block5_input_last_qc_block_num, true}); // last_final_block_num should have a new value BOOST_REQUIRE_EQUAL(block5_bhs_core.last_final_block_num, block4_final_on_strong_qc_block_num); // final_on_strong_qc_block_num should be block4's last_qc_block_num diff --git a/unittests/block_header_tests.cpp b/unittests/block_header_tests.cpp index 48e7e39abb..ae7d31421c 100644 --- a/unittests/block_header_tests.cpp +++ b/unittests/block_header_tests.cpp @@ -24,7 +24,7 @@ BOOST_AUTO_TEST_CASE(instant_finality_extension_with_empty_values_test) emplace_extension( header.header_extensions, instant_finality_extension::extension_id(), - fc::raw::pack( instant_finality_extension{qc_info_t{last_qc_block_num, is_last_qc_strong}, std::optional{}, std::optional{}} ) + fc::raw::pack( instant_finality_extension{qc_info_t{last_qc_block_num, is_last_qc_strong}, std::optional{}, std::shared_ptr{}} ) ); std::optional ext = header.extract_header_extension(instant_finality_extension::extension_id()); @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(instant_finality_extension_uniqueness_test) emplace_extension( header.header_extensions, instant_finality_extension::extension_id(), - fc::raw::pack( instant_finality_extension{qc_info_t{0, false}, {std::nullopt}, {std::nullopt}} ) + fc::raw::pack( instant_finality_extension{qc_info_t{0, false}, {std::nullopt}, std::shared_ptr{}} ) ); std::vector finalizers { {"test description", 50, fc::crypto::blslib::bls_public_key{"PUB_BLS_MPPeebAPxt/ibL2XPuZVGpADjGn+YEVPPoYmTZeBD6Ok2E19M8SnmDGSdZBf2qwSuJim+8H83EsTpEn3OiStWBiFeJYfVRLlEsZuSF0SYYwtVteY48n+KeE1IWzlSAkSyBqiGA==" }} }; @@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(instant_finality_extension_uniqueness_test) new_finalizer_policy.threshold = 100; new_finalizer_policy.finalizers = finalizers; - proposer_policy new_proposer_policy {1, block_timestamp_type{200}, {} }; + proposer_policy_ptr new_proposer_policy = std::make_shared(1, block_timestamp_type{200}, producer_authority_schedule{} ); emplace_extension( header.header_extensions, @@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(instant_finality_extension_with_values_test) new_finalizer_policy.threshold = 100; new_finalizer_policy.finalizers = finalizers; - proposer_policy new_proposer_policy {1, block_timestamp_type{200}, {} }; + proposer_policy_ptr new_proposer_policy = std::make_shared(1, block_timestamp_type{200}, producer_authority_schedule{} ); emplace_extension( header.header_extensions, diff --git a/unittests/block_tests.cpp b/unittests/block_tests.cpp index 9419557ea7..8e11f270e2 100644 --- a/unittests/block_tests.cpp +++ b/unittests/block_tests.cpp @@ -47,7 +47,7 @@ BOOST_AUTO_TEST_CASE(block_with_invalid_tx_test) auto bsf = validator.control->create_block_state_future( copy_b->calculate_id(), copy_b ); validator.control->abort_block(); controller::block_report br; - BOOST_REQUIRE_EXCEPTION(validator.control->push_block( br, bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{} ), fc::exception , + BOOST_REQUIRE_EXCEPTION(validator.control->push_block( br, bsf.get(), {}, trx_meta_cache_lookup{} ), fc::exception , [] (const fc::exception &e)->bool { return e.code() == account_name_exists_exception::code_value ; }) ; @@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(block_with_invalid_tx_mroot_test) auto bsf = validator.control->create_block_state_future( copy_b->calculate_id(), copy_b ); validator.control->abort_block(); controller::block_report br; - BOOST_REQUIRE_EXCEPTION(validator.control->push_block( br, bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{} ), fc::exception, + BOOST_REQUIRE_EXCEPTION(validator.control->push_block( br, bsf.get(), {}, trx_meta_cache_lookup{} ), fc::exception, [] (const fc::exception &e)->bool { return e.code() == block_validate_exception::code_value && e.to_detail_string().find("invalid block transaction merkle root") != std::string::npos; diff --git a/unittests/chain_tests.cpp b/unittests/chain_tests.cpp index 40e49e5a04..45ad505115 100644 --- a/unittests/chain_tests.cpp +++ b/unittests/chain_tests.cpp @@ -27,11 +27,14 @@ BOOST_AUTO_TEST_CASE( replace_producer_keys ) try { } } - const auto old_pending_version = tester.control->pending_producers().version; + // TODO: Add test with instant-finality enabled + BOOST_REQUIRE(tester.control->pending_producers_legacy()); + const auto old_pending_version = tester.control->pending_producers_legacy()->version; const auto old_version = tester.control->active_producers().version; BOOST_REQUIRE_NO_THROW(tester.control->replace_producer_keys(new_key)); const auto new_version = tester.control->active_producers().version; - const auto pending_version = tester.control->pending_producers().version; + BOOST_REQUIRE(tester.control->pending_producers_legacy()); + const auto pending_version = tester.control->pending_producers_legacy()->version; // make sure version not been changed BOOST_REQUIRE(old_version == new_version); BOOST_REQUIRE(old_version == pending_version); @@ -44,7 +47,8 @@ BOOST_AUTO_TEST_CASE( replace_producer_keys ) try { const uint32_t expected_threshold = 1; const weight_type expected_key_weight = 1; - for(const auto& prod : tester.control->pending_producers().producers) { + BOOST_REQUIRE(tester.control->pending_producers_legacy()); + for(const auto& prod : tester.control->pending_producers_legacy()->producers) { BOOST_REQUIRE_EQUAL(std::get(prod.authority).threshold, expected_threshold); for(const auto& key : std::get(prod.authority).keys){ BOOST_REQUIRE_EQUAL(key.key, new_key); diff --git a/unittests/forked_tests.cpp b/unittests/forked_tests.cpp index dc135a509c..2392663921 100644 --- a/unittests/forked_tests.cpp +++ b/unittests/forked_tests.cpp @@ -269,7 +269,7 @@ BOOST_AUTO_TEST_CASE( forking ) try { auto bad_block_bsf = c.control->create_block_state_future( bad_id, std::make_shared(std::move(bad_block)) ); c.control->abort_block(); controller::block_report br; - BOOST_REQUIRE_EXCEPTION(c.control->push_block( br, bad_block_bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{} ), fc::exception, + BOOST_REQUIRE_EXCEPTION(c.control->push_block( br, bad_block_bsf.get(), {}, trx_meta_cache_lookup{} ), fc::exception, [] (const fc::exception &ex)->bool { return ex.to_detail_string().find("block signed by unexpected key") != std::string::npos; }); diff --git a/unittests/producer_schedule_tests.cpp b/unittests/producer_schedule_tests.cpp index dbfd9531ce..ad894303b1 100644 --- a/unittests/producer_schedule_tests.cpp +++ b/unittests/producer_schedule_tests.cpp @@ -137,12 +137,13 @@ BOOST_FIXTURE_TEST_CASE( producer_schedule_promotion_test, validating_tester ) t }; //wdump((fc::json::to_pretty_string(res))); wlog("set producer schedule to [alice,bob]"); - BOOST_REQUIRE_EQUAL( true, control->proposed_producers().has_value() ); - BOOST_CHECK_EQUAL( true, compare_schedules( sch1, *control->proposed_producers() ) ); - BOOST_CHECK_EQUAL( control->pending_producers().version, 0u ); + BOOST_REQUIRE_EQUAL( true, control->proposed_producers_legacy().has_value() ); + BOOST_CHECK_EQUAL( true, compare_schedules( sch1, *control->proposed_producers_legacy() ) ); + BOOST_REQUIRE(control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( control->pending_producers_legacy()->version, 0u ); produce_block(); // Starts new block which promotes the proposed schedule to pending - BOOST_CHECK_EQUAL( control->pending_producers().version, 1u ); - BOOST_CHECK_EQUAL( true, compare_schedules( sch1, control->pending_producers() ) ); + BOOST_CHECK_EQUAL( control->pending_producers_legacy()->version, 1u ); + BOOST_CHECK_EQUAL( true, compare_schedules( sch1, *control->pending_producers_legacy() ) ); BOOST_CHECK_EQUAL( control->active_producers().version, 0u ); produce_block(); produce_block(); // Starts new block which promotes the pending schedule to active @@ -157,15 +158,16 @@ BOOST_FIXTURE_TEST_CASE( producer_schedule_promotion_test, validating_tester ) t producer_authority{"carol"_n, block_signing_authority_v0{1, {{get_public_key("carol"_n, "active"),1}}}} }; wlog("set producer schedule to [alice,bob,carol]"); - BOOST_REQUIRE_EQUAL( true, control->proposed_producers().has_value() ); - BOOST_CHECK_EQUAL( true, compare_schedules( sch2, *control->proposed_producers() ) ); + BOOST_REQUIRE_EQUAL( true, control->proposed_producers_legacy().has_value() ); + BOOST_CHECK_EQUAL( true, compare_schedules( sch2, *control->proposed_producers_legacy() ) ); produce_block(); produce_blocks(23); // Alice produces the last block of her first round. // Bob's first block (which advances LIB to Alice's last block) is started but not finalized. BOOST_REQUIRE_EQUAL( control->head_block_producer(), "alice"_n ); BOOST_REQUIRE_EQUAL( control->pending_block_producer(), "bob"_n ); - BOOST_CHECK_EQUAL( control->pending_producers().version, 2u ); + BOOST_REQUIRE(control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( control->pending_producers_legacy()->version, 2u ); produce_blocks(12); // Bob produces his first 11 blocks BOOST_CHECK_EQUAL( control->active_producers().version, 1u ); @@ -202,12 +204,13 @@ BOOST_FIXTURE_TEST_CASE( producer_schedule_reduction, tester ) try { producer_authority{"carol"_n, block_signing_authority_v0{ 1, {{get_public_key("carol"_n, "active"),1}}}} }; wlog("set producer schedule to [alice,bob,carol]"); - BOOST_REQUIRE_EQUAL( true, control->proposed_producers().has_value() ); - BOOST_CHECK_EQUAL( true, compare_schedules( sch1, *control->proposed_producers() ) ); - BOOST_CHECK_EQUAL( control->pending_producers().version, 0u ); + BOOST_REQUIRE_EQUAL( true, control->proposed_producers_legacy().has_value() ); + BOOST_CHECK_EQUAL( true, compare_schedules( sch1, *control->proposed_producers_legacy() ) ); + BOOST_REQUIRE(control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( control->pending_producers_legacy()->version, 0u ); produce_block(); // Starts new block which promotes the proposed schedule to pending - BOOST_CHECK_EQUAL( control->pending_producers().version, 1u ); - BOOST_CHECK_EQUAL( true, compare_schedules( sch1, control->pending_producers() ) ); + BOOST_CHECK_EQUAL( control->pending_producers_legacy()->version, 1u ); + BOOST_CHECK_EQUAL( true, compare_schedules( sch1, *control->pending_producers_legacy() ) ); BOOST_CHECK_EQUAL( control->active_producers().version, 0u ); produce_block(); produce_block(); // Starts new block which promotes the pending schedule to active @@ -221,13 +224,14 @@ BOOST_FIXTURE_TEST_CASE( producer_schedule_reduction, tester ) try { producer_authority{"bob"_n, block_signing_authority_v0{ 1, {{ get_public_key("bob"_n, "active"),1}}}} }; wlog("set producer schedule to [alice,bob]"); - BOOST_REQUIRE_EQUAL( true, control->proposed_producers().has_value() ); - BOOST_CHECK_EQUAL( true, compare_schedules( sch2, *control->proposed_producers() ) ); + BOOST_REQUIRE_EQUAL( true, control->proposed_producers_legacy().has_value() ); + BOOST_CHECK_EQUAL( true, compare_schedules( sch2, *control->proposed_producers_legacy() ) ); produce_blocks(48); BOOST_REQUIRE_EQUAL( control->head_block_producer(), "bob"_n ); BOOST_REQUIRE_EQUAL( control->pending_block_producer(), "carol"_n ); - BOOST_CHECK_EQUAL( control->pending_producers().version, 2u ); + BOOST_REQUIRE(control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( control->pending_producers_legacy()->version, 2u ); produce_blocks(47); BOOST_CHECK_EQUAL( control->active_producers().version, 1u ); @@ -264,14 +268,16 @@ BOOST_AUTO_TEST_CASE( empty_producer_schedule_has_no_effect ) try { producer_authority{"bob"_n, block_signing_authority_v0{ 1, {{ get_public_key("bob"_n, "active"),1}}}} }; wlog("set producer schedule to [alice,bob]"); - BOOST_REQUIRE_EQUAL( true, c.control->proposed_producers().has_value() ); - BOOST_CHECK_EQUAL( true, compare_schedules( sch1, *c.control->proposed_producers() ) ); - BOOST_CHECK_EQUAL( c.control->pending_producers().producers.size(), 0u ); + BOOST_REQUIRE_EQUAL( true, c.control->proposed_producers_legacy().has_value() ); + BOOST_CHECK_EQUAL( true, compare_schedules( sch1, *c.control->proposed_producers_legacy() ) ); + BOOST_REQUIRE(c.control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( c.control->pending_producers_legacy()->producers.size(), 0u ); // Start a new block which promotes the proposed schedule to pending c.produce_block(); - BOOST_CHECK_EQUAL( c.control->pending_producers().version, 1u ); - BOOST_CHECK_EQUAL( true, compare_schedules( sch1, c.control->pending_producers() ) ); + BOOST_REQUIRE(c.control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( c.control->pending_producers_legacy()->version, 1u ); + BOOST_CHECK_EQUAL( true, compare_schedules( sch1, *c.control->pending_producers_legacy() ) ); BOOST_CHECK_EQUAL( c.control->active_producers().version, 0u ); // Start a new block which promotes the pending schedule to active @@ -282,22 +288,25 @@ BOOST_AUTO_TEST_CASE( empty_producer_schedule_has_no_effect ) try { res = c.set_producers_legacy( {} ); wlog("set producer schedule to []"); - BOOST_REQUIRE_EQUAL( true, c.control->proposed_producers().has_value() ); - BOOST_CHECK_EQUAL( c.control->proposed_producers()->producers.size(), 0u ); - BOOST_CHECK_EQUAL( c.control->proposed_producers()->version, 2u ); + BOOST_REQUIRE_EQUAL( true, c.control->proposed_producers_legacy().has_value() ); + BOOST_CHECK_EQUAL( c.control->proposed_producers_legacy()->producers.size(), 0u ); + BOOST_CHECK_EQUAL( c.control->proposed_producers_legacy()->version, 2u ); c.produce_blocks(12); - BOOST_CHECK_EQUAL( c.control->pending_producers().version, 1u ); + BOOST_REQUIRE(c.control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( c.control->pending_producers_legacy()->version, 1u ); // Empty producer schedule does get promoted from proposed to pending c.produce_block(); - BOOST_CHECK_EQUAL( c.control->pending_producers().version, 2u ); - BOOST_CHECK_EQUAL( false, c.control->proposed_producers().has_value() ); + BOOST_REQUIRE(c.control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( c.control->pending_producers_legacy()->version, 2u ); + BOOST_CHECK_EQUAL( false, c.control->proposed_producers_legacy().has_value() ); // However it should not get promoted from pending to active c.produce_blocks(24); BOOST_CHECK_EQUAL( c.control->active_producers().version, 1u ); - BOOST_CHECK_EQUAL( c.control->pending_producers().version, 2u ); + BOOST_REQUIRE(c.control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( c.control->pending_producers_legacy()->version, 2u ); // Setting a new producer schedule should still use version 2 res = c.set_producers_legacy( {"alice"_n,"bob"_n,"carol"_n} ); @@ -307,15 +316,16 @@ BOOST_AUTO_TEST_CASE( empty_producer_schedule_has_no_effect ) try { producer_authority{"carol"_n, block_signing_authority_v0{ 1, {{get_public_key("carol"_n, "active"),1}}}} }; wlog("set producer schedule to [alice,bob,carol]"); - BOOST_REQUIRE_EQUAL( true, c.control->proposed_producers().has_value() ); - BOOST_CHECK_EQUAL( true, compare_schedules( sch2, *c.control->proposed_producers() ) ); - BOOST_CHECK_EQUAL( c.control->proposed_producers()->version, 2u ); + BOOST_REQUIRE_EQUAL( true, c.control->proposed_producers_legacy().has_value() ); + BOOST_CHECK_EQUAL( true, compare_schedules( sch2, *c.control->proposed_producers_legacy() ) ); + BOOST_CHECK_EQUAL( c.control->proposed_producers_legacy()->version, 2u ); // Produce enough blocks to promote the proposed schedule to pending, which it can do because the existing pending has zero producers c.produce_blocks(24); BOOST_CHECK_EQUAL( c.control->active_producers().version, 1u ); - BOOST_CHECK_EQUAL( c.control->pending_producers().version, 2u ); - BOOST_CHECK_EQUAL( true, compare_schedules( sch2, c.control->pending_producers() ) ); + BOOST_REQUIRE(c.control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( c.control->pending_producers_legacy()->version, 2u ); + BOOST_CHECK_EQUAL( true, compare_schedules( sch2, *c.control->pending_producers_legacy() ) ); // Produce enough blocks to promote the pending schedule to active c.produce_blocks(24); @@ -342,12 +352,14 @@ BOOST_AUTO_TEST_CASE( producer_watermark_test ) try { producer_authority{"carol"_n, block_signing_authority_v0{ 1, {{c.get_public_key("carol"_n, "active"),1}}}} }; wlog("set producer schedule to [alice,bob,carol]"); - BOOST_REQUIRE_EQUAL( true, c.control->proposed_producers().has_value() ); - BOOST_CHECK_EQUAL( true, compare_schedules( sch1, *c.control->proposed_producers() ) ); - BOOST_CHECK_EQUAL( c.control->pending_producers().version, 0u ); + BOOST_REQUIRE_EQUAL( true, c.control->proposed_producers_legacy().has_value() ); + BOOST_CHECK_EQUAL( true, compare_schedules( sch1, *c.control->proposed_producers_legacy() ) ); + BOOST_REQUIRE(c.control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( c.control->pending_producers_legacy()->version, 0u ); c.produce_block(); // Starts new block which promotes the proposed schedule to pending - BOOST_CHECK_EQUAL( c.control->pending_producers().version, 1u ); - BOOST_CHECK_EQUAL( true, compare_schedules( sch1, c.control->pending_producers() ) ); + BOOST_REQUIRE(c.control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( c.control->pending_producers_legacy()->version, 1u ); + BOOST_CHECK_EQUAL( true, compare_schedules( sch1, *c.control->pending_producers_legacy() ) ); BOOST_CHECK_EQUAL( c.control->active_producers().version, 0u ); c.produce_block(); c.produce_block(); // Starts new block which promotes the pending schedule to active @@ -364,16 +376,18 @@ BOOST_AUTO_TEST_CASE( producer_watermark_test ) try { producer_authority{"bob"_n, block_signing_authority_v0{ 1, {{c.get_public_key("bob"_n, "active"),1}}}} }; wlog("set producer schedule to [alice,bob]"); - BOOST_REQUIRE_EQUAL( true, c.control->proposed_producers().has_value() ); - BOOST_CHECK_EQUAL( true, compare_schedules( sch2, *c.control->proposed_producers() ) ); + BOOST_REQUIRE_EQUAL( true, c.control->proposed_producers_legacy().has_value() ); + BOOST_CHECK_EQUAL( true, compare_schedules( sch2, *c.control->proposed_producers_legacy() ) ); produce_until_transition( c, "bob"_n, "carol"_n ); produce_until_transition( c, "alice"_n, "bob"_n ); - BOOST_CHECK_EQUAL( c.control->pending_producers().version, 2u ); + BOOST_REQUIRE(c.control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( c.control->pending_producers_legacy()->version, 2u ); BOOST_CHECK_EQUAL( c.control->active_producers().version, 1u ); produce_until_transition( c, "carol"_n, "alice"_n ); - BOOST_CHECK_EQUAL( c.control->pending_producers().version, 2u ); + BOOST_REQUIRE(c.control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( c.control->pending_producers_legacy()->version, 2u ); BOOST_CHECK_EQUAL( c.control->active_producers().version, 1u ); produce_until_transition( c, "bob"_n, "carol"_n ); @@ -388,8 +402,8 @@ BOOST_AUTO_TEST_CASE( producer_watermark_test ) try { res = c.set_producers( {"alice"_n,"bob"_n,"carol"_n} ); wlog("set producer schedule to [alice,bob,carol]"); - BOOST_REQUIRE_EQUAL( true, c.control->proposed_producers().has_value() ); - BOOST_CHECK_EQUAL( true, compare_schedules( sch1, *c.control->proposed_producers() ) ); + BOOST_REQUIRE_EQUAL( true, c.control->proposed_producers_legacy().has_value() ); + BOOST_CHECK_EQUAL( true, compare_schedules( sch1, *c.control->proposed_producers_legacy() ) ); produce_until_transition( c, "bob"_n, "alice"_n ); @@ -415,7 +429,8 @@ BOOST_AUTO_TEST_CASE( producer_watermark_test ) try { BOOST_CHECK_EQUAL( carol_itr->second, carol_last_produced_block_num ); } - BOOST_CHECK_EQUAL( c.control->pending_producers().version, 3u ); + BOOST_REQUIRE(c.control->pending_producers_legacy()); + BOOST_CHECK_EQUAL( c.control->pending_producers_legacy()->version, 3u ); BOOST_REQUIRE_EQUAL( c.control->active_producers().version, 2u ); produce_until_transition( c, "bob"_n, "alice"_n ); @@ -495,7 +510,7 @@ BOOST_FIXTURE_TEST_CASE( satisfiable_msig_test, validating_tester ) try { fc_exception_message_is( "producer schedule includes an unsatisfiable authority for alice" ) ); - BOOST_REQUIRE_EQUAL( false, control->proposed_producers().has_value() ); + BOOST_REQUIRE_EQUAL( false, control->proposed_producers_legacy().has_value() ); } FC_LOG_AND_RETHROW() @@ -514,7 +529,7 @@ BOOST_FIXTURE_TEST_CASE( duplicate_producers_test, validating_tester ) try { fc_exception_message_is( "duplicate producer name in producer schedule" ) ); - BOOST_REQUIRE_EQUAL( false, control->proposed_producers().has_value() ); + BOOST_REQUIRE_EQUAL( false, control->proposed_producers_legacy().has_value() ); } FC_LOG_AND_RETHROW() @@ -532,7 +547,7 @@ BOOST_FIXTURE_TEST_CASE( duplicate_keys_test, validating_tester ) try { fc_exception_message_is( "producer schedule includes a duplicated key for alice" ) ); - BOOST_REQUIRE_EQUAL( false, control->proposed_producers().has_value() ); + BOOST_REQUIRE_EQUAL( false, control->proposed_producers_legacy().has_value() ); // ensure that multiple producers are allowed to share keys vector sch2 = { @@ -541,7 +556,7 @@ BOOST_FIXTURE_TEST_CASE( duplicate_keys_test, validating_tester ) try { }; set_producer_schedule( sch2 ); - BOOST_REQUIRE_EQUAL( true, control->proposed_producers().has_value() ); + BOOST_REQUIRE_EQUAL( true, control->proposed_producers_legacy().has_value() ); } FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_CASE( large_authority_overflow_test ) try { @@ -603,7 +618,7 @@ BOOST_AUTO_TEST_CASE( extra_signatures_test ) try { }; main.set_producer_schedule( sch1 ); - BOOST_REQUIRE_EQUAL( true, main.control->proposed_producers().has_value() ); + BOOST_REQUIRE_EQUAL( true, main.control->proposed_producers_legacy().has_value() ); main.block_signing_private_keys.emplace(get_public_key("alice"_n, "bs1"), get_private_key("alice"_n, "bs1")); main.block_signing_private_keys.emplace(get_public_key("alice"_n, "bs2"), get_private_key("alice"_n, "bs2")); diff --git a/unittests/protocol_feature_tests.cpp b/unittests/protocol_feature_tests.cpp index 09df3ebdcf..45c76ab339 100644 --- a/unittests/protocol_feature_tests.cpp +++ b/unittests/protocol_feature_tests.cpp @@ -2257,7 +2257,7 @@ BOOST_AUTO_TEST_CASE( block_validation_after_stage_1_test ) { try { controller::block_report br; // The block is invalidated - BOOST_REQUIRE_EXCEPTION(tester2.control->push_block( br, bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{} ), + BOOST_REQUIRE_EXCEPTION(tester2.control->push_block( br, bsf.get(), {}, trx_meta_cache_lookup{} ), fc::exception, fc_exception_message_starts_with("transaction cannot be delayed") ); diff --git a/unittests/unapplied_transaction_queue_tests.cpp b/unittests/unapplied_transaction_queue_tests.cpp index 5d91202698..d2f683dc32 100644 --- a/unittests/unapplied_transaction_queue_tests.cpp +++ b/unittests/unapplied_transaction_queue_tests.cpp @@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE( unapplied_transaction_queue_test ) try { auto bs1 = create_test_block_state( { trx1, trx2 } ); auto bs2 = create_test_block_state( { trx3, trx4, trx5 } ); auto bs3 = create_test_block_state( { trx6 } ); - q.add_forked( { bs3, bs2, bs1, bs1 } ); // bs1 duplicate ignored + q.add_forked( branch_type_legacy{ bs3, bs2, bs1, bs1 } ); // bs1 duplicate ignored BOOST_CHECK( q.size() == 6u ); BOOST_REQUIRE( next( q ) == trx1 ); BOOST_CHECK( q.size() == 5u ); @@ -155,9 +155,9 @@ BOOST_AUTO_TEST_CASE( unapplied_transaction_queue_test ) try { // fifo forked auto bs4 = create_test_block_state( { trx7 } ); - q.add_forked( { bs1 } ); - q.add_forked( { bs3, bs2 } ); - q.add_forked( { bs4 } ); + q.add_forked( branch_type_legacy{ bs1 } ); + q.add_forked( branch_type_legacy{ bs3, bs2 } ); + q.add_forked( branch_type_legacy{ bs4 } ); BOOST_CHECK( q.size() == 7u ); BOOST_REQUIRE( next( q ) == trx1 ); BOOST_CHECK( q.size() == 6u ); @@ -189,10 +189,10 @@ BOOST_AUTO_TEST_CASE( unapplied_transaction_queue_test ) try { // fifo forked, multi forks auto bs5 = create_test_block_state( { trx11, trx12, trx13 } ); auto bs6 = create_test_block_state( { trx11, trx15 } ); - q.add_forked( { bs3, bs2, bs1 } ); - q.add_forked( { bs4 } ); - q.add_forked( { bs3, bs2 } ); // dups ignored - q.add_forked( { bs6, bs5 } ); + q.add_forked( branch_type_legacy{ bs3, bs2, bs1 } ); + q.add_forked( branch_type_legacy{ bs4 } ); + q.add_forked( branch_type_legacy{ bs3, bs2 } ); // dups ignored + q.add_forked( branch_type_legacy{ bs6, bs5 } ); BOOST_CHECK_EQUAL( q.size(), 11u ); BOOST_REQUIRE( next( q ) == trx1 ); BOOST_CHECK( q.size() == 10u ); @@ -220,10 +220,10 @@ BOOST_AUTO_TEST_CASE( unapplied_transaction_queue_test ) try { BOOST_CHECK( q.empty() ); // altogether, order fifo: forked, aborted - q.add_forked( { bs3, bs2, bs1 } ); + q.add_forked( branch_type_legacy{ bs3, bs2, bs1 } ); q.add_aborted( { trx9, trx14 } ); q.add_aborted( { trx18, trx19 } ); - q.add_forked( { bs6, bs5, bs4 } ); + q.add_forked( branch_type_legacy{ bs6, bs5, bs4 } ); // verify order verify_order( q, q.begin(), 15 ); // verify type order @@ -289,7 +289,7 @@ BOOST_AUTO_TEST_CASE( unapplied_transaction_queue_test ) try { BOOST_REQUIRE( next( q ) == trx22 ); BOOST_CHECK( q.empty() ); - q.add_forked( { bs3, bs2, bs1 } ); + q.add_forked( branch_type_legacy{ bs3, bs2, bs1 } ); q.add_aborted( { trx9, trx11 } ); q.clear(); BOOST_CHECK( q.empty() );