From 1565de0d00cf91c9f07765d4782a54d10a86c156 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 10 May 2024 22:40:19 -0500 Subject: [PATCH 1/6] GH-128 Replace active_finalizer_policy_digest with last_pending_finalizer_policy_digest --- libraries/chain/block_header_state.cpp | 34 ++++++++++++++++--- libraries/chain/block_state.cpp | 1 + .../eosio/chain/block_header_state.hpp | 7 +++- unittests/svnn_ibc_tests.cpp | 12 +++---- 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index c612870b21..d6cac55174 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -43,13 +43,11 @@ digest_type block_header_state::compute_base_digest() const { } digest_type block_header_state::compute_finality_digest() const { - assert(active_finalizer_policy); - auto active_finalizer_policy_digest = fc::sha256::hash(*active_finalizer_policy); auto base_digest = compute_base_digest(); - - std::pair active_and_base{ active_finalizer_policy_digest, base_digest }; + std::pair active_and_base{ last_pending_finalizer_policy_digest, base_digest }; auto afp_base_digest = fc::sha256::hash(active_and_base); + assert(active_finalizer_policy); finality_digest_data_v1 finality_digest_data { .active_finalizer_policy_generation = active_finalizer_policy->generation, .finality_tree_digest = finality_mroot(), @@ -67,7 +65,7 @@ const vector& block_header_state::get_new_protocol_feature_activati return detail::get_new_protocol_feature_activations(header_exts); } -// The last proposed finalizer policy if none proposed or pending is the active finalizer policy +// The last proposed finalizer policy if none proposed or pending then the active finalizer policy const finalizer_policy& block_header_state::get_last_proposed_finalizer_policy() const { if (!finalizer_policies.empty()) { for (auto ritr = finalizer_policies.rbegin(); ritr != finalizer_policies.rend(); ++ritr) { @@ -79,6 +77,30 @@ const finalizer_policy& block_header_state::get_last_proposed_finalizer_policy() return *active_finalizer_policy; } +// The last pending finalizer policy if none pending then the active finalizer policy +// Used to populate last_pending_finalizer_policy_digest which is expected to be the highest generation pending +const finalizer_policy& block_header_state::get_last_pending_finalizer_policy() const { + if (!finalizer_policies.empty()) { + [[maybe_unused]] auto highest_pending_generation = [this]() { + finalizer_policy_ptr highest; + for (auto ritr = finalizer_policies.rbegin(); ritr != finalizer_policies.rend(); ++ritr) { + if (ritr->second.state == finalizer_policy_tracker::state_t::pending) { + if (!highest || highest->generation < ritr->second.policy->generation) + highest = ritr->second.policy; + } + } + return highest; + }; + for (auto ritr = finalizer_policies.rbegin(); ritr != finalizer_policies.rend(); ++ritr) { + if (ritr->second.state == finalizer_policy_tracker::state_t::pending) { + assert(highest_pending_generation() == ritr->second.policy); + return *ritr->second.policy; + } + } + } + return *active_finalizer_policy; +} + // The last proposed proposer policy, if none proposed then the active proposer policy const proposer_policy& block_header_state::get_last_proposed_proposer_policy() const { if (proposer_policies.empty()) { @@ -183,6 +205,8 @@ void finish_next(const block_header_state& prev, } } + next_header_state.last_pending_finalizer_policy_digest = fc::sha256::hash(next_header_state.get_last_pending_finalizer_policy()); + if (if_ext.new_finalizer_policy_diff) { finalizer_policy new_finalizer_policy = prev.get_last_proposed_finalizer_policy().apply_diff(*if_ext.new_finalizer_policy_diff); diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index e287e4f8f3..b301981054 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -74,6 +74,7 @@ block_state_ptr block_state::create_if_genesis_block(const block_state_legacy& b instant_finality_extension if_ext = bsp.block->extract_header_extension(); assert(if_ext.new_finalizer_policy_diff); // required by transition mechanism result.active_finalizer_policy = std::make_shared(finalizer_policy{}.apply_diff(std::move(*if_ext.new_finalizer_policy_diff))); + result.last_pending_finalizer_policy_digest = fc::sha256::hash(*result.active_finalizer_policy); result.active_proposer_policy = std::make_shared(); result.active_proposer_policy->active_time = bsp.timestamp(); result.active_proposer_policy->proposer_schedule = bsp.active_schedule; diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index e6c6c6fb6e..3a41665b4b 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -95,6 +95,10 @@ struct block_header_state { // It matches the finalizer policy generation most recently included in this block's `if_extension` or its ancestors uint32_t finalizer_policy_generation{1}; + // digest of the finalizer policy (which includes the generation number in it) with the greatest generation number + // in the history of the blockchain so far that is not in proposed state (so either pending or active state) + digest_type last_pending_finalizer_policy_digest; + // ------ data members caching information available elsewhere ---------------------- header_extension_multimap header_exts; // redundant with the data stored in header @@ -131,6 +135,7 @@ struct block_header_state { const producer_authority& get_scheduled_producer(block_timestamp_type t) const; const finalizer_policy& get_last_proposed_finalizer_policy() const; + const finalizer_policy& get_last_pending_finalizer_policy() const; const proposer_policy& get_last_proposed_proposer_policy() const; }; @@ -145,6 +150,6 @@ FC_REFLECT( eosio::chain::finalizer_policy_tracker, (state)(policy)) FC_REFLECT( eosio::chain::block_header_state, (block_id)(header) (activated_protocol_features)(core)(active_finalizer_policy) (active_proposer_policy)(proposer_policies)(finalizer_policies) - (finalizer_policy_generation)(header_exts)) + (finalizer_policy_generation)(last_pending_finalizer_policy_digest)(header_exts)) FC_REFLECT( eosio::chain::finality_digest_data_v1, (major_version)(minor_version)(active_finalizer_policy_generation)(finality_tree_digest)(active_finalizer_policy_and_base_digest) ) diff --git a/unittests/svnn_ibc_tests.cpp b/unittests/svnn_ibc_tests.cpp index 477c945d33..68248f1787 100644 --- a/unittests/svnn_ibc_tests.cpp +++ b/unittests/svnn_ibc_tests.cpp @@ -108,8 +108,8 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc) BOOST_CHECK_EQUAL(active_finalizer_policy.generation, 1u); - // compute the digest of the finalizer policy - auto active_finalizer_policy_digest = fc::sha256::hash(active_finalizer_policy); + // compute the digest of the last_pending_finalizer_policy_digest which is active at this point + auto last_pending_finalizer_policy_digest = fc::sha256::hash(active_finalizer_policy); auto genesis_block_fd = cluster.node0.control->head_finality_data(); @@ -118,7 +118,7 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc) // compute IF finality leaf auto genesis_base_digest = genesis_block_fd.value().base_digest; - auto genesis_afp_base_digest = hash_pair(active_finalizer_policy_digest, genesis_base_digest); + auto genesis_afp_base_digest = hash_pair(last_pending_finalizer_policy_digest, genesis_base_digest); auto genesis_block_finality_digest = fc::sha256::hash(eosio::chain::finality_digest_data_v1{ .active_finalizer_policy_generation = active_finalizer_policy.generation, @@ -171,7 +171,7 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc) auto block_2_action_mroot = block_2_fd.value().action_mroot; auto block_2_base_digest = block_2_fd.value().base_digest; auto block_2_finality_digest = cluster.node0.control->get_strong_digest_by_id(block_2->calculate_id()); - auto block_2_afp_base_digest = hash_pair(active_finalizer_policy_digest, block_2_base_digest); + auto block_2_afp_base_digest = hash_pair(last_pending_finalizer_policy_digest, block_2_base_digest); auto block_2_leaf = fc::sha256::hash(valid_t::finality_leaf_node_t{ .block_num = block_2->block_num(), .finality_digest = block_2_finality_digest, @@ -196,7 +196,7 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc) cluster.process_votes(1, cluster.num_needed_for_quorum); auto block_4_fd = cluster.node0.control->head_finality_data(); auto block_4_base_digest = block_4_fd.value().base_digest; - auto block_4_afp_base_digest = hash_pair(active_finalizer_policy_digest, block_4_base_digest); + auto block_4_afp_base_digest = hash_pair(last_pending_finalizer_policy_digest, block_4_base_digest); auto block_4_finality_root = block_4->action_mroot; qc_data_t qc_b_4 = extract_qc_data(block_4); @@ -209,7 +209,7 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc) cluster.process_votes(1, cluster.num_needed_for_quorum); auto block_5_fd = cluster.node0.control->head_finality_data(); auto block_5_base_digest = block_5_fd.value().base_digest; - auto block_5_afp_base_digest = hash_pair(active_finalizer_policy_digest, block_5_base_digest); + auto block_5_afp_base_digest = hash_pair(last_pending_finalizer_policy_digest, block_5_base_digest); auto block_5_finality_root = block_5->action_mroot; // retrieve the QC over block_4 that is contained in block_5 From f9b7badd2a894675e4f86f8817f45a025a4f992a Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 13 May 2024 08:43:06 -0500 Subject: [PATCH 2/6] GH-128 Add last_pending_finalizer_policy_digest to snapshot --- libraries/chain/include/eosio/chain/snapshot_detail.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/chain/include/eosio/chain/snapshot_detail.hpp b/libraries/chain/include/eosio/chain/snapshot_detail.hpp index 58e760d03d..3d27f918b6 100644 --- a/libraries/chain/include/eosio/chain/snapshot_detail.hpp +++ b/libraries/chain/include/eosio/chain/snapshot_detail.hpp @@ -119,6 +119,7 @@ namespace eosio::chain::snapshot_detail { flat_map proposer_policies; flat_multimap finalizer_policies; uint32_t finalizer_policy_generation; + digest_type last_pending_finalizer_policy_digest; // from block_state std::optional valid; @@ -135,6 +136,7 @@ namespace eosio::chain::snapshot_detail { , proposer_policies(bs.proposer_policies) , finalizer_policies(bs.finalizer_policies) , finalizer_policy_generation(bs.finalizer_policy_generation) + , last_pending_finalizer_policy_digest(bs.last_pending_finalizer_policy_digest) , valid(bs.valid) {} }; @@ -215,6 +217,7 @@ FC_REFLECT( eosio::chain::snapshot_detail::snapshot_block_state_v7, (proposer_policies) (finalizer_policies) (finalizer_policy_generation) + (last_pending_finalizer_policy_digest) (valid) ) From f29e7f1a5f7e6e98b9e74c88a77a028a695e2d09 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 13 May 2024 09:02:43 -0500 Subject: [PATCH 3/6] GH-128 Rename --- libraries/chain/block_header_state.cpp | 6 +++--- libraries/chain/include/eosio/chain/block_header_state.hpp | 4 ++-- unittests/svnn_ibc_tests.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index d6cac55174..6b65b5fbbd 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -44,14 +44,14 @@ digest_type block_header_state::compute_base_digest() const { digest_type block_header_state::compute_finality_digest() const { auto base_digest = compute_base_digest(); - std::pair active_and_base{ last_pending_finalizer_policy_digest, base_digest }; - auto afp_base_digest = fc::sha256::hash(active_and_base); + std::pair last_pending_and_base{ last_pending_finalizer_policy_digest, base_digest }; + auto lpfp_base_digest = fc::sha256::hash(last_pending_and_base); assert(active_finalizer_policy); finality_digest_data_v1 finality_digest_data { .active_finalizer_policy_generation = active_finalizer_policy->generation, .finality_tree_digest = finality_mroot(), - .active_finalizer_policy_and_base_digest = afp_base_digest + .last_pending_finalizer_policy_and_base_digest = lpfp_base_digest }; return fc::sha256::hash(finality_digest_data); diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index 3a41665b4b..93e5f14383 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -26,7 +26,7 @@ struct finality_digest_data_v1 { uint32_t minor_version{light_header_protocol_version_minor}; uint32_t active_finalizer_policy_generation {0}; digest_type finality_tree_digest; - digest_type active_finalizer_policy_and_base_digest; + digest_type last_pending_finalizer_policy_and_base_digest; }; @@ -152,4 +152,4 @@ FC_REFLECT( eosio::chain::block_header_state, (block_id)(header) (active_proposer_policy)(proposer_policies)(finalizer_policies) (finalizer_policy_generation)(last_pending_finalizer_policy_digest)(header_exts)) -FC_REFLECT( eosio::chain::finality_digest_data_v1, (major_version)(minor_version)(active_finalizer_policy_generation)(finality_tree_digest)(active_finalizer_policy_and_base_digest) ) +FC_REFLECT( eosio::chain::finality_digest_data_v1, (major_version)(minor_version)(active_finalizer_policy_generation)(finality_tree_digest)(last_pending_finalizer_policy_and_base_digest) ) diff --git a/unittests/svnn_ibc_tests.cpp b/unittests/svnn_ibc_tests.cpp index 68248f1787..e6cb492c50 100644 --- a/unittests/svnn_ibc_tests.cpp +++ b/unittests/svnn_ibc_tests.cpp @@ -123,7 +123,7 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc) auto genesis_block_finality_digest = fc::sha256::hash(eosio::chain::finality_digest_data_v1{ .active_finalizer_policy_generation = active_finalizer_policy.generation, .finality_tree_digest = digest_type(), //nothing to finalize yet - .active_finalizer_policy_and_base_digest = genesis_afp_base_digest + .last_pending_finalizer_policy_and_base_digest = genesis_afp_base_digest }); // action_mroot computed using the post-IF activation merkle tree rules From 3f33cc906cb33d351cbc3756491244eba79208e9 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 13 May 2024 09:50:58 -0500 Subject: [PATCH 4/6] GH-128 Add last_pending_finalizer_policy_digest to constructor for snapshot --- libraries/chain/block_state.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index b301981054..a665cebf90 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -145,7 +145,8 @@ block_state::block_state(snapshot_detail::snapshot_block_state_v7&& sbs) .active_proposer_policy = std::move(sbs.active_proposer_policy), .proposer_policies = std::move(sbs.proposer_policies), .finalizer_policies = std::move(sbs.finalizer_policies), - .finalizer_policy_generation = sbs.finalizer_policy_generation + .finalizer_policy_generation = sbs.finalizer_policy_generation, + .last_pending_finalizer_policy_digest = sbs.last_pending_finalizer_policy_digest } , strong_digest(compute_finality_digest()) , weak_digest(create_weak_digest(strong_digest)) From 70b8fb9e05ad8ca3c2e64f24c4c5d5cd9dc5c53f Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 13 May 2024 10:39:33 -0500 Subject: [PATCH 5/6] GH-128 Add comment --- libraries/chain/include/eosio/chain/snapshot_detail.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/chain/include/eosio/chain/snapshot_detail.hpp b/libraries/chain/include/eosio/chain/snapshot_detail.hpp index 3d27f918b6..8deffe4311 100644 --- a/libraries/chain/include/eosio/chain/snapshot_detail.hpp +++ b/libraries/chain/include/eosio/chain/snapshot_detail.hpp @@ -126,6 +126,7 @@ namespace eosio::chain::snapshot_detail { snapshot_block_state_v7() = default; + // When adding a member initialization here also update block_state(snapshot_block_state_v7) constructor explicit snapshot_block_state_v7(const block_state& bs) : block_id(bs.block_id) , header(bs.header) From dce135cd9ad794580cd8e9d3cf28c7fcae4c3c99 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 14 May 2024 07:11:44 -0500 Subject: [PATCH 6/6] GH-128 Add comment --- libraries/chain/block_header_state.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 6b65b5fbbd..b94c694168 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -81,6 +81,7 @@ const finalizer_policy& block_header_state::get_last_proposed_finalizer_policy() // Used to populate last_pending_finalizer_policy_digest which is expected to be the highest generation pending const finalizer_policy& block_header_state::get_last_pending_finalizer_policy() const { if (!finalizer_policies.empty()) { + // lambda only used when asserts enabled [[maybe_unused]] auto highest_pending_generation = [this]() { finalizer_policy_ptr highest; for (auto ritr = finalizer_policies.rbegin(); ritr != finalizer_policies.rend(); ++ritr) {