From 6505e0c8b8d3301eed4b585d3a4da3425bde1789 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 29 Apr 2024 18:41:39 -0500 Subject: [PATCH 01/19] Gh-5 Add ordered_diff --- .../include/fc/container/ordered_diff.hpp | 99 +++++++++++++ libraries/libfc/test/CMakeLists.txt | 1 + libraries/libfc/test/test_ordered_diff.cpp | 130 ++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 libraries/libfc/include/fc/container/ordered_diff.hpp create mode 100644 libraries/libfc/test/test_ordered_diff.cpp diff --git a/libraries/libfc/include/fc/container/ordered_diff.hpp b/libraries/libfc/include/fc/container/ordered_diff.hpp new file mode 100644 index 0000000000..cae14fc322 --- /dev/null +++ b/libraries/libfc/include/fc/container/ordered_diff.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include +#include + +namespace fc { + +/** + * @class ordered_diff + * @brief Provides ablity to generate and apply diff of containers of type T + * + * Example use: + * std::vector source = { 'a', 'b', 'f', 'c', 'd' }; + * std::vector target = { 'b', 'f', 'c', 'd', 'e', 'h' }; + * ordered_diff::diff_result diff = ordered_diff::diff(source, target); + * ordered_diff::apply_diff(source, std::move(diff)); + * assert(source == target); + * + * @param T type stored in Container, must provide == + */ +template typename Container = std::vector> +requires std::equality_comparable && std::random_access_iterator::iterator> +class ordered_diff { +public: + struct diff_result { + Container remove_indexes; + Container> insert_indexes; + }; + + /// Generate diff_result that when `apply_diff(source, diff_result)` to source will generate target + static diff_result diff(const Container& source, const Container& target) { + size_t s = 0; + size_t t = 0; + + diff_result result; + while (s < source.size() || t < target.size()) { + if (s < source.size() && t < target.size()) { + if (source[s] == target[t]) { + // nothing to do, skip over + ++s; + ++t; + } else { // not equal + if (s == source.size() - 1 && t == target.size() - 1) { + // both at end, insert target and remove source + result.remove_indexes.push_back(s); + result.insert_indexes.emplace_back(t, target[t]); + ++s; + ++t; + } else if (s + 1 < source.size() && t + 1 < target.size() && source[s + 1] == target[t + 1]) { + // misalignment, but next value equal, insert and remove + result.remove_indexes.push_back(s); + result.insert_indexes.emplace_back(t, target[t]); + ++s; + ++t; + } else if (t + 1 < target.size() && source[s] == target[t + 1]) { + // source equals next target, insert current target + result.insert_indexes.emplace_back(t, target[t]); + ++t; + } else { // source[s + 1] == target[t] + // target matches next source, remove current source + result.remove_indexes.push_back(s); + ++s; + } + } + } else if (s < source.size()) { + // remove extra in source + result.remove_indexes.push_back(s); + ++s; + } else if (t < target.size()) { + // insert extra in target + result.insert_indexes.emplace_back(t, target[t]); + ++t; + } + } + + return result; + } + + template + requires std::same_as, diff_result> + static void apply_diff(Container& source, X&& diff) { + // Remove from the source based on diff.remove_indexes + std::ptrdiff_t offset = 0; + for (size_t index : diff.remove_indexes) { + source.erase(source.begin() + index + offset); + --offset; + } + + // Insert into the source based on diff.insert_indexes + for (auto& t : diff.insert_indexes) { + size_t index = std::get<0>(t); + auto& value = std::get<1>(t); + source.insert(source.begin() + index, std::move(value)); + } + } + +}; // class ordered_diff + +} // namespace fc diff --git a/libraries/libfc/test/CMakeLists.txt b/libraries/libfc/test/CMakeLists.txt index 4b079be425..ee728d2f13 100644 --- a/libraries/libfc/test/CMakeLists.txt +++ b/libraries/libfc/test/CMakeLists.txt @@ -19,6 +19,7 @@ add_executable( test_fc test_base64.cpp test_escape_str.cpp test_bls.cpp + test_ordered_diff.cpp main.cpp ) target_link_libraries( test_fc fc ) diff --git a/libraries/libfc/test/test_ordered_diff.cpp b/libraries/libfc/test/test_ordered_diff.cpp new file mode 100644 index 0000000000..4cf05792b1 --- /dev/null +++ b/libraries/libfc/test/test_ordered_diff.cpp @@ -0,0 +1,130 @@ +#include + +#include +#include + +using namespace fc; + +BOOST_AUTO_TEST_SUITE(ordered_diff_tests) + +BOOST_AUTO_TEST_CASE(ordered_diff_test) try { + using namespace std; + + { // Basic case + vector source = {'a', 'b', 'c', 'd', 'e'}; + vector target = {'a', 'c', 'e', 'f'}; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } + { // Basic case, deque + using ordered_deque_char_diff = ordered_diff; + deque source = {'a', 'x', 'c', 'd', 'e'}; + deque target = {'z', 'c', 'y', 'f'}; + auto result = ordered_deque_char_diff::diff(source, target); + ordered_deque_char_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } + { // Empty vectors + vector source; + vector target; + ordered_diff::diff_result result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } + { // All elements removed + vector source = {'a', 'b', 'c', 'd', 'e'}; + vector target; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } + { // All elements inserted + vector source; + vector target = {'a', 'b', 'c', 'd', 'e'}; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } + { // Mix of removals and inserts + vector source = {'a', 'b', 'c', 'd', 'e'}; + vector target = {'a', 'c', 'e', 'f', 'g', 'h'}; + ordered_diff::diff_result result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } + { // Mix of removals and inserts + vector source = {1, 2, 3, 4, 5}; + vector target = {3, 4, 6, 2, 0}; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } + { // Complete change + vector source = {'a', 'b', 'c', 'd', 'e'}; + vector target = {'f', 'g', 'h', 'i'}; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } + { // Diff order + vector source = {'a', 'b', 'c', 'd', 'e'}; + vector target = {'e', 'd', 'c', 'b', 'a'}; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(ordered_diff_string_test) try { + using namespace std; + { + vector source = {"hello", "how", "are", "you", "today"}; + vector target = {"hi", "are", "you", "here"}; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } + { + vector source = {"prod1", "prod2", "prod3", "prod4", "prod5"}; + vector target = {"prod2", "prod1", "prod3", "prod4", "prod5"};; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } + { + vector source = {"prod1", "prod2", "prod3", "prod4", "prod5"}; + vector target = {"prod5", "prod1", "prod2", "prod3", "prod4"};; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, std::move(result)); + BOOST_TEST(source == target); + } + +} FC_LOG_AND_RETHROW(); + +class count_moves { + std::string s; +public: + inline static size_t num_moves = 0; + count_moves(const count_moves& m) : s(m.s) {}; + count_moves(count_moves&& m) noexcept : s(std::move(m.s)) { ++num_moves; }; + count_moves& operator=(const count_moves& rhs) = default; + explicit count_moves(std::string s) : s(s) {}; + auto operator<=>(const count_moves&) const = default; + bool operator==(const count_moves&) const = default; +}; + +BOOST_AUTO_TEST_CASE(ordered_diff_moveable_test) try { + using namespace std; + { + vector source = {count_moves{"hello"}, count_moves{"there"}}; + vector target = {count_moves{"hi"}, count_moves{"there"}}; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, std::move(result)); + BOOST_TEST(source == target); + BOOST_TEST(count_moves::num_moves == 1); + } + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file From 7f4879ebcaea616dffe18a3243027b17407789ba Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 7 May 2024 14:32:08 -0500 Subject: [PATCH 02/19] GH-5 Add some additional tests cases --- libraries/libfc/test/test_ordered_diff.cpp | 32 ++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/libraries/libfc/test/test_ordered_diff.cpp b/libraries/libfc/test/test_ordered_diff.cpp index 4cf05792b1..2ec54b1650 100644 --- a/libraries/libfc/test/test_ordered_diff.cpp +++ b/libraries/libfc/test/test_ordered_diff.cpp @@ -46,6 +46,13 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { ordered_diff::apply_diff(source, result); BOOST_TEST(source == target); } + { // No change + vector source = {'a', 'b', 'c', 'd', 'e'}; + vector target = source; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } { // Mix of removals and inserts vector source = {'a', 'b', 'c', 'd', 'e'}; vector target = {'a', 'c', 'e', 'f', 'g', 'h'}; @@ -74,6 +81,20 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { ordered_diff::apply_diff(source, result); BOOST_TEST(source == target); } + { // shift left + vector source = {'a', 'b', 'c', 'd', 'e'}; + vector target = {'b', 'c', 'd', 'e', 'f'}; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } + { // shift right + vector source = {'a', 'b', 'c', 'd', 'e'}; + vector target = {'z', 'a', 'b', 'c', 'd'}; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } } FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_CASE(ordered_diff_string_test) try { @@ -87,14 +108,21 @@ BOOST_AUTO_TEST_CASE(ordered_diff_string_test) try { } { vector source = {"prod1", "prod2", "prod3", "prod4", "prod5"}; - vector target = {"prod2", "prod1", "prod3", "prod4", "prod5"};; + vector target = {"prod2", "prod1", "prod3", "prod4", "prod5"}; auto result = ordered_diff::diff(source, target); ordered_diff::apply_diff(source, result); BOOST_TEST(source == target); } { vector source = {"prod1", "prod2", "prod3", "prod4", "prod5"}; - vector target = {"prod5", "prod1", "prod2", "prod3", "prod4"};; + vector target = {"prod5", "prod1", "prod2", "prod3", "prod4"}; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, std::move(result)); + BOOST_TEST(source == target); + } + { + vector source = {"prod1", "prod2", "prod3", "prod4", "prod5"}; + vector target = {"prod2", "prod3", "prod4", "prod5", "prod6"}; auto result = ordered_diff::diff(source, target); ordered_diff::apply_diff(source, std::move(result)); BOOST_TEST(source == target); From 1403867d9a10fcf10d20501fc3417193a21ac799 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 7 May 2024 14:33:21 -0500 Subject: [PATCH 03/19] GH-5 FC pack supports pair not tuple --- libraries/libfc/include/fc/container/ordered_diff.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libfc/include/fc/container/ordered_diff.hpp b/libraries/libfc/include/fc/container/ordered_diff.hpp index cae14fc322..ed6523d9e8 100644 --- a/libraries/libfc/include/fc/container/ordered_diff.hpp +++ b/libraries/libfc/include/fc/container/ordered_diff.hpp @@ -24,7 +24,7 @@ class ordered_diff { public: struct diff_result { Container remove_indexes; - Container> insert_indexes; + Container> insert_indexes; }; /// Generate diff_result that when `apply_diff(source, diff_result)` to source will generate target From ac49b89d3efb5b5d17f331097b7abaff8f555e7e Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 7 May 2024 14:35:42 -0500 Subject: [PATCH 04/19] GH-5 Provide a diff of finalizers in instant_finality_extension instead of a full list of finalizers --- libraries/chain/block_header_state.cpp | 22 +++++++------ libraries/chain/block_header_state_legacy.cpp | 4 ++- libraries/chain/block_state.cpp | 5 +-- .../eosio/chain/block_header_state.hpp | 24 ++++++++++++-- .../eosio/chain/finality/finalizer_policy.hpp | 29 ++++++++++++++++- .../finality/instant_finality_extension.hpp | 12 +++---- unittests/api_tests.cpp | 18 +++++------ unittests/block_header_tests.cpp | 32 ++++++++----------- unittests/finality_test_cluster.cpp | 8 ++--- unittests/finalizer_update_tests.cpp | 29 ++++++++++++++--- unittests/protocol_feature_tests.cpp | 6 ++-- unittests/svnn_ibc_tests.cpp | 8 ++--- unittests/vote_processor_tests.cpp | 7 ++-- 13 files changed, 136 insertions(+), 68 deletions(-) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index e0f17e9a4a..e89b9adc32 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -22,8 +22,7 @@ digest_type block_header_state::compute_base_digest() const { fc::raw::pack( enc, fp_pair.first ); const finalizer_policy_tracker& tracker = fp_pair.second; fc::raw::pack( enc, tracker.state ); - assert(tracker.policy); - fc::raw::pack( enc, *tracker.policy ); + fc::raw::pack( enc, tracker.policy_diff ); } assert(active_proposer_policy); @@ -136,13 +135,14 @@ void finish_next(const block_header_state& prev, if (tracker.state == finalizer_policy_tracker::state_t::pending) { // new finalizer_policy becones active // ----------------------------------- - next_header_state.active_finalizer_policy.reset(new finalizer_policy(*tracker.policy)); + next_header_state.active_finalizer_policy.reset(new finalizer_policy(*prev.active_finalizer_policy)); + next_header_state.active_finalizer_policy->apply_diff(tracker.policy_diff); } else { assert(tracker.state == finalizer_policy_tracker::state_t::proposed); // block where finalizer_policy was proposed became final. The finalizer policy will // become active when next block becomes final. // --------------------------------------------------------------------------------- - finalizer_policy_tracker t { finalizer_policy_tracker::state_t::pending, tracker.policy }; + finalizer_policy_tracker t { finalizer_policy_tracker::state_t::pending, tracker.policy_diff }; next_header_state.finalizer_policies.emplace(next_header_state.block_num(), std::move(t)); } ++it; @@ -156,19 +156,19 @@ void finish_next(const block_header_state& prev, } } - if (if_ext.new_finalizer_policy) { + if (if_ext.new_finalizer_policy_diff) { // a new `finalizer_policy` was proposed in the previous block, and is present in the previous // block's header extensions. // Add this new proposal to the `finalizer_policies` multimap which tracks the in-flight proposals, // increment the generation number, and log that proposal (debug level). // ------------------------------------------------------------------------------------------------ dlog("New finalizer policy proposed in block ${id}: ${pol}", - ("id", prev.block_id)("pol", *if_ext.new_finalizer_policy)); - next_header_state.finalizer_policy_generation = if_ext.new_finalizer_policy->generation; + ("id", prev.block_id)("pol", *if_ext.new_finalizer_policy_diff)); + next_header_state.finalizer_policy_generation = if_ext.new_finalizer_policy_diff->generation; next_header_state.finalizer_policies.emplace( next_header_state.block_num(), finalizer_policy_tracker{finalizer_policy_tracker::state_t::proposed, - std::make_shared(std::move(*if_ext.new_finalizer_policy))}); + std::move(*if_ext.new_finalizer_policy_diff)}); } else { next_header_state.finalizer_policy_generation = prev.finalizer_policy_generation; @@ -205,8 +205,12 @@ block_header_state block_header_state::next(block_header_state_input& input) con // finality extension // ------------------ + std::optional new_finalizer_policy_diff; + if (input.new_finalizer_policy) { + new_finalizer_policy_diff = calculate_finalizer_policy_diff(*input.new_finalizer_policy); + } instant_finality_extension new_if_ext { input.most_recent_ancestor_with_qc, - std::move(input.new_finalizer_policy), + std::move(new_finalizer_policy_diff), std::move(input.new_proposer_policy) }; uint16_t if_ext_id = instant_finality_extension::extension_id(); diff --git a/libraries/chain/block_header_state_legacy.cpp b/libraries/chain/block_header_state_legacy.cpp index a47ca2282f..01cbe4113e 100644 --- a/libraries/chain/block_header_state_legacy.cpp +++ b/libraries/chain/block_header_state_legacy.cpp @@ -220,8 +220,10 @@ namespace eosio::chain { // set current block_num as qc_claim.last_qc_block_num in the IF extension qc_claim_t initial_if_claim { .block_num = block_num, .is_strong_qc = false }; + finalizer_policy no_policy; + auto new_fin_policy_diff = no_policy.create_diff(*new_finalizer_policy); emplace_extension(h.header_extensions, instant_finality_extension::extension_id(), - fc::raw::pack(instant_finality_extension{ initial_if_claim, std::move(new_finalizer_policy), {} })); + fc::raw::pack(instant_finality_extension{ initial_if_claim, std::move(new_fin_policy_diff), {} })); } else if (qc_claim) { emplace_extension(h.header_extensions, instant_finality_extension::extension_id(), fc::raw::pack(instant_finality_extension{ *qc_claim, {}, {} })); diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index 5d84d2f60a..690ba7408c 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -72,8 +72,9 @@ block_state_ptr block_state::create_if_genesis_block(const block_state_legacy& b assert(bsp.block->contains_header_extension(instant_finality_extension::extension_id())); // required by transition mechanism instant_finality_extension if_ext = bsp.block->extract_header_extension(); - assert(if_ext.new_finalizer_policy); // required by transition mechanism - result.active_finalizer_policy = std::make_shared(*if_ext.new_finalizer_policy); + assert(if_ext.new_finalizer_policy_diff); // required by transition mechanism + result.active_finalizer_policy = std::make_shared(); + result.active_finalizer_policy->apply_diff(std::move(*if_ext.new_finalizer_policy_diff)); 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 7fd43afe32..cd89d3338b 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -46,8 +46,8 @@ struct finality_digest_data_v1 { // ------------------------------------------------------------------------------------------ struct finalizer_policy_tracker { enum class state_t { proposed = 0, pending }; - state_t state; - finalizer_policy_ptr policy; + state_t state; + finalizer_policy_diff policy_diff; }; struct building_block_input { @@ -129,6 +129,24 @@ struct block_header_state { const vector& get_new_protocol_feature_activations() const; const producer_authority& get_scheduled_producer(block_timestamp_type t) const; + + finalizer_policy_diff calculate_finalizer_policy_diff(const finalizer_policy& new_policy) const { + if (finalizer_policies.empty()) { + return active_finalizer_policy->create_diff(new_policy); + } + finalizer_policy_ptr fin_policy_ptr = std::make_shared(*active_finalizer_policy); + for (const auto& e : finalizer_policies) { + if (e.second.state == finalizer_policy_tracker::state_t::pending) { + fin_policy_ptr->apply_diff(e.second.policy_diff); + } + } + for (const auto& e : finalizer_policies) { + if (e.second.state == finalizer_policy_tracker::state_t::proposed) { + fin_policy_ptr->apply_diff(e.second.policy_diff); + } + } + return fin_policy_ptr->create_diff(new_policy); + } }; using block_header_state_ptr = std::shared_ptr; @@ -137,7 +155,7 @@ using block_header_state_ptr = std::shared_ptr; FC_REFLECT_ENUM( eosio::chain::finalizer_policy_tracker::state_t, (proposed)(pending)) -FC_REFLECT( eosio::chain::finalizer_policy_tracker, (state)(policy)) +FC_REFLECT( eosio::chain::finalizer_policy_tracker, (state)(policy_diff)) FC_REFLECT( eosio::chain::block_header_state, (block_id)(header) (activated_protocol_features)(core)(active_finalizer_policy) diff --git a/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp b/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp index 1fa27d14ac..64089fa950 100644 --- a/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp +++ b/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp @@ -2,13 +2,37 @@ #include #include +#include namespace eosio::chain { + using finalizers_differ = fc::ordered_diff; + using finalizers_diff_t = fc::ordered_diff::diff_result; + + struct finalizer_policy_diff { + uint32_t generation = 0; ///< sequentially incrementing version number + uint64_t threshold = 0; ///< vote weight threshold to finalize blocks + finalizers_diff_t finalizers_diff; + }; + struct finalizer_policy { uint32_t generation = 0; ///< sequentially incrementing version number uint64_t threshold = 0; ///< vote weight threshold to finalize blocks - std::vector finalizers; ///< Instant Finality voter set + std::vector finalizers; ///< Instant Finality voter set + + finalizer_policy_diff create_diff(const finalizer_policy& target) const { + return {.generation = target.generation, + .threshold = target.threshold, + .finalizers_diff = finalizers_differ::diff(finalizers, target.finalizers)}; + } + + template + requires std::same_as, finalizer_policy_diff> + void apply_diff(X&& diff) { + generation = diff.generation; + threshold = diff.threshold; + finalizers_differ::apply_diff(finalizers, std::move(diff.finalizers_diff)); + } // max accumulated weak weight before becoming weak_final uint64_t max_weak_sum_before_weak_final() const { @@ -23,7 +47,10 @@ namespace eosio::chain { }; using finalizer_policy_ptr = std::shared_ptr; + using finalizer_policy_diff_ptr = std::shared_ptr; } /// eosio::chain FC_REFLECT( eosio::chain::finalizer_policy, (generation)(threshold)(finalizers) ) +FC_REFLECT( eosio::chain::finalizers_diff_t, (remove_indexes)(insert_indexes) ) +FC_REFLECT( eosio::chain::finalizer_policy_diff, (generation)(threshold)(finalizers_diff) ) diff --git a/libraries/chain/include/eosio/chain/finality/instant_finality_extension.hpp b/libraries/chain/include/eosio/chain/finality/instant_finality_extension.hpp index 3b78770a5b..ff2cb53e82 100644 --- a/libraries/chain/include/eosio/chain/finality/instant_finality_extension.hpp +++ b/libraries/chain/include/eosio/chain/finality/instant_finality_extension.hpp @@ -12,10 +12,10 @@ struct instant_finality_extension : fc::reflect_init { instant_finality_extension() = default; instant_finality_extension(qc_claim_t qc_claim, - std::optional new_finalizer_policy, + std::optional new_finalizer_policy_diff, std::shared_ptr new_proposer_policy) : qc_claim(qc_claim), - new_finalizer_policy(std::move(new_finalizer_policy)), + new_finalizer_policy_diff(std::move(new_finalizer_policy_diff)), new_proposer_policy(std::move(new_proposer_policy)) {} @@ -25,11 +25,11 @@ struct instant_finality_extension : fc::reflect_init { static_assert( extension_id() == 2, "instant_finality_extension extension id must be 2" ); } - qc_claim_t qc_claim; - std::optional new_finalizer_policy; - std::shared_ptr new_proposer_policy; + qc_claim_t qc_claim; + std::optional new_finalizer_policy_diff; + std::shared_ptr new_proposer_policy; }; } /// eosio::chain -FC_REFLECT( eosio::chain::instant_finality_extension, (qc_claim)(new_finalizer_policy)(new_proposer_policy) ) +FC_REFLECT( eosio::chain::instant_finality_extension, (qc_claim)(new_finalizer_policy_diff)(new_proposer_policy) ) diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index c344f4d0a9..0796d4333f 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -3890,11 +3890,11 @@ BOOST_AUTO_TEST_CASE(initial_set_finalizer_test) { try { std::optional ext = block->extract_header_extension(instant_finality_extension::extension_id()); BOOST_TEST(!!ext); - std::optional fin_policy = std::get(*ext).new_finalizer_policy; - BOOST_TEST(!!fin_policy); - BOOST_TEST(fin_policy->finalizers.size() == finalizers.size()); - BOOST_TEST(fin_policy->generation == 1); - BOOST_TEST(fin_policy->threshold == finalizers.size() / 3 * 2 + 1); + std::optional fin_policy_diff = std::get(*ext).new_finalizer_policy_diff; + BOOST_TEST(!!fin_policy_diff); + BOOST_TEST(fin_policy_diff->finalizers_diff.insert_indexes.size() == finalizers.size()); + BOOST_TEST(fin_policy_diff->generation == 1); + BOOST_TEST(fin_policy_diff->threshold == finalizers.size() / 3 * 2 + 1); block_id_type if_genesis_block_id = block->calculate_id(); for (block_num_type active_block_num = block->block_num(); active_block_num > lib; t.produce_block()) { @@ -3943,10 +3943,10 @@ void test_finality_transition(const vector& accounts, const base_t std::optional ext = block->extract_header_extension(instant_finality_extension::extension_id()); BOOST_TEST(!!ext); - std::optional fin_policy = std::get(*ext).new_finalizer_policy; - BOOST_TEST(!!fin_policy); - BOOST_TEST(fin_policy->finalizers.size() == accounts.size()); - BOOST_TEST(fin_policy->generation == 1); + std::optional fin_policy_diff = std::get(*ext).new_finalizer_policy_diff; + BOOST_TEST(!!fin_policy_diff); + BOOST_TEST(fin_policy_diff->finalizers_diff.insert_indexes.size() == accounts.size()); + BOOST_TEST(fin_policy_diff->generation == 1); block_id_type if_genesis_block_id = block->calculate_id(); block_num_type active_block_num = block->block_num(); diff --git a/unittests/block_header_tests.cpp b/unittests/block_header_tests.cpp index 22b68345c9..67fdd24a8e 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) header.header_extensions, instant_finality_extension::extension_id(), fc::raw::pack( instant_finality_extension{qc_claim_t{last_qc_block_num, is_last_strong_qc}, - std::optional{}, std::shared_ptr{}} ) + std::optional{}, std::shared_ptr{}} ) ); std::optional ext = header.extract_header_extension(instant_finality_extension::extension_id()); @@ -33,7 +33,7 @@ BOOST_AUTO_TEST_CASE(instant_finality_extension_with_empty_values_test) const auto& if_extension = std::get(*ext); BOOST_REQUIRE_EQUAL( if_extension.qc_claim.block_num, last_qc_block_num ); BOOST_REQUIRE_EQUAL( if_extension.qc_claim.is_strong_qc, is_last_strong_qc ); - BOOST_REQUIRE( !if_extension.new_finalizer_policy ); + BOOST_REQUIRE( !if_extension.new_finalizer_policy_diff ); BOOST_REQUIRE( !if_extension.new_proposer_policy ); } @@ -50,17 +50,15 @@ BOOST_AUTO_TEST_CASE(instant_finality_extension_uniqueness_test) ); std::vector finalizers { {"test description", 50, fc::crypto::blslib::bls_public_key{"PUB_BLS_qVbh4IjYZpRGo8U_0spBUM-u-r_G0fMo4MzLZRsKWmm5uyeQTp74YFaMN9IDWPoVVT5rj_Tw1gvps6K9_OZ6sabkJJzug3uGfjA6qiaLbLh5Fnafwv-nVgzzzBlU2kwRrcHc8Q" }} }; - finalizer_policy new_finalizer_policy; - new_finalizer_policy.generation = 1; - new_finalizer_policy.threshold = 100; - new_finalizer_policy.finalizers = finalizers; + auto fin_policy = std::make_shared(); + finalizer_policy_diff new_finalizer_policy_diff = fin_policy->create_diff(finalizer_policy{.generation = 1, .threshold = 100, .finalizers = finalizers}); proposer_policy_ptr new_proposer_policy = std::make_shared(1, block_timestamp_type{200}, producer_authority_schedule{} ); emplace_extension( header.header_extensions, instant_finality_extension::extension_id(), - fc::raw::pack( instant_finality_extension{qc_claim_t{100, true}, new_finalizer_policy, new_proposer_policy} ) + fc::raw::pack( instant_finality_extension{qc_claim_t{100, true}, new_finalizer_policy_diff, new_proposer_policy} ) ); BOOST_CHECK_THROW(header.validate_and_extract_header_extensions(), invalid_block_header_extension); @@ -74,17 +72,15 @@ BOOST_AUTO_TEST_CASE(instant_finality_extension_with_values_test) constexpr bool is_strong_qc {true}; std::vector finalizers { {"test description", 50, fc::crypto::blslib::bls_public_key{"PUB_BLS_qVbh4IjYZpRGo8U_0spBUM-u-r_G0fMo4MzLZRsKWmm5uyeQTp74YFaMN9IDWPoVVT5rj_Tw1gvps6K9_OZ6sabkJJzug3uGfjA6qiaLbLh5Fnafwv-nVgzzzBlU2kwRrcHc8Q" }} }; - finalizer_policy new_finalizer_policy; - new_finalizer_policy.generation = 1; - new_finalizer_policy.threshold = 100; - new_finalizer_policy.finalizers = finalizers; + auto fin_policy = std::make_shared(); + finalizer_policy_diff new_finalizer_policy_diff = fin_policy->create_diff(finalizer_policy{.generation = 1, .threshold = 100, .finalizers = finalizers}); proposer_policy_ptr new_proposer_policy = std::make_shared(1, block_timestamp_type{200}, producer_authority_schedule{} ); emplace_extension( header.header_extensions, instant_finality_extension::extension_id(), - fc::raw::pack( instant_finality_extension{qc_claim_t{last_qc_block_num, is_strong_qc}, new_finalizer_policy, new_proposer_policy} ) + fc::raw::pack( instant_finality_extension{qc_claim_t{last_qc_block_num, is_strong_qc}, new_finalizer_policy_diff, new_proposer_policy} ) ); std::optional ext = header.extract_header_extension(instant_finality_extension::extension_id()); @@ -95,12 +91,12 @@ BOOST_AUTO_TEST_CASE(instant_finality_extension_with_values_test) BOOST_REQUIRE_EQUAL( if_extension.qc_claim.block_num, last_qc_block_num ); BOOST_REQUIRE_EQUAL( if_extension.qc_claim.is_strong_qc, is_strong_qc ); - BOOST_REQUIRE( !!if_extension.new_finalizer_policy ); - BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy->generation, 1u); - BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy->threshold, 100u); - BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy->finalizers[0].description, "test description"); - BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy->finalizers[0].weight, 50u); - BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy->finalizers[0].public_key.to_string(), "PUB_BLS_qVbh4IjYZpRGo8U_0spBUM-u-r_G0fMo4MzLZRsKWmm5uyeQTp74YFaMN9IDWPoVVT5rj_Tw1gvps6K9_OZ6sabkJJzug3uGfjA6qiaLbLh5Fnafwv-nVgzzzBlU2kwRrcHc8Q"); + BOOST_REQUIRE( !!if_extension.new_finalizer_policy_diff ); + BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy_diff->generation, 1u); + BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy_diff->threshold, 100u); + BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy_diff->finalizers_diff.insert_indexes[0].second.description, "test description"); + BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy_diff->finalizers_diff.insert_indexes[0].second.weight, 50u); + BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy_diff->finalizers_diff.insert_indexes[0].second.public_key.to_string(), "PUB_BLS_qVbh4IjYZpRGo8U_0spBUM-u-r_G0fMo4MzLZRsKWmm5uyeQTp74YFaMN9IDWPoVVT5rj_Tw1gvps6K9_OZ6sabkJJzug3uGfjA6qiaLbLh5Fnafwv-nVgzzzBlU2kwRrcHc8Q"); BOOST_REQUIRE( !!if_extension.new_proposer_policy ); BOOST_REQUIRE_EQUAL(if_extension.new_proposer_policy->schema_version, 1u); diff --git a/unittests/finality_test_cluster.cpp b/unittests/finality_test_cluster.cpp index 0a49e0fba3..c1a9ce2064 100644 --- a/unittests/finality_test_cluster.cpp +++ b/unittests/finality_test_cluster.cpp @@ -35,10 +35,10 @@ void finality_test_cluster::initial_tests(){ // this block contains the header exten/sion for the instant finality std::optional ext = block_1_n0->extract_header_extension(eosio::chain::instant_finality_extension::extension_id()); BOOST_TEST(!!ext); - std::optional fin_policy = std::get(*ext).new_finalizer_policy; - BOOST_TEST(!!fin_policy); - BOOST_TEST(fin_policy->finalizers.size() == 3); - BOOST_TEST(fin_policy->generation == 1); + std::optional fin_policy_diff = std::get(*ext).new_finalizer_policy_diff; + BOOST_TEST(!!fin_policy_diff); + BOOST_TEST(fin_policy_diff->finalizers_diff.insert_indexes.size() == 3); + BOOST_TEST(fin_policy_diff->generation == 1); produce_and_push_block(); // make setfinalizer irreversible diff --git a/unittests/finalizer_update_tests.cpp b/unittests/finalizer_update_tests.cpp index 17cdd1666c..6d52b4dbd8 100644 --- a/unittests/finalizer_update_tests.cpp +++ b/unittests/finalizer_update_tests.cpp @@ -179,24 +179,43 @@ BOOST_AUTO_TEST_CASE(savanna_set_finalizer_multiple_test) { try { auto b2 = t.produce_block(); auto pubkeys5 = t.set_active_finalizers({&finalizers[5], finset_size}); t.produce_blocks(2); + auto pubkeys6 = t.set_active_finalizers({&finalizers[6], finset_size}); b5 = t.produce_block(); + auto pubkeys7 = t.set_active_finalizers({&finalizers[7], finset_size}); check_finalizer_policy(t, b5, 2, pubkeys2); // 5 blocks after pubkeys3 (b5 - b0), pubkeys2 should still be active b6 = t.produce_block(); + auto pubkeys8 = t.set_active_finalizers({&finalizers[8], finset_size}); check_finalizer_policy(t, b6, 3, pubkeys3); // 6 blocks after pubkeys3 (b6 - b0), pubkeys3 should be active auto b7 = t.produce_block(); + auto pubkeys9 = t.set_active_finalizers({&finalizers[9], finset_size}); check_finalizer_policy(t, b7, 4, pubkeys4); // 6 blocks after pubkeys4 (b7 - b1), pubkeys4 should be active auto b8 = t.produce_block(); + auto pubkeys10 = t.set_active_finalizers({&finalizers[10], finset_size}); check_finalizer_policy(t, b8, 4, pubkeys4); // 7 blocks after pubkeys4, pubkeys4 should still be active auto b9 = t.produce_block(); + auto pubkeys11 = t.set_active_finalizers({&finalizers[11], finset_size}); check_finalizer_policy(t, b9, 5, pubkeys5); // 6 blocks after pubkeys5 (b9 - b3), pubkeys5 should be active + auto b10 = t.produce_block(); + auto b11 = t.produce_block(); // two blocks between 5 & 6 proposals + check_finalizer_policy(t, b11, 6, pubkeys6); // the rest are all one block apart, tests pending with propsed + auto b12 = t.produce_block(); + check_finalizer_policy(t, b12, 7, pubkeys7); + auto b13 = t.produce_block(); + check_finalizer_policy(t, b13, 8, pubkeys8); + auto b14 = t.produce_block(); + check_finalizer_policy(t, b14, 9, pubkeys9); + auto b15 = t.produce_block(); + check_finalizer_policy(t, b15, 10, pubkeys10); + auto b16 = t.produce_block(); + check_finalizer_policy(t, b16, 11, pubkeys11); // and no further change - ensure_next_block_finalizer_policy(t, 5, pubkeys5); - ensure_next_block_finalizer_policy(t, 5, pubkeys5); - ensure_next_block_finalizer_policy(t, 5, pubkeys5); - ensure_next_block_finalizer_policy(t, 5, pubkeys5); - ensure_next_block_finalizer_policy(t, 5, pubkeys5); + ensure_next_block_finalizer_policy(t, 11, pubkeys11); + ensure_next_block_finalizer_policy(t, 11, pubkeys11); + ensure_next_block_finalizer_policy(t, 11, pubkeys11); + ensure_next_block_finalizer_policy(t, 11, pubkeys11); + ensure_next_block_finalizer_policy(t, 11, pubkeys11); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/unittests/protocol_feature_tests.cpp b/unittests/protocol_feature_tests.cpp index 7557c163ae..3893e46477 100644 --- a/unittests/protocol_feature_tests.cpp +++ b/unittests/protocol_feature_tests.cpp @@ -1110,9 +1110,9 @@ BOOST_AUTO_TEST_CASE( protocol_activatation_works_after_transition_to_savanna ) std::optional ext = block->extract_header_extension(instant_finality_extension::extension_id()); BOOST_TEST(!!ext); - std::optional fin_policy = std::get(*ext).new_finalizer_policy; - BOOST_TEST(!!fin_policy); - BOOST_TEST(fin_policy->finalizers.size() == accounts.size()); + std::optional fin_policy_diff = std::get(*ext).new_finalizer_policy_diff; + BOOST_TEST(!!fin_policy_diff); + BOOST_TEST(fin_policy_diff->finalizers_diff.insert_indexes.size() == accounts.size()); block = c.produce_block(); // savanna now active auto fb = c.control->fetch_block_by_id(block->calculate_id()); diff --git a/unittests/svnn_ibc_tests.cpp b/unittests/svnn_ibc_tests.cpp index b243166f02..d879e88a06 100644 --- a/unittests/svnn_ibc_tests.cpp +++ b/unittests/svnn_ibc_tests.cpp @@ -95,10 +95,10 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc) BOOST_CHECK(std::holds_alternative(genesis_if_ext)); // and that it has the expected initial finalizer_policy - std::optional maybe_active_finalizer_policy = std::get(genesis_if_ext).new_finalizer_policy; - - BOOST_CHECK(maybe_active_finalizer_policy.has_value()); + std::optional maybe_active_finalizer_policy_diff = std::get(genesis_if_ext).new_finalizer_policy_diff; + BOOST_CHECK(maybe_active_finalizer_policy_diff.has_value()); +/** TODO diff or full active policy ? eosio::chain::finalizer_policy active_finalizer_policy = maybe_active_finalizer_policy.value(); BOOST_CHECK(active_finalizer_policy.finalizers.size() == 3); @@ -352,7 +352,7 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc) // verify action has failed, as expected BOOST_CHECK(failed); - +*/ } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/unittests/vote_processor_tests.cpp b/unittests/vote_processor_tests.cpp index 85c2ca0598..99f3cec753 100644 --- a/unittests/vote_processor_tests.cpp +++ b/unittests/vote_processor_tests.cpp @@ -42,13 +42,14 @@ auto create_genesis_block_state() { // block 2 std::vector finalizers; finalizers.push_back(finalizer_authority{.description = "first", .weight = 1, .public_key = bls_priv_keys.at(0).get_public_key()}); - finalizers.push_back(finalizer_authority{.description = "first", .weight = 1, .public_key = bls_priv_keys.at(1).get_public_key()}); - finalizers.push_back(finalizer_authority{.description = "first", .weight = 1, .public_key = bls_priv_keys.at(2).get_public_key()}); + finalizers.push_back(finalizer_authority{.description = "second", .weight = 1, .public_key = bls_priv_keys.at(1).get_public_key()}); + finalizers.push_back(finalizer_authority{.description = "third", .weight = 1, .public_key = bls_priv_keys.at(2).get_public_key()}); finalizer_policy new_finalizer_policy{.finalizers = finalizers}; + finalizer_policy_diff new_finalizer_policy_diff = finalizer_policy{}.create_diff(new_finalizer_policy); qc_claim_t initial_if_claim { .block_num = 2, .is_strong_qc = false }; emplace_extension(block->header_extensions, instant_finality_extension::extension_id(), - fc::raw::pack(instant_finality_extension{ initial_if_claim, new_finalizer_policy, {} })); + fc::raw::pack(instant_finality_extension{ initial_if_claim, new_finalizer_policy_diff, {} })); producer_authority_schedule schedule = { 0, { producer_authority{block->producer, block_signing_authority_v0{ 1, {{pub_key, 1}} } } } }; auto genesis = std::make_shared(); From 8000be2e2d245812f98b6be2fb7f400ae16c0ca8 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 7 May 2024 16:25:40 -0500 Subject: [PATCH 05/19] GH-5 Fix include --- libraries/libfc/include/fc/container/ordered_diff.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libfc/include/fc/container/ordered_diff.hpp b/libraries/libfc/include/fc/container/ordered_diff.hpp index ed6523d9e8..5d0ac7ed07 100644 --- a/libraries/libfc/include/fc/container/ordered_diff.hpp +++ b/libraries/libfc/include/fc/container/ordered_diff.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include namespace fc { From 6397cbd8466c403d5449ff642228bcc8c2c1f3d6 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 7 May 2024 19:23:16 -0500 Subject: [PATCH 06/19] GH-5 shared_ptr not needed --- .../chain/include/eosio/chain/block_header_state.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index cd89d3338b..174356e3da 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -134,18 +134,18 @@ struct block_header_state { if (finalizer_policies.empty()) { return active_finalizer_policy->create_diff(new_policy); } - finalizer_policy_ptr fin_policy_ptr = std::make_shared(*active_finalizer_policy); + finalizer_policy fin_policy = *active_finalizer_policy; for (const auto& e : finalizer_policies) { if (e.second.state == finalizer_policy_tracker::state_t::pending) { - fin_policy_ptr->apply_diff(e.second.policy_diff); + fin_policy.apply_diff(e.second.policy_diff); } } for (const auto& e : finalizer_policies) { if (e.second.state == finalizer_policy_tracker::state_t::proposed) { - fin_policy_ptr->apply_diff(e.second.policy_diff); + fin_policy.apply_diff(e.second.policy_diff); } } - return fin_policy_ptr->create_diff(new_policy); + return fin_policy.create_diff(new_policy); } }; From 16628b8692e04fb32eb9e44fd40ca4746d2e850e Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 7 May 2024 19:23:36 -0500 Subject: [PATCH 07/19] GH-5 Fix merge issue --- libraries/testing/include/eosio/testing/tester.hpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 6a26539cfb..1bcc1e9c2a 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -817,11 +817,11 @@ namespace eosio::testing { // Do some sanity checks on the genesis block // ------------------------------------------ const auto& ext = genesis_block->template extract_header_extension(); - const auto& fin_policy = ext.new_finalizer_policy; - BOOST_TEST(!!fin_policy); - BOOST_TEST(fin_policy->finalizers.size() == fin_policy_size); - BOOST_TEST(fin_policy->generation == 1); - BOOST_TEST(fin_policy->threshold == (fin_policy_size * 2) / 3 + 1); + const auto& fin_policy_diff = ext.new_finalizer_policy_diff; + BOOST_TEST(!!fin_policy_diff); + BOOST_TEST(fin_policy_diff->finalizers_diff.insert_indexes.size() == fin_policy_size); + BOOST_TEST(fin_policy_diff->generation == 1); + BOOST_TEST(fin_policy_diff->threshold == (fin_policy_size * 2) / 3 + 1); // wait till the genesis_block becomes irreversible. // The critical block is the block that makes the genesis_block irreversible @@ -850,7 +850,9 @@ namespace eosio::testing { auto b = produce_block(); BOOST_REQUIRE_EQUAL(t.lib_block->block_num(), pt_block->block_num()); - return *fin_policy; + finalizer_policy fin_policy; + fin_policy.apply_diff(*fin_policy_diff); + return fin_policy; } Tester& t; From bc78d46ad401d92de0ea57ea9ad485bf9a2e16ee Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 8 May 2024 12:47:50 -0500 Subject: [PATCH 08/19] GH-5 Reduce max by one to equal uint16_t max --- libraries/chain/include/eosio/chain/config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 74af7b59ca..c82d6c8c05 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -134,7 +134,7 @@ static_assert(maximum_tracked_dpos_confirmations >= ((max_producers * 2 / 3) + 1 /** * Maximum number of finalizers in the finalizer set */ -const static size_t max_finalizers = 64*1024; +const static size_t max_finalizers = 65535; // largest allowed finalizer policy diff const static size_t max_finalizer_description_size = 256; /** From ad7e9a7d4b711bc5df2a863cda1fcfe6a541f6e3 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 8 May 2024 12:49:28 -0500 Subject: [PATCH 09/19] GH-5 Make the index type templated to save space in packed diff_result. Added asserts to check for overflow. --- .../include/fc/container/ordered_diff.hpp | 36 ++++++++----- libraries/libfc/test/test_ordered_diff.cpp | 52 +++++++++++++++++-- 2 files changed, 71 insertions(+), 17 deletions(-) diff --git a/libraries/libfc/include/fc/container/ordered_diff.hpp b/libraries/libfc/include/fc/container/ordered_diff.hpp index 5d0ac7ed07..31437261c3 100644 --- a/libraries/libfc/include/fc/container/ordered_diff.hpp +++ b/libraries/libfc/include/fc/container/ordered_diff.hpp @@ -7,7 +7,7 @@ namespace fc { /** * @class ordered_diff - * @brief Provides ablity to generate and apply diff of containers of type T + * @brief Provides ability to generate and apply diff of containers of type T * * Example use: * std::vector source = { 'a', 'b', 'f', 'c', 'd' }; @@ -17,17 +17,19 @@ namespace fc { * assert(source == target); * * @param T type stored in Container, must provide == + * @param SizeType numeric type used for index into diff_result, for non-unique Containers a larger type may be required + * @param Container container type for ordered diff and for diff_result */ -template typename Container = std::vector> +template typename Container = std::vector> requires std::equality_comparable && std::random_access_iterator::iterator> class ordered_diff { public: struct diff_result { - Container remove_indexes; - Container> insert_indexes; + Container remove_indexes; + Container> insert_indexes; }; - /// Generate diff_result that when `apply_diff(source, diff_result)` to source will generate target + /// Generate diff_result that when `apply_diff(source, diff_result)` will modify source to be equal to target. static diff_result diff(const Container& source, const Container& target) { size_t s = 0; size_t t = 0; @@ -37,37 +39,47 @@ class ordered_diff { if (s < source.size() && t < target.size()) { if (source[s] == target[t]) { // nothing to do, skip over + assert(s <= std::numeric_limits::max()); + assert(t <= std::numeric_limits::max()); ++s; ++t; } else { // not equal if (s == source.size() - 1 && t == target.size() - 1) { // both at end, insert target and remove source + assert(s <= std::numeric_limits::max()); + assert(t <= std::numeric_limits::max()); result.remove_indexes.push_back(s); result.insert_indexes.emplace_back(t, target[t]); ++s; ++t; } else if (s + 1 < source.size() && t + 1 < target.size() && source[s + 1] == target[t + 1]) { // misalignment, but next value equal, insert and remove + assert(s <= std::numeric_limits::max()); + assert(t <= std::numeric_limits::max()); result.remove_indexes.push_back(s); result.insert_indexes.emplace_back(t, target[t]); ++s; ++t; } else if (t + 1 < target.size() && source[s] == target[t + 1]) { // source equals next target, insert current target + assert(t <= std::numeric_limits::max()); result.insert_indexes.emplace_back(t, target[t]); ++t; } else { // source[s + 1] == target[t] // target matches next source, remove current source + assert(s <= std::numeric_limits::max()); result.remove_indexes.push_back(s); ++s; } } } else if (s < source.size()) { // remove extra in source + assert(s <= std::numeric_limits::max()); result.remove_indexes.push_back(s); ++s; } else if (t < target.size()) { // insert extra in target + assert(t <= std::numeric_limits::max()); result.insert_indexes.emplace_back(t, target[t]); ++t; } @@ -76,21 +88,21 @@ class ordered_diff { return result; } + /// @param diff the diff_result created from diff(source, target), apply_diff(source, diff_result) => target + /// @param container the source of diff(source, target) to modify using the diff_result to produce original target template requires std::same_as, diff_result> - static void apply_diff(Container& source, X&& diff) { + static void apply_diff(Container& container, X&& diff) { // Remove from the source based on diff.remove_indexes std::ptrdiff_t offset = 0; - for (size_t index : diff.remove_indexes) { - source.erase(source.begin() + index + offset); + for (SizeType index : diff.remove_indexes) { + container.erase(container.begin() + index + offset); --offset; } // Insert into the source based on diff.insert_indexes - for (auto& t : diff.insert_indexes) { - size_t index = std::get<0>(t); - auto& value = std::get<1>(t); - source.insert(source.begin() + index, std::move(value)); + for (auto& [index, value] : diff.insert_indexes) { + container.insert(container.begin() + index, std::move(value)); } } diff --git a/libraries/libfc/test/test_ordered_diff.cpp b/libraries/libfc/test/test_ordered_diff.cpp index 2ec54b1650..23b9c2035f 100644 --- a/libraries/libfc/test/test_ordered_diff.cpp +++ b/libraries/libfc/test/test_ordered_diff.cpp @@ -18,7 +18,7 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { BOOST_TEST(source == target); } { // Basic case, deque - using ordered_deque_char_diff = ordered_diff; + using ordered_deque_char_diff = ordered_diff; deque source = {'a', 'x', 'c', 'd', 'e'}; deque target = {'z', 'c', 'y', 'f'}; auto result = ordered_deque_char_diff::diff(source, target); @@ -28,15 +28,15 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { { // Empty vectors vector source; vector target; - ordered_diff::diff_result result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + ordered_diff::diff_result result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); BOOST_TEST(source == target); } { // All elements removed vector source = {'a', 'b', 'c', 'd', 'e'}; vector target; - auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); BOOST_TEST(source == target); } { // All elements inserted @@ -95,6 +95,48 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { ordered_diff::apply_diff(source, result); BOOST_TEST(source == target); } + { // non-unique + vector source = {'a', 'b', 'c', 'd', 'e', 'c', 'a', 'q'}; + vector target = {'z', 'a', 'b', 'c', 'd', 'a'}; + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } + { // full + vector source(std::numeric_limits::max()+1); + std::iota(source.begin(), source.end(), 0); + vector target(source.size()); + std::reverse_copy(source.begin(), source.end(), target.begin()); + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + target.clear(); + result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + source.clear(); + result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } + { // non-unique full + vector source(std::numeric_limits::max()*2); + std::iota(source.begin(), source.begin()+std::numeric_limits::max(), 0); + std::iota(source.begin()+std::numeric_limits::max(), source.end(), 0); + vector target(source.size()); + std::reverse_copy(source.begin(), source.end(), target.begin()); + auto result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + target.clear(); + result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + source.clear(); + result = ordered_diff::diff(source, target); + ordered_diff::apply_diff(source, result); + BOOST_TEST(source == target); + } } FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_CASE(ordered_diff_string_test) try { From 7495f2aa759c144fdfc3cd86a912fc860539a49d Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 8 May 2024 12:50:08 -0500 Subject: [PATCH 10/19] GH-5 Use uint16_t for index type of diff since max_finalizers fit --- .../chain/include/eosio/chain/finality/finalizer_policy.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp b/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp index 64089fa950..d0df6383dd 100644 --- a/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp +++ b/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp @@ -6,8 +6,9 @@ namespace eosio::chain { - using finalizers_differ = fc::ordered_diff; - using finalizers_diff_t = fc::ordered_diff::diff_result; + static_assert(std::numeric_limits::max() <= config::max_finalizers); + using finalizers_differ = fc::ordered_diff; + using finalizers_diff_t = finalizers_differ::diff_result; struct finalizer_policy_diff { uint32_t generation = 0; ///< sequentially incrementing version number From 8456ea5ac12fdbc9a3d3433d59414f4e4dd586ee Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 8 May 2024 12:50:30 -0500 Subject: [PATCH 11/19] GH-5 Add assert, update log message --- libraries/chain/block_header_state.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index e89b9adc32..494e668a92 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -135,6 +135,7 @@ void finish_next(const block_header_state& prev, if (tracker.state == finalizer_policy_tracker::state_t::pending) { // new finalizer_policy becones active // ----------------------------------- + assert(prev.active_finalizer_policy); next_header_state.active_finalizer_policy.reset(new finalizer_policy(*prev.active_finalizer_policy)); next_header_state.active_finalizer_policy->apply_diff(tracker.policy_diff); } else { @@ -162,7 +163,7 @@ void finish_next(const block_header_state& prev, // Add this new proposal to the `finalizer_policies` multimap which tracks the in-flight proposals, // increment the generation number, and log that proposal (debug level). // ------------------------------------------------------------------------------------------------ - dlog("New finalizer policy proposed in block ${id}: ${pol}", + dlog("New finalizer policy proposed in block ${id}, diff: ${pol}", ("id", prev.block_id)("pol", *if_ext.new_finalizer_policy_diff)); next_header_state.finalizer_policy_generation = if_ext.new_finalizer_policy_diff->generation; next_header_state.finalizer_policies.emplace( From ad4ced333ce3492d9f2ec9dee16eccfb643ca26b Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 8 May 2024 16:25:25 -0500 Subject: [PATCH 12/19] GH-5 Take rvalue reference and return the container from apply_diff to make usage more obvious. --- .../eosio/chain/finality/finalizer_policy.hpp | 2 +- .../include/fc/container/ordered_diff.hpp | 6 ++- libraries/libfc/test/test_ordered_diff.cpp | 48 +++++++++---------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp b/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp index d0df6383dd..2637cd90c3 100644 --- a/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp +++ b/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp @@ -32,7 +32,7 @@ namespace eosio::chain { void apply_diff(X&& diff) { generation = diff.generation; threshold = diff.threshold; - finalizers_differ::apply_diff(finalizers, std::move(diff.finalizers_diff)); + finalizers = finalizers_differ::apply_diff(std::move(finalizers), std::forward(diff).finalizers_diff); } // max accumulated weak weight before becoming weak_final diff --git a/libraries/libfc/include/fc/container/ordered_diff.hpp b/libraries/libfc/include/fc/container/ordered_diff.hpp index 31437261c3..e2440d6ab9 100644 --- a/libraries/libfc/include/fc/container/ordered_diff.hpp +++ b/libraries/libfc/include/fc/container/ordered_diff.hpp @@ -88,11 +88,12 @@ class ordered_diff { return result; } - /// @param diff the diff_result created from diff(source, target), apply_diff(source, diff_result) => target + /// @param diff the diff_result created from diff(source, target), apply_diff(std::move(source), diff_result) => target /// @param container the source of diff(source, target) to modify using the diff_result to produce original target + /// @return the modified container now equal to original target template requires std::same_as, diff_result> - static void apply_diff(Container& container, X&& diff) { + static Container apply_diff(Container&& container, X&& diff) { // Remove from the source based on diff.remove_indexes std::ptrdiff_t offset = 0; for (SizeType index : diff.remove_indexes) { @@ -104,6 +105,7 @@ class ordered_diff { for (auto& [index, value] : diff.insert_indexes) { container.insert(container.begin() + index, std::move(value)); } + return container; } }; // class ordered_diff diff --git a/libraries/libfc/test/test_ordered_diff.cpp b/libraries/libfc/test/test_ordered_diff.cpp index 23b9c2035f..e7ffcfebea 100644 --- a/libraries/libfc/test/test_ordered_diff.cpp +++ b/libraries/libfc/test/test_ordered_diff.cpp @@ -14,7 +14,7 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { vector source = {'a', 'b', 'c', 'd', 'e'}; vector target = {'a', 'c', 'e', 'f'}; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { // Basic case, deque @@ -22,84 +22,84 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { deque source = {'a', 'x', 'c', 'd', 'e'}; deque target = {'z', 'c', 'y', 'f'}; auto result = ordered_deque_char_diff::diff(source, target); - ordered_deque_char_diff::apply_diff(source, result); + source = ordered_deque_char_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { // Empty vectors vector source; vector target; ordered_diff::diff_result result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { // All elements removed vector source = {'a', 'b', 'c', 'd', 'e'}; vector target; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { // All elements inserted vector source; vector target = {'a', 'b', 'c', 'd', 'e'}; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { // No change vector source = {'a', 'b', 'c', 'd', 'e'}; vector target = source; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { // Mix of removals and inserts vector source = {'a', 'b', 'c', 'd', 'e'}; vector target = {'a', 'c', 'e', 'f', 'g', 'h'}; ordered_diff::diff_result result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { // Mix of removals and inserts vector source = {1, 2, 3, 4, 5}; vector target = {3, 4, 6, 2, 0}; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { // Complete change vector source = {'a', 'b', 'c', 'd', 'e'}; vector target = {'f', 'g', 'h', 'i'}; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { // Diff order vector source = {'a', 'b', 'c', 'd', 'e'}; vector target = {'e', 'd', 'c', 'b', 'a'}; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { // shift left vector source = {'a', 'b', 'c', 'd', 'e'}; vector target = {'b', 'c', 'd', 'e', 'f'}; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { // shift right vector source = {'a', 'b', 'c', 'd', 'e'}; vector target = {'z', 'a', 'b', 'c', 'd'}; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { // non-unique vector source = {'a', 'b', 'c', 'd', 'e', 'c', 'a', 'q'}; vector target = {'z', 'a', 'b', 'c', 'd', 'a'}; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { // full @@ -108,15 +108,15 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { vector target(source.size()); std::reverse_copy(source.begin(), source.end(), target.begin()); auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); target.clear(); result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); source.clear(); result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { // non-unique full @@ -126,15 +126,15 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { vector target(source.size()); std::reverse_copy(source.begin(), source.end(), target.begin()); auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); target.clear(); result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); source.clear(); result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } } FC_LOG_AND_RETHROW(); @@ -145,28 +145,28 @@ BOOST_AUTO_TEST_CASE(ordered_diff_string_test) try { vector source = {"hello", "how", "are", "you", "today"}; vector target = {"hi", "are", "you", "here"}; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { vector source = {"prod1", "prod2", "prod3", "prod4", "prod5"}; vector target = {"prod2", "prod1", "prod3", "prod4", "prod5"}; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, result); + source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } { vector source = {"prod1", "prod2", "prod3", "prod4", "prod5"}; vector target = {"prod5", "prod1", "prod2", "prod3", "prod4"}; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, std::move(result)); + source = ordered_diff::apply_diff(std::move(source), std::move(result)); BOOST_TEST(source == target); } { vector source = {"prod1", "prod2", "prod3", "prod4", "prod5"}; vector target = {"prod2", "prod3", "prod4", "prod5", "prod6"}; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, std::move(result)); + source = ordered_diff::apply_diff(std::move(source), std::move(result)); BOOST_TEST(source == target); } @@ -190,7 +190,7 @@ BOOST_AUTO_TEST_CASE(ordered_diff_moveable_test) try { vector source = {count_moves{"hello"}, count_moves{"there"}}; vector target = {count_moves{"hi"}, count_moves{"there"}}; auto result = ordered_diff::diff(source, target); - ordered_diff::apply_diff(source, std::move(result)); + source = ordered_diff::apply_diff(std::move(source), std::move(result)); BOOST_TEST(source == target); BOOST_TEST(count_moves::num_moves == 1); } From 6fe5ec2f66c7ae85371f0b12f7fca235b46b22c0 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 8 May 2024 18:40:26 -0500 Subject: [PATCH 13/19] GH-5 Track full finalizer policy instead of diffs --- libraries/chain/block_header_state.cpp | 76 +++++++++++++++---- .../eosio/chain/block_header_state.hpp | 23 +----- unittests/svnn_ibc_tests.cpp | 9 ++- 3 files changed, 71 insertions(+), 37 deletions(-) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 494e668a92..528947b393 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -22,7 +22,8 @@ digest_type block_header_state::compute_base_digest() const { fc::raw::pack( enc, fp_pair.first ); const finalizer_policy_tracker& tracker = fp_pair.second; fc::raw::pack( enc, tracker.state ); - fc::raw::pack( enc, tracker.policy_diff ); + assert(tracker.policy); + fc::raw::pack( enc, *tracker.policy ); } assert(active_proposer_policy); @@ -66,6 +67,48 @@ const vector& block_header_state::get_new_protocol_feature_activati return detail::get_new_protocol_feature_activations(header_exts); } +finalizer_policy_diff block_header_state::calculate_finalizer_policy_diff(const finalizer_policy& new_policy) const { + if (finalizer_policies.empty()) { + return active_finalizer_policy->create_diff(new_policy); + } + for (const auto& e : finalizer_policies) { + if (e.second.state == finalizer_policy_tracker::state_t::pending) { + return e.second.policy->create_diff(new_policy); + } + } + for (const auto& e : finalizer_policies) { + if (e.second.state == finalizer_policy_tracker::state_t::proposed) { + return e.second.policy->create_diff(new_policy); + } + } + assert(false); +} + +finalizer_policy block_header_state::calculate_finalizer_policy(const finalizer_policy_diff& diff) const { + finalizer_policy result; + if (finalizer_policies.empty()) { + assert(active_finalizer_policy); + result = *active_finalizer_policy; + result.apply_diff(diff); + return result; + } + for (const auto& e : finalizer_policies) { + if (e.second.state == finalizer_policy_tracker::state_t::pending) { + result = *e.second.policy; + result.apply_diff(diff); + return result; + } + } + for (const auto& e : finalizer_policies) { + if (e.second.state == finalizer_policy_tracker::state_t::proposed) { + result = *e.second.policy; + result.apply_diff(diff); + return result; + } + } + assert(false); +} + // ------------------------------------------------------------------------------------------------- // `finish_next` updates the next `block_header_state` according to the contents of the // header extensions (either new protocol_features or instant_finality_extension) applicable to this @@ -77,7 +120,8 @@ const vector& block_header_state::get_new_protocol_feature_activati void finish_next(const block_header_state& prev, block_header_state& next_header_state, vector new_protocol_feature_activations, - instant_finality_extension if_ext) { + instant_finality_extension if_ext, + std::optional new_finalizer_policy) { // activated protocol features // --------------------------- if (!new_protocol_feature_activations.empty()) { @@ -135,15 +179,13 @@ void finish_next(const block_header_state& prev, if (tracker.state == finalizer_policy_tracker::state_t::pending) { // new finalizer_policy becones active // ----------------------------------- - assert(prev.active_finalizer_policy); - next_header_state.active_finalizer_policy.reset(new finalizer_policy(*prev.active_finalizer_policy)); - next_header_state.active_finalizer_policy->apply_diff(tracker.policy_diff); + next_header_state.active_finalizer_policy.reset(new finalizer_policy(*tracker.policy)); } else { assert(tracker.state == finalizer_policy_tracker::state_t::proposed); // block where finalizer_policy was proposed became final. The finalizer policy will // become active when next block becomes final. // --------------------------------------------------------------------------------- - finalizer_policy_tracker t { finalizer_policy_tracker::state_t::pending, tracker.policy_diff }; + finalizer_policy_tracker t { finalizer_policy_tracker::state_t::pending, tracker.policy }; next_header_state.finalizer_policies.emplace(next_header_state.block_num(), std::move(t)); } ++it; @@ -157,20 +199,19 @@ void finish_next(const block_header_state& prev, } } - if (if_ext.new_finalizer_policy_diff) { + if (new_finalizer_policy) { // a new `finalizer_policy` was proposed in the previous block, and is present in the previous // block's header extensions. // Add this new proposal to the `finalizer_policies` multimap which tracks the in-flight proposals, // increment the generation number, and log that proposal (debug level). // ------------------------------------------------------------------------------------------------ - dlog("New finalizer policy proposed in block ${id}, diff: ${pol}", - ("id", prev.block_id)("pol", *if_ext.new_finalizer_policy_diff)); - next_header_state.finalizer_policy_generation = if_ext.new_finalizer_policy_diff->generation; + dlog("New finalizer policy proposed in block ${id}..: ${pol}", + ("id", prev.block_id.str().substr(8,16))("pol", *new_finalizer_policy)); + next_header_state.finalizer_policy_generation = new_finalizer_policy->generation; next_header_state.finalizer_policies.emplace( next_header_state.block_num(), finalizer_policy_tracker{finalizer_policy_tracker::state_t::proposed, - std::move(*if_ext.new_finalizer_policy_diff)}); - + std::make_shared(std::move(*new_finalizer_policy))}); } else { next_header_state.finalizer_policy_generation = prev.finalizer_policy_generation; } @@ -228,7 +269,8 @@ block_header_state block_header_state::next(block_header_state_input& input) con next_header_state.header_exts.emplace(ext_id, std::move(pfa_ext)); } - finish_next(*this, next_header_state, std::move(input.new_protocol_feature_activations), std::move(new_if_ext)); + finish_next(*this, next_header_state, std::move(input.new_protocol_feature_activations), std::move(new_if_ext), + std::move(input.new_finalizer_policy)); return next_header_state; } @@ -285,7 +327,13 @@ block_header_state block_header_state::next(const signed_block_header& h, valida ("f", next_core_metadata.final_on_strong_qc_block_num)); }; - finish_next(*this, next_header_state, std::move(new_protocol_feature_activations), if_ext); + std::optional new_finalizer_policy; + if (if_ext.new_finalizer_policy_diff) { + new_finalizer_policy = calculate_finalizer_policy(*if_ext.new_finalizer_policy_diff); + } + + finish_next(*this, next_header_state, std::move(new_protocol_feature_activations), if_ext, + std::move(new_finalizer_policy)); return next_header_state; } diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index 174356e3da..7e82b874da 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -47,7 +47,7 @@ struct finality_digest_data_v1 { struct finalizer_policy_tracker { enum class state_t { proposed = 0, pending }; state_t state; - finalizer_policy_diff policy_diff; + finalizer_policy_ptr policy; }; struct building_block_input { @@ -130,23 +130,8 @@ struct block_header_state { const vector& get_new_protocol_feature_activations() const; const producer_authority& get_scheduled_producer(block_timestamp_type t) const; - finalizer_policy_diff calculate_finalizer_policy_diff(const finalizer_policy& new_policy) const { - if (finalizer_policies.empty()) { - return active_finalizer_policy->create_diff(new_policy); - } - finalizer_policy fin_policy = *active_finalizer_policy; - for (const auto& e : finalizer_policies) { - if (e.second.state == finalizer_policy_tracker::state_t::pending) { - fin_policy.apply_diff(e.second.policy_diff); - } - } - for (const auto& e : finalizer_policies) { - if (e.second.state == finalizer_policy_tracker::state_t::proposed) { - fin_policy.apply_diff(e.second.policy_diff); - } - } - return fin_policy.create_diff(new_policy); - } + finalizer_policy_diff calculate_finalizer_policy_diff(const finalizer_policy& new_policy) const; + finalizer_policy calculate_finalizer_policy(const finalizer_policy_diff& diff) const; }; using block_header_state_ptr = std::shared_ptr; @@ -155,7 +140,7 @@ using block_header_state_ptr = std::shared_ptr; FC_REFLECT_ENUM( eosio::chain::finalizer_policy_tracker::state_t, (proposed)(pending)) -FC_REFLECT( eosio::chain::finalizer_policy_tracker, (state)(policy_diff)) +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) diff --git a/unittests/svnn_ibc_tests.cpp b/unittests/svnn_ibc_tests.cpp index 74d06f587d..ab70b0eac0 100644 --- a/unittests/svnn_ibc_tests.cpp +++ b/unittests/svnn_ibc_tests.cpp @@ -101,10 +101,11 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc) std::get(genesis_if_ext).new_finalizer_policy_diff; BOOST_CHECK(maybe_active_finalizer_policy_diff.has_value()); -/** TODO diff or full active policy ? - eosio::chain::finalizer_policy active_finalizer_policy = maybe_active_finalizer_policy.value(); - BOOST_CHECK_EQUAL(active_finalizer_policy.finalizers.size(), cluster.num_nodes); + eosio::chain::finalizer_policy_diff active_finalizer_policy_diff = maybe_active_finalizer_policy_diff.value(); + eosio::chain::finalizer_policy active_finalizer_policy; + active_finalizer_policy.apply_diff(active_finalizer_policy_diff); + BOOST_CHECK_EQUAL(active_finalizer_policy.generation, 1u); // compute the digest of the finalizer policy @@ -374,7 +375,7 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc) // verify action has failed, as expected BOOST_CHECK(failed); -*/ + } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file From 01177018891387bb736151021ad7f1e52b9d7f46 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 9 May 2024 12:20:45 -0500 Subject: [PATCH 14/19] GH-5 Verify instant_finality_extension finalizes diff --- unittests/finalizer_update_tests.cpp | 40 +++++++++++++++++++++------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/unittests/finalizer_update_tests.cpp b/unittests/finalizer_update_tests.cpp index 1c9a2d8bbf..b96d9888ec 100644 --- a/unittests/finalizer_update_tests.cpp +++ b/unittests/finalizer_update_tests.cpp @@ -71,6 +71,17 @@ BOOST_AUTO_TEST_CASE(savanna_set_finalizer_multiple_test) { try { size_t num_keys = 50u; size_t finset_size = 21u; + auto verify_block_finality_generation = [](const signed_block_ptr& block, uint32_t gen) { + std::optional ext = block->extract_header_extension(instant_finality_extension::extension_id()); + BOOST_TEST(!!ext); + std::optional fin_policy_diff = std::get(*ext).new_finalizer_policy_diff; + BOOST_TEST(!!fin_policy_diff); + BOOST_TEST(fin_policy_diff->generation == gen); + // each set_finalizer_policy in this test removes one and adds one + BOOST_TEST(fin_policy_diff->finalizers_diff.remove_indexes.size() == 1); + BOOST_TEST(fin_policy_diff->finalizers_diff.insert_indexes.size() == 1); + }; + // Create finalizer keys finalizer_keys fin_keys(t, num_keys, finset_size); @@ -96,30 +107,39 @@ BOOST_AUTO_TEST_CASE(savanna_set_finalizer_multiple_test) { try { // take to become active // ------------------------------------------------------------------------------ auto pubkeys3 = fin_keys.set_finalizer_policy(3u).pubkeys; - t.produce_block(); + auto b = t.produce_block(); + verify_block_finality_generation(b, 3); auto pubkeys4 = fin_keys.set_finalizer_policy(4u).pubkeys; - t.produce_block(); + b = t.produce_block(); + verify_block_finality_generation(b, 4); t.produce_block(); auto pubkeys5 = fin_keys.set_finalizer_policy(5u).pubkeys; - t.produce_blocks(2); - auto pubkeys6 = fin_keys.set_finalizer_policy(6u).pubkeys; + b = t.produce_block(); + verify_block_finality_generation(b, 5); t.produce_block(); + auto pubkeys6 = fin_keys.set_finalizer_policy(6u).pubkeys; + b = t.produce_block(); + verify_block_finality_generation(b, 6); auto pubkeys7 = fin_keys.set_finalizer_policy(7u).pubkeys; t.check_head_finalizer_policy(2u, pubkeys2); // 5 blocks after pubkeys3 (b5 - b0), pubkeys2 should still be active - t.produce_block(); + b = t.produce_block(); + verify_block_finality_generation(b, 7); auto pubkeys8 = fin_keys.set_finalizer_policy(8u).pubkeys; t.check_head_finalizer_policy(3u, pubkeys3); // 6 blocks after pubkeys3 (b6 - b0), pubkeys3 should be active - t.produce_block(); + b = t.produce_block(); + verify_block_finality_generation(b, 8); auto pubkeys9 = fin_keys.set_finalizer_policy(9u).pubkeys; t.check_head_finalizer_policy(4u, pubkeys4); // 6 blocks after pubkeys4 (b7 - b1), pubkeys4 should be active - - t.produce_block(); + b = t.produce_block(); + verify_block_finality_generation(b, 9); auto pubkeys10 = fin_keys.set_finalizer_policy(10u).pubkeys; t.check_head_finalizer_policy(4u, pubkeys4); // 7 blocks after pubkeys4, pubkeys4 should still be active - t.produce_block(); + b = t.produce_block(); + verify_block_finality_generation(b, 10); auto pubkeys11 = fin_keys.set_finalizer_policy(11u).pubkeys; t.check_head_finalizer_policy(5u, pubkeys5); // 6 blocks after pubkeys5 (b9 - b3), pubkeys5 should be active - t.produce_block(); + b = t.produce_block(); + verify_block_finality_generation(b, 11); t.produce_block(); // two blocks between 5 & 6 proposals t.check_head_finalizer_policy(6u, pubkeys6); // the rest are all one block apart, tests pending with propsed auto b12 = t.produce_block(); From 822ac388422c51d5b355caffe1c217bfc275be7b Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 9 May 2024 12:21:07 -0500 Subject: [PATCH 15/19] GH-5 Calculate policy instead of passing it --- libraries/chain/block_header_state.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 528947b393..7835f633cb 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -120,8 +120,7 @@ finalizer_policy block_header_state::calculate_finalizer_policy(const finalizer_ void finish_next(const block_header_state& prev, block_header_state& next_header_state, vector new_protocol_feature_activations, - instant_finality_extension if_ext, - std::optional new_finalizer_policy) { + instant_finality_extension if_ext) { // activated protocol features // --------------------------- if (!new_protocol_feature_activations.empty()) { @@ -199,19 +198,21 @@ void finish_next(const block_header_state& prev, } } - if (new_finalizer_policy) { + if (if_ext.new_finalizer_policy_diff) { + finalizer_policy new_finalizer_policy = prev.calculate_finalizer_policy(*if_ext.new_finalizer_policy_diff); + // a new `finalizer_policy` was proposed in the previous block, and is present in the previous // block's header extensions. // Add this new proposal to the `finalizer_policies` multimap which tracks the in-flight proposals, // increment the generation number, and log that proposal (debug level). // ------------------------------------------------------------------------------------------------ dlog("New finalizer policy proposed in block ${id}..: ${pol}", - ("id", prev.block_id.str().substr(8,16))("pol", *new_finalizer_policy)); - next_header_state.finalizer_policy_generation = new_finalizer_policy->generation; + ("id", prev.block_id.str().substr(8,16))("pol", new_finalizer_policy)); + next_header_state.finalizer_policy_generation = new_finalizer_policy.generation; next_header_state.finalizer_policies.emplace( next_header_state.block_num(), finalizer_policy_tracker{finalizer_policy_tracker::state_t::proposed, - std::make_shared(std::move(*new_finalizer_policy))}); + std::make_shared(std::move(new_finalizer_policy))}); } else { next_header_state.finalizer_policy_generation = prev.finalizer_policy_generation; } @@ -269,8 +270,7 @@ block_header_state block_header_state::next(block_header_state_input& input) con next_header_state.header_exts.emplace(ext_id, std::move(pfa_ext)); } - finish_next(*this, next_header_state, std::move(input.new_protocol_feature_activations), std::move(new_if_ext), - std::move(input.new_finalizer_policy)); + finish_next(*this, next_header_state, std::move(input.new_protocol_feature_activations), std::move(new_if_ext)); return next_header_state; } @@ -327,13 +327,7 @@ block_header_state block_header_state::next(const signed_block_header& h, valida ("f", next_core_metadata.final_on_strong_qc_block_num)); }; - std::optional new_finalizer_policy; - if (if_ext.new_finalizer_policy_diff) { - new_finalizer_policy = calculate_finalizer_policy(*if_ext.new_finalizer_policy_diff); - } - - finish_next(*this, next_header_state, std::move(new_protocol_feature_activations), if_ext, - std::move(new_finalizer_policy)); + finish_next(*this, next_header_state, std::move(new_protocol_feature_activations), if_ext); return next_header_state; } From c4d4700dba2fdab12995256a5ad3664de01d958f Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 9 May 2024 12:34:17 -0500 Subject: [PATCH 16/19] GH-5 Verify instant_finality_extension diff --- unittests/finalizer_update_tests.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/unittests/finalizer_update_tests.cpp b/unittests/finalizer_update_tests.cpp index b96d9888ec..bd043170a8 100644 --- a/unittests/finalizer_update_tests.cpp +++ b/unittests/finalizer_update_tests.cpp @@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(savanna_set_finalizer_multiple_test) { try { size_t num_keys = 50u; size_t finset_size = 21u; - auto verify_block_finality_generation = [](const signed_block_ptr& block, uint32_t gen) { + auto verify_block_finality_generation = [](const signed_block_ptr& block, uint32_t gen, const bls_public_key& key) { std::optional ext = block->extract_header_extension(instant_finality_extension::extension_id()); BOOST_TEST(!!ext); std::optional fin_policy_diff = std::get(*ext).new_finalizer_policy_diff; @@ -79,7 +79,8 @@ BOOST_AUTO_TEST_CASE(savanna_set_finalizer_multiple_test) { try { BOOST_TEST(fin_policy_diff->generation == gen); // each set_finalizer_policy in this test removes one and adds one BOOST_TEST(fin_policy_diff->finalizers_diff.remove_indexes.size() == 1); - BOOST_TEST(fin_policy_diff->finalizers_diff.insert_indexes.size() == 1); + BOOST_TEST_REQUIRE(fin_policy_diff->finalizers_diff.insert_indexes.size() == 1); + BOOST_TEST(fin_policy_diff->finalizers_diff.insert_indexes[0].second.public_key == key); }; // Create finalizer keys @@ -108,38 +109,38 @@ BOOST_AUTO_TEST_CASE(savanna_set_finalizer_multiple_test) { try { // ------------------------------------------------------------------------------ auto pubkeys3 = fin_keys.set_finalizer_policy(3u).pubkeys; auto b = t.produce_block(); - verify_block_finality_generation(b, 3); + verify_block_finality_generation(b, 3, pubkeys3.back()); auto pubkeys4 = fin_keys.set_finalizer_policy(4u).pubkeys; b = t.produce_block(); - verify_block_finality_generation(b, 4); + verify_block_finality_generation(b, 4, pubkeys4.back()); t.produce_block(); auto pubkeys5 = fin_keys.set_finalizer_policy(5u).pubkeys; b = t.produce_block(); - verify_block_finality_generation(b, 5); + verify_block_finality_generation(b, 5, pubkeys5.back()); t.produce_block(); auto pubkeys6 = fin_keys.set_finalizer_policy(6u).pubkeys; b = t.produce_block(); - verify_block_finality_generation(b, 6); + verify_block_finality_generation(b, 6, pubkeys6.back()); auto pubkeys7 = fin_keys.set_finalizer_policy(7u).pubkeys; t.check_head_finalizer_policy(2u, pubkeys2); // 5 blocks after pubkeys3 (b5 - b0), pubkeys2 should still be active b = t.produce_block(); - verify_block_finality_generation(b, 7); + verify_block_finality_generation(b, 7, pubkeys7.back()); auto pubkeys8 = fin_keys.set_finalizer_policy(8u).pubkeys; t.check_head_finalizer_policy(3u, pubkeys3); // 6 blocks after pubkeys3 (b6 - b0), pubkeys3 should be active b = t.produce_block(); - verify_block_finality_generation(b, 8); + verify_block_finality_generation(b, 8, pubkeys8.back()); auto pubkeys9 = fin_keys.set_finalizer_policy(9u).pubkeys; t.check_head_finalizer_policy(4u, pubkeys4); // 6 blocks after pubkeys4 (b7 - b1), pubkeys4 should be active b = t.produce_block(); - verify_block_finality_generation(b, 9); + verify_block_finality_generation(b, 9, pubkeys9.back()); auto pubkeys10 = fin_keys.set_finalizer_policy(10u).pubkeys; t.check_head_finalizer_policy(4u, pubkeys4); // 7 blocks after pubkeys4, pubkeys4 should still be active b = t.produce_block(); - verify_block_finality_generation(b, 10); + verify_block_finality_generation(b, 10, pubkeys10.back()); auto pubkeys11 = fin_keys.set_finalizer_policy(11u).pubkeys; t.check_head_finalizer_policy(5u, pubkeys5); // 6 blocks after pubkeys5 (b9 - b3), pubkeys5 should be active b = t.produce_block(); - verify_block_finality_generation(b, 11); + verify_block_finality_generation(b, 11, pubkeys11.back()); t.produce_block(); // two blocks between 5 & 6 proposals t.check_head_finalizer_policy(6u, pubkeys6); // the rest are all one block apart, tests pending with propsed auto b12 = t.produce_block(); From 30c56b7999e3974f01e19d66cc0897c6915f2232 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 9 May 2024 12:36:16 -0500 Subject: [PATCH 17/19] GH-5 Compare with correct in-flight finalizer policy --- libraries/chain/block_header_state.cpp | 50 ++++++------------- .../eosio/chain/block_header_state.hpp | 1 + 2 files changed, 16 insertions(+), 35 deletions(-) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 7835f633cb..1f5bf538bf 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -67,46 +67,26 @@ const vector& block_header_state::get_new_protocol_feature_activati return detail::get_new_protocol_feature_activations(header_exts); } -finalizer_policy_diff block_header_state::calculate_finalizer_policy_diff(const finalizer_policy& new_policy) const { - if (finalizer_policies.empty()) { - return active_finalizer_policy->create_diff(new_policy); - } - for (const auto& e : finalizer_policies) { - if (e.second.state == finalizer_policy_tracker::state_t::pending) { - return e.second.policy->create_diff(new_policy); - } - } - for (const auto& e : finalizer_policies) { - if (e.second.state == finalizer_policy_tracker::state_t::proposed) { - return e.second.policy->create_diff(new_policy); +// The last proposed finalizer policy if none proposed or pending is 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) { + if (ritr->second.state == finalizer_policy_tracker::state_t::proposed) + return *ritr->second.policy; } + return *finalizer_policies.rbegin()->second.policy; } - assert(false); + return *active_finalizer_policy; +} + +finalizer_policy_diff block_header_state::calculate_finalizer_policy_diff(const finalizer_policy& new_policy) const { + return get_last_proposed_finalizer_policy().create_diff(new_policy); } finalizer_policy block_header_state::calculate_finalizer_policy(const finalizer_policy_diff& diff) const { - finalizer_policy result; - if (finalizer_policies.empty()) { - assert(active_finalizer_policy); - result = *active_finalizer_policy; - result.apply_diff(diff); - return result; - } - for (const auto& e : finalizer_policies) { - if (e.second.state == finalizer_policy_tracker::state_t::pending) { - result = *e.second.policy; - result.apply_diff(diff); - return result; - } - } - for (const auto& e : finalizer_policies) { - if (e.second.state == finalizer_policy_tracker::state_t::proposed) { - result = *e.second.policy; - result.apply_diff(diff); - return result; - } - } - assert(false); + finalizer_policy result = get_last_proposed_finalizer_policy(); + result.apply_diff(diff); + return result; } // ------------------------------------------------------------------------------------------------- diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index 7e82b874da..c775de9d66 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -130,6 +130,7 @@ struct block_header_state { const vector& get_new_protocol_feature_activations() const; const producer_authority& get_scheduled_producer(block_timestamp_type t) const; + const finalizer_policy& get_last_proposed_finalizer_policy() const; finalizer_policy_diff calculate_finalizer_policy_diff(const finalizer_policy& new_policy) const; finalizer_policy calculate_finalizer_policy(const finalizer_policy_diff& diff) const; }; From b9d2d479abfd5004d1ce28cd2d4afe500c3b8c41 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 9 May 2024 14:43:30 -0500 Subject: [PATCH 18/19] GH-5 Fix static_assert --- libraries/chain/include/eosio/chain/config.hpp | 2 +- .../chain/include/eosio/chain/finality/finalizer_policy.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index c82d6c8c05..1712ef7685 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -134,7 +134,7 @@ static_assert(maximum_tracked_dpos_confirmations >= ((max_producers * 2 / 3) + 1 /** * Maximum number of finalizers in the finalizer set */ -const static size_t max_finalizers = 65535; // largest allowed finalizer policy diff +const static size_t max_finalizers = 64*1024; // largest allowed finalizer policy diff const static size_t max_finalizer_description_size = 256; /** diff --git a/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp b/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp index 2637cd90c3..9a616ba1d0 100644 --- a/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp +++ b/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp @@ -6,7 +6,7 @@ namespace eosio::chain { - static_assert(std::numeric_limits::max() <= config::max_finalizers); + static_assert(std::numeric_limits::max() >= config::max_finalizers - 1); using finalizers_differ = fc::ordered_diff; using finalizers_diff_t = finalizers_differ::diff_result; From f69c2b7eaf9185879945696875cc135f56a0c1c7 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 9 May 2024 14:43:59 -0500 Subject: [PATCH 19/19] GH-5 rename lambda --- unittests/finalizer_update_tests.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/unittests/finalizer_update_tests.cpp b/unittests/finalizer_update_tests.cpp index bd043170a8..db71dfa21c 100644 --- a/unittests/finalizer_update_tests.cpp +++ b/unittests/finalizer_update_tests.cpp @@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(savanna_set_finalizer_multiple_test) { try { size_t num_keys = 50u; size_t finset_size = 21u; - auto verify_block_finality_generation = [](const signed_block_ptr& block, uint32_t gen, const bls_public_key& key) { + auto verify_block_finality_policy_diff = [](const signed_block_ptr& block, uint32_t gen, const bls_public_key& key) { std::optional ext = block->extract_header_extension(instant_finality_extension::extension_id()); BOOST_TEST(!!ext); std::optional fin_policy_diff = std::get(*ext).new_finalizer_policy_diff; @@ -109,38 +109,38 @@ BOOST_AUTO_TEST_CASE(savanna_set_finalizer_multiple_test) { try { // ------------------------------------------------------------------------------ auto pubkeys3 = fin_keys.set_finalizer_policy(3u).pubkeys; auto b = t.produce_block(); - verify_block_finality_generation(b, 3, pubkeys3.back()); + verify_block_finality_policy_diff(b, 3, pubkeys3.back()); auto pubkeys4 = fin_keys.set_finalizer_policy(4u).pubkeys; b = t.produce_block(); - verify_block_finality_generation(b, 4, pubkeys4.back()); + verify_block_finality_policy_diff(b, 4, pubkeys4.back()); t.produce_block(); auto pubkeys5 = fin_keys.set_finalizer_policy(5u).pubkeys; b = t.produce_block(); - verify_block_finality_generation(b, 5, pubkeys5.back()); + verify_block_finality_policy_diff(b, 5, pubkeys5.back()); t.produce_block(); auto pubkeys6 = fin_keys.set_finalizer_policy(6u).pubkeys; b = t.produce_block(); - verify_block_finality_generation(b, 6, pubkeys6.back()); + verify_block_finality_policy_diff(b, 6, pubkeys6.back()); auto pubkeys7 = fin_keys.set_finalizer_policy(7u).pubkeys; t.check_head_finalizer_policy(2u, pubkeys2); // 5 blocks after pubkeys3 (b5 - b0), pubkeys2 should still be active b = t.produce_block(); - verify_block_finality_generation(b, 7, pubkeys7.back()); + verify_block_finality_policy_diff(b, 7, pubkeys7.back()); auto pubkeys8 = fin_keys.set_finalizer_policy(8u).pubkeys; t.check_head_finalizer_policy(3u, pubkeys3); // 6 blocks after pubkeys3 (b6 - b0), pubkeys3 should be active b = t.produce_block(); - verify_block_finality_generation(b, 8, pubkeys8.back()); + verify_block_finality_policy_diff(b, 8, pubkeys8.back()); auto pubkeys9 = fin_keys.set_finalizer_policy(9u).pubkeys; t.check_head_finalizer_policy(4u, pubkeys4); // 6 blocks after pubkeys4 (b7 - b1), pubkeys4 should be active b = t.produce_block(); - verify_block_finality_generation(b, 9, pubkeys9.back()); + verify_block_finality_policy_diff(b, 9, pubkeys9.back()); auto pubkeys10 = fin_keys.set_finalizer_policy(10u).pubkeys; t.check_head_finalizer_policy(4u, pubkeys4); // 7 blocks after pubkeys4, pubkeys4 should still be active b = t.produce_block(); - verify_block_finality_generation(b, 10, pubkeys10.back()); + verify_block_finality_policy_diff(b, 10, pubkeys10.back()); auto pubkeys11 = fin_keys.set_finalizer_policy(11u).pubkeys; t.check_head_finalizer_policy(5u, pubkeys5); // 6 blocks after pubkeys5 (b9 - b3), pubkeys5 should be active b = t.produce_block(); - verify_block_finality_generation(b, 11, pubkeys11.back()); + verify_block_finality_policy_diff(b, 11, pubkeys11.back()); t.produce_block(); // two blocks between 5 & 6 proposals t.check_head_finalizer_policy(6u, pubkeys6); // the rest are all one block apart, tests pending with propsed auto b12 = t.produce_block();