From adf303787c058698bdfb6a088b79e31374651710 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Fri, 19 Jan 2024 11:05:57 -0500 Subject: [PATCH 1/5] Rename some functions to better match what they actually do. --- libraries/chain/controller.cpp | 14 +++++++------- .../include/eosio/chain/block_header_state.hpp | 2 +- libraries/chain/include/eosio/chain/controller.hpp | 2 +- libraries/testing/tester.cpp | 2 +- plugins/producer_plugin/producer_plugin.cpp | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 283a4ff66f..192386f788 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -558,8 +558,8 @@ struct assembled_block { v); } - completed_block make_completed_block(const protocol_feature_set& pfs, validator_t validator, - const signer_callback_type& signer) { + completed_block complete_block(const protocol_feature_set& pfs, validator_t validator, + const signer_callback_type& signer) { return std::visit(overloaded{[&](assembled_block_dpos& ab) { auto bsp = std::make_shared( std::move(ab.pending_block_header_state), std::move(ab.unsigned_block), @@ -2693,7 +2693,7 @@ struct controller_impl { guard_pending.cancel(); } /// start_block - void finish_block(bool validating = false, std::optional validating_qc_info = {}) + void assemble_block(bool validating = false, std::optional validating_qc_info = {}) { EOS_ASSERT( pending, block_validate_exception, "it is not valid to finalize when there is no pending block"); EOS_ASSERT( std::holds_alternative(pending->_block_stage), block_validate_exception, "already called finish_block"); @@ -3003,7 +3003,7 @@ struct controller_impl { auto& if_ext = std::get(if_entry->second); qc_info = if_ext.qc_info; } - finish_block(true, qc_info); + assemble_block(true, qc_info); auto& ab = std::get(pending->_block_stage); @@ -3935,13 +3935,13 @@ void controller::start_block( block_timestamp_type when, bs, std::optional(), deadline ); } -void controller::finish_block( block_report& br, const signer_callback_type& signer_callback ) { +void controller::assemble_and_complete_block( block_report& br, const signer_callback_type& signer_callback ) { validate_db_available_size(); - my->finish_block(); + my->assemble_block(); auto& ab = std::get(my->pending->_block_stage); - my->pending->_block_stage = ab.make_completed_block( + my->pending->_block_stage = ab.complete_block( my->protocol_features.get_protocol_feature_set(), [](block_timestamp_type timestamp, const flat_set& cur_features, const vector& new_features) {}, signer_callback); diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index 48253149bc..43e318479f 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -68,7 +68,7 @@ struct block_header_state { // ------ functions ----------------------------------------------------------------- -#warning TDDO https://github.com/AntelopeIO/leap/issues/2080 + // [if todo] https://github.com/AntelopeIO/leap/issues/2080 digest_type compute_finalizer_digest() const { return id; }; block_timestamp_type timestamp() const { return header.timestamp; } account_name producer() const { return header.producer; } diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 402209b563..e13ec1f606 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -184,7 +184,7 @@ namespace eosio::chain { fc::microseconds total_time{}; }; - void finish_block( block_report& br, const signer_callback_type& signer_callback ); + void assemble_and_complete_block( block_report& br, const signer_callback_type& signer_callback ); void sign_block( const signer_callback_type& signer_callback ); void commit_block(); diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index d4b97fc002..d6cf964be7 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -487,7 +487,7 @@ namespace eosio { namespace testing { }); controller::block_report br; - control->finish_block( br, [&]( digest_type d ) { + control->assemble_and_complete_block( br, [&]( digest_type d ) { std::vector result; result.reserve(signing_keys.size()); for (const auto& k: signing_keys) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index f2478176f2..49b8d8c55c 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -2648,7 +2648,7 @@ void producer_plugin_impl::produce_block() { // idump( (fc::time_point::now() - chain.pending_block_time()) ); controller::block_report br; - chain.finish_block(br, [&](const digest_type& d) { + chain.assemble_and_complete_block(br, [&](const digest_type& d) { auto debug_logger = maybe_make_debug_time_logger(); vector sigs; sigs.reserve(relevant_providers.size()); From ce58704134e816558bfd7ce9d622bc4bad8d5a9e Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Fri, 19 Jan 2024 11:28:38 -0500 Subject: [PATCH 2/5] Pass correct qc to `assembled_block_if` constructor. --- libraries/chain/controller.cpp | 46 +++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 192386f788..e5127ab38a 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -856,7 +856,7 @@ struct building_block { const protocol_feature_set& pfs, const block_data_t& block_data, bool validating, - std::optional validating_qc_info) { + std::optional validating_qc_data) { digests_t& action_receipts = action_receipt_digests(); return std::visit( overloaded{ @@ -912,7 +912,10 @@ struct building_block { // find most recent ancestor block that has a QC by traversing fork db // branch from parent std::optional qc_data; - if (!validating) { + if (validating) { + // we are simulating a block received from the network. Use the embedded qc from the block + qc_data = validating_qc_data; + } else { auto branch = fork_db.fetch_branch(parent_id()); for( auto it = branch.begin(); it != branch.end(); ++it ) { auto qc = (*it)->get_best_qc(); @@ -933,16 +936,10 @@ struct building_block { .new_protocol_feature_activations = new_protocol_feature_activations() }; - std::optional qc_info; - if (validating) { - qc_info = validating_qc_info; - } else if (qc_data) { - qc_info = qc_data->qc_info; - } block_header_state_input bhs_input{ bb_input, transaction_mroot, action_mroot, std::move(bb.new_proposer_policy), std::move(bb.new_finalizer_policy), - qc_info, validating + qc_data ? qc_data->qc_info : std::optional{}, validating }; assembled_block::assembled_block_if ab{std::move(bb.active_producer_authority), bb.parent.next(bhs_input), @@ -2693,7 +2690,7 @@ struct controller_impl { guard_pending.cancel(); } /// start_block - void assemble_block(bool validating = false, std::optional validating_qc_info = {}) + void assemble_block(bool validating = false, std::optional validating_qc_data = {}) { EOS_ASSERT( pending, block_validate_exception, "it is not valid to finalize when there is no pending block"); EOS_ASSERT( std::holds_alternative(pending->_block_stage), block_validate_exception, "already called finish_block"); @@ -2717,7 +2714,7 @@ struct controller_impl { 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, validating, validating_qc_info); + protocol_features.get_protocol_feature_set(), block_data, validating, validating_qc_data); // Update TaPoS table: create_block_summary( assembled_block.id() ); @@ -2907,6 +2904,25 @@ struct controller_impl { #undef EOS_REPORT } + static std::optional extract_qc_data(const signed_block_ptr& b) { + std::optional qc_data; + auto hexts = b->validate_and_extract_header_extensions(); + if (auto if_entry = hexts.lower_bound(instant_finality_extension::extension_id()); if_entry != hexts.end()) { + auto& if_ext = std::get(if_entry->second); + if (if_ext.qc_info) { + auto exts = b->validate_and_extract_extensions(); + if (auto entry = exts.lower_bound(quorum_certificate_extension::extension_id()); entry != exts.end()) { + // this should always be the case that we find a quorum_certificate_extension + auto& qc_ext = std::get(entry->second); + qc_data = { qc_ext.qc, *if_ext.qc_info }; + } + else + qc_data = { quorum_certificate{}, *if_ext.qc_info }; + } + } + return qc_data; + } + template void apply_block( controller::block_report& br, const BSP& bsp, controller::block_status s, const trx_meta_cache_lookup& trx_lookup ) { @@ -2997,13 +3013,7 @@ struct controller_impl { ("lhs", r)("rhs", static_cast(receipt))); } - std::optional qc_info; - auto exts = b->validate_and_extract_header_extensions(); - if (auto if_entry = exts.lower_bound(instant_finality_extension::extension_id()); if_entry != exts.end()) { - auto& if_ext = std::get(if_entry->second); - qc_info = if_ext.qc_info; - } - assemble_block(true, qc_info); + assemble_block(true, extract_qc_data(b)); auto& ab = std::get(pending->_block_stage); From 58196a9fac2917a8e107b95a717b4632e2e6f532 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Fri, 19 Jan 2024 12:56:00 -0500 Subject: [PATCH 3/5] Simplify code building the `assembled_block`. --- libraries/chain/block_header_state.cpp | 6 ++-- libraries/chain/block_state.cpp | 2 +- libraries/chain/controller.cpp | 32 +++++++++---------- .../eosio/chain/block_header_state.hpp | 6 ---- 4 files changed, 18 insertions(+), 28 deletions(-) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 9359b8271c..df92dd77f8 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -131,9 +131,7 @@ block_header_state block_header_state::next(block_header_state_input& input) con instant_finality_extension new_if_ext {if_ext.qc_info, std::move(input.new_finalizer_policy), std::move(input.new_proposer_policy)}; - if (input.validating) - new_if_ext.qc_info = input.qc_info; - else if (input.qc_info) + 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)); @@ -198,7 +196,7 @@ block_header_state block_header_state::next(const signed_block_header& h, const 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, true}; + if_ext.qc_info }; return next(bhs_input); } diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index a93f6ae136..6130daa6ca 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -26,7 +26,7 @@ block_state::block_state(const block_header_state& bhs, dequetransactions = std::move(trx_receipts); - if( qc && bhs.is_needed(*qc) ) { + if( qc ) { emplace_extension(block->block_extensions, quorum_certificate_extension::extension_id(), fc::raw::pack( *qc )); } } diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index e5127ab38a..bfda0a20e2 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -914,7 +914,7 @@ struct building_block { std::optional qc_data; if (validating) { // we are simulating a block received from the network. Use the embedded qc from the block - qc_data = validating_qc_data; + qc_data = std::move(validating_qc_data); } else { auto branch = fork_db.fetch_branch(parent_id()); for( auto it = branch.begin(); it != branch.end(); ++it ) { @@ -939,7 +939,7 @@ struct building_block { block_header_state_input bhs_input{ 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{}, validating + qc_data ? qc_data->qc_info : std::optional{} }; assembled_block::assembled_block_if ab{std::move(bb.active_producer_authority), bb.parent.next(bhs_input), @@ -2713,8 +2713,9 @@ struct controller_impl { ); 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, validating, validating_qc_data); + auto assembled_block = + bb.assemble_block(thread_pool.get_executor(), protocol_features.get_protocol_feature_set(), block_data, + validating, std::move(validating_qc_data)); // Update TaPoS table: create_block_summary( assembled_block.id() ); @@ -2906,21 +2907,18 @@ struct controller_impl { static std::optional extract_qc_data(const signed_block_ptr& b) { std::optional qc_data; - auto hexts = b->validate_and_extract_header_extensions(); - if (auto if_entry = hexts.lower_bound(instant_finality_extension::extension_id()); if_entry != hexts.end()) { + auto exts = b->validate_and_extract_extensions(); + if (auto entry = exts.lower_bound(quorum_certificate_extension::extension_id()); entry != exts.end()) { + auto& qc_ext = std::get(entry->second); + + // get the matching header extension... should always be present + auto hexts = b->validate_and_extract_header_extensions(); + auto if_entry = hexts.lower_bound(instant_finality_extension::extension_id()); + assert(if_entry != hexts.end()); auto& if_ext = std::get(if_entry->second); - if (if_ext.qc_info) { - auto exts = b->validate_and_extract_extensions(); - if (auto entry = exts.lower_bound(quorum_certificate_extension::extension_id()); entry != exts.end()) { - // this should always be the case that we find a quorum_certificate_extension - auto& qc_ext = std::get(entry->second); - qc_data = { qc_ext.qc, *if_ext.qc_info }; - } - else - qc_data = { quorum_certificate{}, *if_ext.qc_info }; - } + return qc_data_t{ std::move(qc_ext.qc), *if_ext.qc_info }; } - return qc_data; + return {}; } template diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index 43e318479f..0e9185152e 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -33,7 +33,6 @@ struct block_header_state_input : public building_block_input { 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)); - bool validating = false; }; struct block_header_state_core { @@ -80,11 +79,6 @@ struct block_header_state { 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; } const vector& get_new_protocol_feature_activations() const; producer_authority get_scheduled_producer(block_timestamp_type t) const; From fdd69b7b62f70035ce596c5f353e8a2ddc4c8fe8 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Fri, 19 Jan 2024 13:02:38 -0500 Subject: [PATCH 4/5] Small cleanups. --- libraries/chain/block_state.cpp | 4 ++-- libraries/chain/controller.cpp | 14 ++++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index 6130daa6ca..bf16a34a18 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -35,7 +35,7 @@ block_state::block_state(const block_header_state& bhs, deque ext = bsp.block->extract_header_extension(instant_finality_extension::extension_id()); assert(ext); // required by current transition mechanism @@ -83,7 +83,7 @@ std::pair> block_state::aggregate_vote(const hs_vo return {valid, strong ? core.final_on_strong_qc_block_num : std::optional{}}; } else { wlog( "finalizer_key (${k}) in vote is not in finalizer policy", ("k", vote.finalizer_key) ); - return {false, {}}; + return {}; } } diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index bfda0a20e2..9ad93a3372 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -2886,18 +2886,16 @@ struct controller_impl { EOS_REPORT( "header_extensions", b.header_extensions, ab.header_extensions ) if (b.header_extensions != ab.header_extensions) { - { - flat_multimap bheader_exts = b.validate_and_extract_header_extensions(); - if (bheader_exts.count(instant_finality_extension::extension_id())) { - const auto& if_extension = - std::get(bheader_exts.lower_bound(instant_finality_extension::extension_id())->second); - elog("b if: ${i}", ("i", if_extension)); - } + flat_multimap bheader_exts = b.validate_and_extract_header_extensions(); + if (bheader_exts.count(instant_finality_extension::extension_id())) { + const auto& if_extension = + std::get(bheader_exts.lower_bound(instant_finality_extension::extension_id())->second); + elog("b if: ${i}", ("i", if_extension)); } flat_multimap abheader_exts = ab.validate_and_extract_header_extensions(); if (abheader_exts.count(instant_finality_extension::extension_id())) { const auto& if_extension = - std::get(abheader_exts.lower_bound(instant_finality_extension::extension_id())->second); + std::get(abheader_exts.lower_bound(instant_finality_extension::extension_id())->second); elog("ab if: ${i}", ("i", if_extension)); } } From 12075229f185ea6f3998d9a66a83a945bad4ae52 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Sat, 20 Jan 2024 09:43:09 -0600 Subject: [PATCH 5/5] GH-2048 Misc cleanup --- libraries/chain/controller.cpp | 35 +++++----- libraries/chain/fork_database.cpp | 19 +++-- .../include/eosio/chain/fork_database.hpp | 70 +++++++++++-------- 3 files changed, 73 insertions(+), 51 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 600251aaa1..5dbcecd145 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -668,7 +668,7 @@ struct building_block { // branch from parent std::optional qc_data; if (!validating) { - // get fork_database so that we can search for the best qc to include in this block. + // get fork_database so that we can search for the best qc to include in this block. fork_db.apply_if([&](const auto& forkdb) { auto branch = forkdb.fetch_branch(parent_id()); for( auto it = branch.begin(); it != branch.end(); ++it ) { @@ -1245,7 +1245,7 @@ struct controller_impl { forkdb.chain_head->block = std::make_shared(genheader.header); }; - fork_db.apply_dpos(init_blockchain); // assuming here that genesis_state is always dpos + fork_db.apply_legacy(init_blockchain); // assuming here that genesis_state is always dpos db.set_revision( head_block_num() ); initialize_database(genesis); @@ -1625,7 +1625,7 @@ struct controller_impl { section.template add_row(*forkdb.chain_head, db); }); }; - fork_db.apply_dpos(write_block_state_section); + fork_db.apply_legacy(write_block_state_section); controller_index_set::walk_indices([this, &snapshot]( auto utils ){ using value_t = typename decltype(utils)::index_t::value_type; @@ -1702,7 +1702,7 @@ struct controller_impl { forkdb.chain_head = std::make_shared(); static_cast(*forkdb.chain_head) = head_header_state; }; - fork_db.apply_dpos(read_block_state_section); + fork_db.apply_legacy(read_block_state_section); controller_index_set::walk_indices([this, &snapshot, &header]( auto utils ){ using value_t = typename decltype(utils)::index_t::value_type; @@ -2470,16 +2470,17 @@ struct controller_impl { "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()) ); - fork_db.apply_dpos([&](auto& forkdb) { - maybe_session session = self.skip_db_sessions(s) ? maybe_session() : maybe_session(db); - pending.emplace(std::move(session), *forkdb.chain_head, when, confirm_block_count, new_protocol_feature_activations); - }); - fork_db.apply_if([&](auto& forkdb) { - maybe_session session = self.skip_db_sessions(s) ? maybe_session() : maybe_session(db); - building_block_input bbi{ forkdb.chain_head->id(), when, forkdb.chain_head->get_scheduled_producer(when).producer_name, - new_protocol_feature_activations }; - pending.emplace(std::move(session), *forkdb.chain_head, bbi); - }); + fork_db.apply( + [&](auto& forkdb) { // legacy + maybe_session session = self.skip_db_sessions(s) ? maybe_session() : maybe_session(db); + pending.emplace(std::move(session), *forkdb.chain_head, when, confirm_block_count, new_protocol_feature_activations); + }, + [&](auto& forkdb) { // instant-finality + maybe_session session = self.skip_db_sessions(s) ? maybe_session() : maybe_session(db); + building_block_input bbi{forkdb.chain_head->id(), when, forkdb.chain_head->get_scheduled_producer(when).producer_name, + new_protocol_feature_activations}; + pending.emplace(std::move(session), *forkdb.chain_head, bbi); + }); pending->_block_status = s; pending->_producer_block_id = producer_block_id; @@ -2686,7 +2687,7 @@ struct controller_impl { fork_db.apply(add_completed_block); - fork_db.apply_dpos([this](auto& forkdb) { + fork_db.apply_legacy([this](auto& forkdb) { #warning todo: support deep_mind_logger even when in IF mode (use apply instead of apply_dpos) // at block level, no transaction specific logging is possible if (auto* dm_logger = get_deep_mind_logger(false)) { @@ -2714,7 +2715,7 @@ struct controller_impl { } return false; }; - if (fork_db.apply_dpos(transition)) { + if (fork_db.apply_legacy(transition)) { fork_db.switch_from_legacy(); } @@ -3981,7 +3982,7 @@ const block_header& controller::head_block_header()const { block_state_legacy_ptr controller::head_block_state_legacy()const { // returns null after instant finality activated - return my->fork_db.apply_dpos( + return my->fork_db.apply_legacy( [](auto& forkdb) -> block_state_legacy_ptr { return forkdb.chain_head; }); } diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index f1aadfe01a..552298a025 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -39,7 +39,7 @@ namespace eosio::chain { using bhsp = bs::bhsp_t; using bhs = bhsp::element_type; - using fork_db_t = fork_database_t; + using fork_db_t = fork_database_t; using branch_type = fork_db_t::branch_type; using branch_type_pair = fork_db_t::branch_type_pair; @@ -565,6 +565,10 @@ namespace eosio::chain { } fork_database::~fork_database() { + close(); + } + + void fork_database::close() { apply([&](auto& forkdb) { forkdb.close(data_dir / config::forkdb_filename); }); } @@ -592,26 +596,29 @@ namespace eosio::chain { ); if (totem == fork_database_legacy_t::legacy_magic_number) { - apply_dpos([&](auto& forkdb) { + apply_legacy([&](auto& forkdb) { forkdb.open(fork_db_file, validator); }); } else { // file is instant-finality data, so switch to fork_database_if_t - v.emplace(fork_database_if_t::magic_number); + vforkdb.emplace(fork_database_if_t::magic_number); apply_if([&](auto& forkdb) { forkdb.open(fork_db_file, validator); }); } + apply([&](auto& forkdb) { + forkdb.open(fork_db_file, validator); + }); } FC_CAPTURE_AND_RETHROW( (fork_db_file) ) } } void fork_database::switch_from_legacy() { + std::lock_guard g(m); // no need to close fork_db because we don't want to write anything out, file is removed on open - block_state_legacy_ptr head = std::get(v).chain_head; // will throw if called after transistion + block_state_legacy_ptr head = std::get(vforkdb).chain_head; // will throw if called after transistion auto new_head = std::make_shared(*head); - std::lock_guard g(m); - v.emplace(fork_database_if_t::magic_number); + vforkdb.emplace(fork_database_if_t::magic_number); apply_if([&](auto& forkdb) { forkdb.chain_head = new_head; forkdb.reset(*new_head); diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 9e90c6e310..a2f4f7f868 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -20,6 +20,8 @@ namespace eosio::chain { * irreversible signal. * * Not thread safe, thread safety provided by fork_database below. + * fork_database should be used instead of fork_database_t directly as it manages + * the different supported types. */ template // either block_state_legacy_ptr or block_state_ptr class fork_database_t { @@ -107,17 +109,20 @@ namespace eosio::chain { /** * Provides thread safety on fork_database_t and provide mechanism for opening the correct type - * as well as switching from legacy to instant-finality. + * as well as switching from legacy (old dpos) to instant-finality. + * + * All methods assert until open() is closed. */ class fork_database { mutable std::recursive_mutex m; const std::filesystem::path data_dir; - std::variant, fork_database_t> v; + std::variant, fork_database_t> vforkdb; public: explicit fork_database(const std::filesystem::path& data_dir); ~fork_database(); // close on destruction void open( validator_t& validator ); + void close(); void switch_from_legacy(); @@ -128,55 +133,64 @@ namespace eosio::chain { R apply(const F& f) { std::lock_guard g(m); if constexpr (std::is_same_v) - std::visit([&](auto& forkdb) { f(forkdb); }, v); + std::visit([&](auto& forkdb) { f(forkdb); }, vforkdb); else - return std::visit([&](auto& forkdb) -> R { return f(forkdb); }, v); + return std::visit([&](auto& forkdb) -> R { return f(forkdb); }, vforkdb); } template R apply(const F& f) const { std::lock_guard g(m); if constexpr (std::is_same_v) - std::visit([&](const auto& forkdb) { f(forkdb); }, v); + std::visit([&](const auto& forkdb) { f(forkdb); }, vforkdb); else - return std::visit([&](const auto& forkdb) -> R { return f(forkdb); }, v); + return std::visit([&](const auto& forkdb) -> R { return f(forkdb); }, vforkdb); } + /// Apply for when only need lambda executed when in instant-finality mode template R apply_if(const F& f) { + std::lock_guard g(m); if constexpr (std::is_same_v) std::visit(overloaded{[&](fork_database_legacy_t&) {}, - [&](fork_database_if_t& forkdb) { - std::lock_guard g(m); - f(forkdb); - }}, v); + [&](fork_database_if_t& forkdb) { f(forkdb); }}, + vforkdb); else return std::visit(overloaded{[&](fork_database_legacy_t&) -> R { return {}; }, - [&](fork_database_if_t& forkdb) -> R { - std::lock_guard g(m); - return f(forkdb); - }}, v); + [&](fork_database_if_t& forkdb) -> R { return f(forkdb); }}, + vforkdb); } + /// Apply for when only need lambda executed when in legacy mode template - R apply_dpos(const F& f) { + R apply_legacy(const F& f) { + std::lock_guard g(m); + if constexpr (std::is_same_v) + std::visit(overloaded{[&](fork_database_legacy_t& forkdb) { f(forkdb); }, + [&](fork_database_if_t&) {}}, + vforkdb); + else + return std::visit(overloaded{[&](fork_database_legacy_t& forkdb) -> R { return f(forkdb); }, + [&](fork_database_if_t&) -> R { return {}; }}, + vforkdb); + } + + /// @param legacy_f the lambda to execute if in legacy mode + /// @param if_f the lambda to execute if in instant-finality mode + template + R apply(const LegacyF& legacy_f, const IfF& if_f) { + std::lock_guard g(m); if constexpr (std::is_same_v) - std::visit(overloaded{[&](fork_database_legacy_t& forkdb) { - std::lock_guard g(m); - f(forkdb); - }, - [&](fork_database_if_t&) {}}, v); + std::visit(overloaded{[&](fork_database_legacy_t& forkdb) { legacy_f(forkdb); }, + [&](fork_database_if_t& forkdb) { if_f(forkdb); }}, + vforkdb); else - return std::visit(overloaded{[&](fork_database_legacy_t& forkdb) -> R { - std::lock_guard g(m); - return f(forkdb); - }, - [&](fork_database_if_t&) -> R { - return {}; - }}, v); + return std::visit(overloaded{[&](fork_database_legacy_t& forkdb) -> R { return legacy_f(forkdb); }, + [&](fork_database_if_t& forkdb) -> R { return if_f(forkdb); }}, + vforkdb); } - // if we every support more than one version then need to save min/max in fork_database_t + // if we ever support more than one version then need to save min/max in fork_database_t static constexpr uint32_t min_supported_version = 1; static constexpr uint32_t max_supported_version = 1; };