From 37e4b25d9c8b43ee45f2fb4920570b2f9ed78dfd Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 11 Dec 2023 09:58:24 -0500 Subject: [PATCH 01/94] add setfinalizer to eosio.bios --- .../include/eosio.bios/eosio.bios.hpp | 42 +++++++++++++++++++ contracts/eosio.bios/src/eosio.bios.cpp | 29 +++++++++++++ 2 files changed, 71 insertions(+) diff --git a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp index 643e562c..266da1be 100644 --- a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp +++ b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include namespace eosiobios { @@ -66,6 +67,35 @@ namespace eosiobios { (schedule_version)(new_producers)) }; + /** + * finalizer_authority + * + * The public bls key and proof of possession of private key signature, + * and vote weight of a finalizer. + */ + struct finalizer_authority { + std::string description; + uint64_t weight = 0; // weight that this finalizer's vote has for meeting threshold + std::string public_key; // public key of the finalizer in base64 format + std::string pop; // proof of possession of private key in base64 format + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE(finalizer_authority, (description)(weight)(public_key)(pop)) + }; + + /** + * finalizer_policy + * + * List of finalizer authorties along with the threshold + */ + struct finalizer_policy { + uint64_t threshold = 0; // quorum threshold + std::vector finalizers; + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE(finalizer_policy, (threshold)(finalizers)); + }; + /** * The `eosio.bios` is the first sample of system contract provided by `block.one` through the EOSIO platform. It is a minimalist system contract because it only supplies the actions that are absolutely critical to bootstrap a chain and nothing more. This allows for a chain agnostic approach to bootstrapping a chain. * @@ -190,6 +220,18 @@ namespace eosiobios { [[eosio::action]] void onerror( ignore sender_id, ignore> sent_trx ); + /** + * Set a new list of finalizer policy. + * + * @details Set a new list of active finalizer policy, by proposing a finalizer policy, once the block that + * contains the proposal becomes irreversible the new finalizer policy. will be made active according + * to Antelope finalizer active policy rules. Replaces existing finalizer policy.. + * + * @param finalizer_policy - New list of active finalizer policy. to set + */ + [[eosio::action]] + void setfinalizer( const finalizer_policy& finalizer_policy ); + /** * Set privilege action allows to set privilege status for an account (turn it on/off). * @param account - the account to set the privileged status for. diff --git a/contracts/eosio.bios/src/eosio.bios.cpp b/contracts/eosio.bios/src/eosio.bios.cpp index 69d6758f..570fdbeb 100644 --- a/contracts/eosio.bios/src/eosio.bios.cpp +++ b/contracts/eosio.bios/src/eosio.bios.cpp @@ -1,4 +1,5 @@ #include +#include namespace eosiobios { @@ -17,6 +18,34 @@ void bios::setabi( name account, const std::vector& abi ) { } } +void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { + require_auth( get_self() ); + check(finalizer_policy.finalizers.size() > 0, "require at least one finalizer"); + + eosio::abi_finalizer_policy abi_finalizer_policy; + abi_finalizer_policy.fthreshold = finalizer_policy.threshold; + abi_finalizer_policy.finalizers.reserve(finalizer_policy.finalizers.size()); + + const std::string pk_prefix = "PUB_BLS"; + const std::string sig_prefix = "SIG_BLS"; + + for (const auto& f: finalizer_policy.finalizers) { + // basic key format checks + check(f.public_key.substr(0, pk_prefix.length()) == pk_prefix, "public key not started with PUB_BLS"); + check(f.pop.substr(0, sig_prefix.length()) == sig_prefix, "proof of possession signature not started with SIG_BLS"); + + // proof of possession of private key check + const auto pk = eosio::decode_bls_public_key_to_g1(f.public_key); + const auto signature = eosio::decode_bls_signature_to_g2(f.pop); + check(eosio::bls_pop_verify(pk, signature), "proof of possession failed"); + + const std::vector pk_vector(pk.begin(), pk.end()); + abi_finalizer_policy.finalizers.emplace_back(eosio::abi_finalizer_authority{f.description, f.weight, pk_vector}); + } + + set_finalizers(abi_finalizer_policy); +} + void bios::onerror( ignore, ignore> ) { check( false, "the onerror action cannot be called directly" ); } From 6eac8c2a44ee26ba8597dbde7aa43a55be96eca2 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 11 Dec 2023 10:14:10 -0500 Subject: [PATCH 02/94] add tests for eosio.bios setfinalizer action --- tests/CMakeLists.txt | 2 +- tests/eosio.bios_inst_fin_tests.cpp | 126 ++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 tests/eosio.bios_inst_fin_tests.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8c0ab125..86cb70a7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.5) set(EOSIO_VERSION_MIN "3.1") -set(EOSIO_VERSION_SOFT_MAX "4.1") +set(EOSIO_VERSION_SOFT_MAX "5.0") # set(EOSIO_VERSION_HARD_MAX "") find_package(leap) diff --git a/tests/eosio.bios_inst_fin_tests.cpp b/tests/eosio.bios_inst_fin_tests.cpp new file mode 100644 index 00000000..5e6a70f0 --- /dev/null +++ b/tests/eosio.bios_inst_fin_tests.cpp @@ -0,0 +1,126 @@ +#include +#include +#include + +#include + +#include "contracts.hpp" + +using namespace eosio::testing; +using namespace eosio; +using namespace eosio::chain; +using namespace eosio::testing; +using namespace fc; + +using mvo = fc::mutable_variant_object; + +class eosio_bios_if_tester : public tester { +public: + + eosio_bios_if_tester() { + create_accounts( { "iftester"_n } ); + produce_block(); + + base_tester::push_action(config::system_account_name, "setpriv"_n, + config::system_account_name, mutable_variant_object() + ("account", "iftester") + ("is_priv", 1) + ); + + set_code( "iftester"_n, contracts::bios_wasm() ); + set_abi( "iftester"_n, contracts::bios_abi().data() ); + produce_block(); + } +}; + +BOOST_AUTO_TEST_SUITE(eosio_bios_if_tests) + +BOOST_FIXTURE_TEST_CASE( set_1_finalizer, eosio_bios_if_tester ) try { + push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() + ("finalizer_policy", mvo()("threshold", 2) + ("finalizers", std::vector{mvo() + ("description", "set_1_finalizer") + ("weight", 1) + ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") + ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))); + signed_block_ptr cur_block = produce_block(); + fc::variant pretty_output; + abi_serializer::to_variant( *cur_block, pretty_output, get_resolver(), fc::microseconds::maximum() ); + BOOST_REQUIRE(pretty_output.get_object().contains("proposed_finalizer_policy")); + BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["generation"], 1); + BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["fthreshold"], 2); + BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"].size(), 1u); + BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"][size_t(0)]["description"], "set_1_finalizer"); + BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"][size_t(0)]["fweight"], 1); + BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"][size_t(0)]["public_key"], "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ=="); +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( set_2_finalizers, eosio_bios_if_tester ) try { + push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() + ("finalizer_policy", mvo()("threshold", 4) + ("finalizers", std::vector{mvo() + ("description", "set_2_finalizer_1") + ("weight", 1) + ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") + ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg=="), + + mvo()("description", "set_2_finalizer_2") + ("weight", 2) + ("public_key", "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw==") + ("pop", "SIG_BLS_bFLCSmXqVrFqWo2mqxCeuLO5iAevMu/8qxpS7HkXSMmXuVLEytt+shDHn8FpcrUMlMHjxEAHOyRVi0ckvXYrCpHMx6floRvljJ1vV2FphGqgm24DxuB1BE3E21Okc0QS3GH6UCISfVBXuqoK+EfmoSGz3ssi0kzevE8MQitzGgK9EW3zTlZtvdRryI1OTUoUXkjTo1Q2VQIbqJZ55W7SNHUcIBZO5Ih4AXc7usjWUBXv1BK0NNcort4EAfOXnkIN47iRLQ==") + }))); + + signed_block_ptr cur_block = produce_block(); + fc::variant pretty_output; + abi_serializer::to_variant( *cur_block, pretty_output, get_resolver(), fc::microseconds::maximum() ); + BOOST_REQUIRE(pretty_output.get_object().contains("proposed_finalizer_policy")); + BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["generation"], 1); + BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["fthreshold"], 4); + BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"].size(), 2u); + BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"][size_t(1)]["description"], "set_2_finalizer_2"); + BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"][size_t(1)]["fweight"], 2); + BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"][size_t(1)]["public_key"], "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw=="); +} FC_LOG_AND_RETHROW() + + +BOOST_FIXTURE_TEST_CASE( empty_finalizers, eosio_bios_if_tester ) try { + BOOST_REQUIRE_THROW(push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() + ("finalizer_policy", mvo()("threshold", 2) + ("finalizers", std::vector{}))), eosio_assert_message_exception); +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( public_key_not_started_with_PUB_BLS, eosio_bios_if_tester ) try { + BOOST_REQUIRE_THROW(push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() + ("finalizer_policy", mvo()("threshold", 2) + ("finalizers", std::vector{mvo() + ("description", "set_1_finalizer") + ("weight", 1) + // PUB_BLS to UB_BLS + ("public_key", "UB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") + ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( signature_not_started_with_SIG_BLS, eosio_bios_if_tester ) try { + BOOST_REQUIRE_THROW(push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() + ("finalizer_policy", mvo()("threshold", 2) + ("finalizers", std::vector{mvo() + ("description", "set_1_finalizer") + ("weight", 1) + ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") + // SIG_BLS changed to SIG_BL + ("pop", "SIG_BL_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); +} FC_LOG_AND_RETHROW() + + +BOOST_FIXTURE_TEST_CASE( pop_failed, eosio_bios_if_tester ) try { + BOOST_REQUIRE_THROW(push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() + ("finalizer_policy", mvo()("threshold", 2) + ("finalizers", std::vector{mvo() + ("description", "set_1_finalizer") + ("weight", 1) + ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") + // SIG_BLS_q changed to SIG_BLS_j + ("pop", "SIG_BLS_jxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() From 7181593c84756d2f72b283e1df472478a59389d4 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 11 Dec 2023 10:47:49 -0500 Subject: [PATCH 03/94] add more comments to eosio.bios setfinalizer tests --- tests/eosio.bios_inst_fin_tests.cpp | 53 ++++++++++++++++++----------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/tests/eosio.bios_inst_fin_tests.cpp b/tests/eosio.bios_inst_fin_tests.cpp index 5e6a70f0..291cb40a 100644 --- a/tests/eosio.bios_inst_fin_tests.cpp +++ b/tests/eosio.bios_inst_fin_tests.cpp @@ -14,6 +14,7 @@ using namespace fc; using mvo = fc::mutable_variant_object; +// tests for instant finality actions class eosio_bios_if_tester : public tester { public: @@ -21,6 +22,7 @@ class eosio_bios_if_tester : public tester { create_accounts( { "iftester"_n } ); produce_block(); + // instant finality actions are previlidged base_tester::push_action(config::system_account_name, "setpriv"_n, config::system_account_name, mutable_variant_object() ("account", "iftester") @@ -35,17 +37,23 @@ class eosio_bios_if_tester : public tester { BOOST_AUTO_TEST_SUITE(eosio_bios_if_tests) +// one finalizer in finalizer policy BOOST_FIXTURE_TEST_CASE( set_1_finalizer, eosio_bios_if_tester ) try { + // public_key and pop are generated by leap-util push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() - ("finalizer_policy", mvo()("threshold", 2) - ("finalizers", std::vector{mvo() - ("description", "set_1_finalizer") - ("weight", 1) - ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") - ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))); + ("finalizer_policy", mvo() + ("threshold", 2) + ("finalizers", std::vector{ + mvo() + ("description", "set_1_finalizer") + ("weight", 1) + ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") + ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))); + signed_block_ptr cur_block = produce_block(); fc::variant pretty_output; abi_serializer::to_variant( *cur_block, pretty_output, get_resolver(), fc::microseconds::maximum() ); + BOOST_REQUIRE(pretty_output.get_object().contains("proposed_finalizer_policy")); BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["generation"], 1); BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["fthreshold"], 2); @@ -55,24 +63,29 @@ BOOST_FIXTURE_TEST_CASE( set_1_finalizer, eosio_bios_if_tester ) try { BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"][size_t(0)]["public_key"], "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ=="); } FC_LOG_AND_RETHROW() +// two finalizers in finalizer policy BOOST_FIXTURE_TEST_CASE( set_2_finalizers, eosio_bios_if_tester ) try { + // public_key and pop are generated by leap-util push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() - ("finalizer_policy", mvo()("threshold", 4) - ("finalizers", std::vector{mvo() - ("description", "set_2_finalizer_1") - ("weight", 1) - ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") - ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg=="), - - mvo()("description", "set_2_finalizer_2") - ("weight", 2) - ("public_key", "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw==") - ("pop", "SIG_BLS_bFLCSmXqVrFqWo2mqxCeuLO5iAevMu/8qxpS7HkXSMmXuVLEytt+shDHn8FpcrUMlMHjxEAHOyRVi0ckvXYrCpHMx6floRvljJ1vV2FphGqgm24DxuB1BE3E21Okc0QS3GH6UCISfVBXuqoK+EfmoSGz3ssi0kzevE8MQitzGgK9EW3zTlZtvdRryI1OTUoUXkjTo1Q2VQIbqJZ55W7SNHUcIBZO5Ih4AXc7usjWUBXv1BK0NNcort4EAfOXnkIN47iRLQ==") + ("finalizer_policy", mvo() + ("threshold", 4) + ("finalizers", std::vector{ + mvo() + ("description", "set_2_finalizer_1") + ("weight", 1) + ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") + ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg=="), + mvo() + ("description", "set_2_finalizer_2") + ("weight", 2) + ("public_key", "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw==") + ("pop", "SIG_BLS_bFLCSmXqVrFqWo2mqxCeuLO5iAevMu/8qxpS7HkXSMmXuVLEytt+shDHn8FpcrUMlMHjxEAHOyRVi0ckvXYrCpHMx6floRvljJ1vV2FphGqgm24DxuB1BE3E21Okc0QS3GH6UCISfVBXuqoK+EfmoSGz3ssi0kzevE8MQitzGgK9EW3zTlZtvdRryI1OTUoUXkjTo1Q2VQIbqJZ55W7SNHUcIBZO5Ih4AXc7usjWUBXv1BK0NNcort4EAfOXnkIN47iRLQ==") }))); signed_block_ptr cur_block = produce_block(); fc::variant pretty_output; abi_serializer::to_variant( *cur_block, pretty_output, get_resolver(), fc::microseconds::maximum() ); + BOOST_REQUIRE(pretty_output.get_object().contains("proposed_finalizer_policy")); BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["generation"], 1); BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["fthreshold"], 4); @@ -82,13 +95,14 @@ BOOST_FIXTURE_TEST_CASE( set_2_finalizers, eosio_bios_if_tester ) try { BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"][size_t(1)]["public_key"], "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw=="); } FC_LOG_AND_RETHROW() - +// finalizer cannot be empty BOOST_FIXTURE_TEST_CASE( empty_finalizers, eosio_bios_if_tester ) try { BOOST_REQUIRE_THROW(push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() ("finalizer_policy", mvo()("threshold", 2) ("finalizers", std::vector{}))), eosio_assert_message_exception); } FC_LOG_AND_RETHROW() +// public_key must start with PUB_BLS BOOST_FIXTURE_TEST_CASE( public_key_not_started_with_PUB_BLS, eosio_bios_if_tester ) try { BOOST_REQUIRE_THROW(push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() ("finalizer_policy", mvo()("threshold", 2) @@ -100,6 +114,7 @@ BOOST_FIXTURE_TEST_CASE( public_key_not_started_with_PUB_BLS, eosio_bios_if_test ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); } FC_LOG_AND_RETHROW() +// pop signature must start with SIG_BLS BOOST_FIXTURE_TEST_CASE( signature_not_started_with_SIG_BLS, eosio_bios_if_tester ) try { BOOST_REQUIRE_THROW(push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() ("finalizer_policy", mvo()("threshold", 2) @@ -111,7 +126,7 @@ BOOST_FIXTURE_TEST_CASE( signature_not_started_with_SIG_BLS, eosio_bios_if_teste ("pop", "SIG_BL_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); } FC_LOG_AND_RETHROW() - +// test to verify POP verification failure BOOST_FIXTURE_TEST_CASE( pop_failed, eosio_bios_if_tester ) try { BOOST_REQUIRE_THROW(push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() ("finalizer_policy", mvo()("threshold", 2) From 0d5cc0dd671a327cb10cdc1917f0c94b78d42b3a Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 11 Dec 2023 11:23:44 -0500 Subject: [PATCH 04/94] update Leap and CDT versions for CICD --- .cicd/defaults.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.cicd/defaults.json b/.cicd/defaults.json index ff3a3dbc..136b822d 100644 --- a/.cicd/defaults.json +++ b/.cicd/defaults.json @@ -1,10 +1,10 @@ { "leap-dev":{ - "target":"3", + "target":"hotstuff_integration", "prerelease":false }, "cdt":{ - "target":"3", + "target":"hotstuff_integration", "prerelease":false } } From f91b47fa858fdac88841c57ba79939b584feedb4 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 11 Dec 2023 13:23:42 -0500 Subject: [PATCH 05/94] use std::move for argument passing --- contracts/eosio.bios/src/eosio.bios.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/eosio.bios/src/eosio.bios.cpp b/contracts/eosio.bios/src/eosio.bios.cpp index 570fdbeb..6a6e1b2a 100644 --- a/contracts/eosio.bios/src/eosio.bios.cpp +++ b/contracts/eosio.bios/src/eosio.bios.cpp @@ -39,11 +39,11 @@ void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { const auto signature = eosio::decode_bls_signature_to_g2(f.pop); check(eosio::bls_pop_verify(pk, signature), "proof of possession failed"); - const std::vector pk_vector(pk.begin(), pk.end()); - abi_finalizer_policy.finalizers.emplace_back(eosio::abi_finalizer_authority{f.description, f.weight, pk_vector}); + std::vector pk_vector(pk.begin(), pk.end()); + abi_finalizer_policy.finalizers.emplace_back(eosio::abi_finalizer_authority{f.description, f.weight, std::move(pk_vector)}); } - set_finalizers(abi_finalizer_policy); + set_finalizers(std::move(abi_finalizer_policy)); } void bios::onerror( ignore, ignore> ) { From 4e31832506709b9ae91ba6ce913bc613f9c1506a Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 11 Dec 2023 13:33:09 -0500 Subject: [PATCH 06/94] correct a typo of privileged --- tests/eosio.bios_inst_fin_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/eosio.bios_inst_fin_tests.cpp b/tests/eosio.bios_inst_fin_tests.cpp index 291cb40a..4733340c 100644 --- a/tests/eosio.bios_inst_fin_tests.cpp +++ b/tests/eosio.bios_inst_fin_tests.cpp @@ -22,7 +22,7 @@ class eosio_bios_if_tester : public tester { create_accounts( { "iftester"_n } ); produce_block(); - // instant finality actions are previlidged + // instant finality actions are privileged base_tester::push_action(config::system_account_name, "setpriv"_n, config::system_account_name, mutable_variant_object() ("account", "iftester") From 37c4dc3bbd3d6ee23f892af37ece60457724475a Mon Sep 17 00:00:00 2001 From: Lin Huang <107445030+linh2931@users.noreply.github.com> Date: Mon, 11 Dec 2023 15:14:09 -0500 Subject: [PATCH 07/94] update CDT asset-artifact-download-action from v2 to v3 --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 1b211e8a..fb0af03a 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -62,7 +62,7 @@ jobs: echo cdt-prerelease=${{inputs.override-cdt-prerelease}} >> $GITHUB_OUTPUT fi - name: Download cdt - uses: AntelopeIO/asset-artifact-download-action@v2 + uses: AntelopeIO/asset-artifact-download-action@v3 with: owner: AntelopeIO repo: cdt From da83307b73802f0cdb349ff24f2c3d1f640db130 Mon Sep 17 00:00:00 2001 From: Lin Huang <107445030+linh2931@users.noreply.github.com> Date: Mon, 11 Dec 2023 18:23:07 -0500 Subject: [PATCH 08/94] add apt-get update && apt-get upgrade -y before apt install --- .github/workflows/build.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index fb0af03a..a9a399ee 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -84,6 +84,7 @@ jobs: token: ${{github.token}} - name: Install packages run: | + sudo apt-get update && sudo apt-get upgrade -y sudo apt install ./*.deb sudo apt-get install cmake rm ./*.deb From d9dceab2fd3cf5efd030cd7c6c98957dad0e1564 Mon Sep 17 00:00:00 2001 From: Lin Huang <107445030+linh2931@users.noreply.github.com> Date: Mon, 11 Dec 2023 20:01:19 -0500 Subject: [PATCH 09/94] change leap-dev asset-artifact-download-action to v3 --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index a9a399ee..157dfca2 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -72,7 +72,7 @@ jobs: artifact-name: cdt_ubuntu_package_amd64 token: ${{github.token}} - name: Download leap-dev - uses: AntelopeIO/asset-artifact-download-action@v2 + uses: AntelopeIO/asset-artifact-download-action@v3 with: owner: AntelopeIO repo: leap From 5b3c58e4bda3bd334b2607d5745ee674adefea4f Mon Sep 17 00:00:00 2001 From: Lin Huang <107445030+linh2931@users.noreply.github.com> Date: Mon, 11 Dec 2023 20:23:14 -0500 Subject: [PATCH 10/94] remove token usage --- .github/workflows/build.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 157dfca2..9530f87f 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -70,7 +70,6 @@ jobs: target: '${{steps.versions.outputs.cdt-target}}' prereleases: ${{fromJSON(steps.versions.outputs.cdt-prerelease)}} artifact-name: cdt_ubuntu_package_amd64 - token: ${{github.token}} - name: Download leap-dev uses: AntelopeIO/asset-artifact-download-action@v3 with: @@ -81,7 +80,6 @@ jobs: prereleases: ${{fromJSON(steps.versions.outputs.leap-dev-prerelease)}} artifact-name: leap-dev-ubuntu20-amd64 container-package: experimental-binaries - token: ${{github.token}} - name: Install packages run: | sudo apt-get update && sudo apt-get upgrade -y From d7f7616c845bf0179d90aab07daec094cb0b25a5 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 13 Dec 2023 11:31:45 -0500 Subject: [PATCH 11/94] correct comments about setfinalizer and add max_finalizers and max_finalizer_description_size definition --- .../eosio.bios/include/eosio.bios/eosio.bios.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp index 266da1be..7ee9e45a 100644 --- a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp +++ b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp @@ -73,6 +73,9 @@ namespace eosiobios { * The public bls key and proof of possession of private key signature, * and vote weight of a finalizer. */ + constexpr size_t max_finalizers = 64*1024; + constexpr size_t max_finalizer_description_size = 256; + struct finalizer_authority { std::string description; uint64_t weight = 0; // weight that this finalizer's vote has for meeting threshold @@ -221,13 +224,10 @@ namespace eosiobios { void onerror( ignore sender_id, ignore> sent_trx ); /** - * Set a new list of finalizer policy. - * - * @details Set a new list of active finalizer policy, by proposing a finalizer policy, once the block that - * contains the proposal becomes irreversible the new finalizer policy. will be made active according - * to Antelope finalizer active policy rules. Replaces existing finalizer policy.. + * Propose new finalizer policy that, unless superseded by a later + * finalizer policy, will eventually become the active finalizer policy. * - * @param finalizer_policy - New list of active finalizer policy. to set + * @param finalizer_policy - proposed finalizer policy */ [[eosio::action]] void setfinalizer( const finalizer_policy& finalizer_policy ); From 312f46adff04e1f2a421a3b4b4d0219346913132 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 13 Dec 2023 11:34:04 -0500 Subject: [PATCH 12/94] add checks for duplicate keys, too small threshold, weight sum overflow, max_finalizers, and max_finalizer_description_size --- contracts/eosio.bios/src/eosio.bios.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/contracts/eosio.bios/src/eosio.bios.cpp b/contracts/eosio.bios/src/eosio.bios.cpp index 6a6e1b2a..13d6db91 100644 --- a/contracts/eosio.bios/src/eosio.bios.cpp +++ b/contracts/eosio.bios/src/eosio.bios.cpp @@ -1,6 +1,8 @@ #include #include +#include + namespace eosiobios { void bios::setabi( name account, const std::vector& abi ) { @@ -19,7 +21,12 @@ void bios::setabi( name account, const std::vector& abi ) { } void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { + // exensive checks are performed to make sure setfinalizer host function + // will never fail + require_auth( get_self() ); + + check(finalizer_policy.finalizers.size() <= max_finalizers, "number of finalizers exceeds the maximum allowed"); check(finalizer_policy.finalizers.size() > 0, "require at least one finalizer"); eosio::abi_finalizer_policy abi_finalizer_policy; @@ -29,20 +36,36 @@ void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { const std::string pk_prefix = "PUB_BLS"; const std::string sig_prefix = "SIG_BLS"; + std::unordered_set unique_finalizer_keys; + uint64_t weight_sum = 0; + for (const auto& f: finalizer_policy.finalizers) { + check(f.description.size() <= max_finalizer_description_size, "Finalizer description greater than max allowed size"); + // basic key format checks check(f.public_key.substr(0, pk_prefix.length()) == pk_prefix, "public key not started with PUB_BLS"); check(f.pop.substr(0, sig_prefix.length()) == sig_prefix, "proof of possession signature not started with SIG_BLS"); - // proof of possession of private key check + // duplicate key check + check(unique_finalizer_keys.insert(f.public_key).second, "duplicate public keys"); + + // check overflow + check(std::numeric_limits::max() - weight_sum >= f.weight, "sum of weights causes uint64_t overflow"); + weight_sum += f.weight; + + // decode_bls_public_key_to_g1 and decode_bls_signature_to_g2 + // will throw ("check" function fails) if keys are not valid const auto pk = eosio::decode_bls_public_key_to_g1(f.public_key); const auto signature = eosio::decode_bls_signature_to_g2(f.pop); + // proof of possession of private key check check(eosio::bls_pop_verify(pk, signature), "proof of possession failed"); std::vector pk_vector(pk.begin(), pk.end()); abi_finalizer_policy.finalizers.emplace_back(eosio::abi_finalizer_authority{f.description, f.weight, std::move(pk_vector)}); } + check(finalizer_policy.threshold > weight_sum / 2, "finalizer policy threshold cannot be met by finalizer weights"); + set_finalizers(std::move(abi_finalizer_policy)); } From d5bf2414283ce902c3d13b06bbc823ddb3b2437c Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 13 Dec 2023 11:34:25 -0500 Subject: [PATCH 13/94] add additional tests for setfinalizer input validation --- tests/eosio.bios_inst_fin_tests.cpp | 69 +++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/tests/eosio.bios_inst_fin_tests.cpp b/tests/eosio.bios_inst_fin_tests.cpp index 4733340c..f1c145cf 100644 --- a/tests/eosio.bios_inst_fin_tests.cpp +++ b/tests/eosio.bios_inst_fin_tests.cpp @@ -138,4 +138,73 @@ BOOST_FIXTURE_TEST_CASE( pop_failed, eosio_bios_if_tester ) try { ("pop", "SIG_BLS_jxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); } FC_LOG_AND_RETHROW() +// Verifies threshold must be greater than half the sum of the weights +BOOST_FIXTURE_TEST_CASE( threshold_equal_to_half_weights, eosio_bios_if_tester ) try { + BOOST_REQUIRE_THROW(push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() + ("finalizer_policy", mvo() + ("threshold", 5) + ("finalizers", std::vector{ + mvo() + ("description", "set_2_finalizer_1") + ("weight", 5) + ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") + ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg=="), + mvo() + ("description", "set_2_finalizer_2") + ("weight", 5) + ("public_key", "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw==") + ("pop", "SIG_BLS_bFLCSmXqVrFqWo2mqxCeuLO5iAevMu/8qxpS7HkXSMmXuVLEytt+shDHn8FpcrUMlMHjxEAHOyRVi0ckvXYrCpHMx6floRvljJ1vV2FphGqgm24DxuB1BE3E21Okc0QS3GH6UCISfVBXuqoK+EfmoSGz3ssi0kzevE8MQitzGgK9EW3zTlZtvdRryI1OTUoUXkjTo1Q2VQIbqJZ55W7SNHUcIBZO5Ih4AXc7usjWUBXv1BK0NNcort4EAfOXnkIN47iRLQ==") + }))), eosio_assert_message_exception); +} FC_LOG_AND_RETHROW() + +// Verifies threshold greater by one than half of the sum of the weights works +BOOST_FIXTURE_TEST_CASE( threshold_greater_than_by_one_half_weights, eosio_bios_if_tester ) try { + BOOST_REQUIRE_NO_THROW(push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() + ("finalizer_policy", mvo() + ("threshold", 6) + ("finalizers", std::vector{ + mvo() + ("description", "set_2_finalizer_1") + ("weight", 5) + ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") + ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg=="), + mvo() + ("description", "set_2_finalizer_2") + ("weight", 5) + ("public_key", "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw==") + ("pop", "SIG_BLS_bFLCSmXqVrFqWo2mqxCeuLO5iAevMu/8qxpS7HkXSMmXuVLEytt+shDHn8FpcrUMlMHjxEAHOyRVi0ckvXYrCpHMx6floRvljJ1vV2FphGqgm24DxuB1BE3E21Okc0QS3GH6UCISfVBXuqoK+EfmoSGz3ssi0kzevE8MQitzGgK9EW3zTlZtvdRryI1OTUoUXkjTo1Q2VQIbqJZ55W7SNHUcIBZO5Ih4AXc7usjWUBXv1BK0NNcort4EAfOXnkIN47iRLQ==") + })))); +} FC_LOG_AND_RETHROW() + +// Verifies no duplicate keys are allowed +BOOST_FIXTURE_TEST_CASE( duplicate_pub_keys, eosio_bios_if_tester ) try { + BOOST_REQUIRE_THROW(push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() + ("finalizer_policy", mvo() + ("threshold", 10) + ("finalizers", std::vector{ + mvo() + ("description", "set_2_finalizer_1") + ("weight", 5) + ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") + ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg=="), + mvo() + ("description", "set_2_finalizer_2") + ("weight", 5) + ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") + ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg=="), + }))), eosio_assert_message_exception); +} FC_LOG_AND_RETHROW() + +// Verifies description cannot exceed maximum allowed size (256 chars) +BOOST_FIXTURE_TEST_CASE( long_description, eosio_bios_if_tester ) try { + BOOST_REQUIRE_THROW(push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() + ("finalizer_policy", mvo()("threshold", 2) + ("finalizers", std::vector{mvo() + // 257 chars long + ("description", "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456") + ("weight", 1) + ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") + ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); +} FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() From 8676a921269c6d599064a357db345672c5415022 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 13 Dec 2023 13:28:56 -0500 Subject: [PATCH 14/94] simplify building long description in tests and add a test for description length equal to max allowed size --- tests/eosio.bios_inst_fin_tests.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/eosio.bios_inst_fin_tests.cpp b/tests/eosio.bios_inst_fin_tests.cpp index f1c145cf..625e6398 100644 --- a/tests/eosio.bios_inst_fin_tests.cpp +++ b/tests/eosio.bios_inst_fin_tests.cpp @@ -200,11 +200,21 @@ BOOST_FIXTURE_TEST_CASE( long_description, eosio_bios_if_tester ) try { BOOST_REQUIRE_THROW(push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() ("finalizer_policy", mvo()("threshold", 2) ("finalizers", std::vector{mvo() - // 257 chars long - ("description", "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456") + ("description", std::string(257, 'a')) ("weight", 1) ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); } FC_LOG_AND_RETHROW() +// Verifies description equal to maximum allowed size (256 chars) +BOOST_FIXTURE_TEST_CASE( description_size_equal_to_max, eosio_bios_if_tester ) try { + BOOST_REQUIRE_NO_THROW(push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() + ("finalizer_policy", mvo()("threshold", 2) + ("finalizers", std::vector{mvo() + ("description", std::string(256, 'a')) + ("weight", 1) + ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") + ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")})))); +} FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() From ac597eaa21fae956cd95f7001a2b0b9d3d367f33 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 13 Dec 2023 17:47:44 -0500 Subject: [PATCH 15/94] use affine raw format for key uniqueness check --- contracts/eosio.bios/src/eosio.bios.cpp | 29 ++++++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/contracts/eosio.bios/src/eosio.bios.cpp b/contracts/eosio.bios/src/eosio.bios.cpp index 13d6db91..1988578c 100644 --- a/contracts/eosio.bios/src/eosio.bios.cpp +++ b/contracts/eosio.bios/src/eosio.bios.cpp @@ -20,6 +20,21 @@ void bios::setabi( name account, const std::vector& abi ) { } } +// helpers for defining std::unordered_set +struct g1_hash { + // bls_g1 is defined as std::array + std::size_t operator()(const eosio::bls_g1& g1) const { + std::hash hash_func; + return hash_func(g1.data()); + } +}; + +struct g1_equal { + bool operator()(const eosio::bls_g1& lhs, const eosio::bls_g1& rhs) const { + return std::memcmp(lhs.data(), rhs.data(), 96 * sizeof(char)) == 0; + } +}; + void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { // exensive checks are performed to make sure setfinalizer host function // will never fail @@ -36,7 +51,8 @@ void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { const std::string pk_prefix = "PUB_BLS"; const std::string sig_prefix = "SIG_BLS"; - std::unordered_set unique_finalizer_keys; + // use raw affine format for uniqueness check + std::unordered_set unique_finalizer_keys; uint64_t weight_sum = 0; for (const auto& f: finalizer_policy.finalizers) { @@ -46,17 +62,18 @@ void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { check(f.public_key.substr(0, pk_prefix.length()) == pk_prefix, "public key not started with PUB_BLS"); check(f.pop.substr(0, sig_prefix.length()) == sig_prefix, "proof of possession signature not started with SIG_BLS"); - // duplicate key check - check(unique_finalizer_keys.insert(f.public_key).second, "duplicate public keys"); - // check overflow check(std::numeric_limits::max() - weight_sum >= f.weight, "sum of weights causes uint64_t overflow"); weight_sum += f.weight; - // decode_bls_public_key_to_g1 and decode_bls_signature_to_g2 - // will throw ("check" function fails) if keys are not valid + // decode_bls_public_key_to_g1 will fail ("check" function fails) + // if the key is invalid const auto pk = eosio::decode_bls_public_key_to_g1(f.public_key); + // duplicate key check + check(unique_finalizer_keys.insert(pk).second, "duplicate public key"); + const auto signature = eosio::decode_bls_signature_to_g2(f.pop); + // proof of possession of private key check check(eosio::bls_pop_verify(pk, signature), "proof of possession failed"); From 89672ac80f095ab8546557d3077a51afcd545cb0 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 14 Dec 2023 08:49:39 -0500 Subject: [PATCH 16/94] move g1_hash and g1_equal inside function body and next to their use, use std::hash for hashing, use size() instead of 96 * sizeof(char) --- contracts/eosio.bios/src/eosio.bios.cpp | 29 +++++++++++-------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/contracts/eosio.bios/src/eosio.bios.cpp b/contracts/eosio.bios/src/eosio.bios.cpp index 1988578c..a1a51e71 100644 --- a/contracts/eosio.bios/src/eosio.bios.cpp +++ b/contracts/eosio.bios/src/eosio.bios.cpp @@ -20,21 +20,6 @@ void bios::setabi( name account, const std::vector& abi ) { } } -// helpers for defining std::unordered_set -struct g1_hash { - // bls_g1 is defined as std::array - std::size_t operator()(const eosio::bls_g1& g1) const { - std::hash hash_func; - return hash_func(g1.data()); - } -}; - -struct g1_equal { - bool operator()(const eosio::bls_g1& lhs, const eosio::bls_g1& rhs) const { - return std::memcmp(lhs.data(), rhs.data(), 96 * sizeof(char)) == 0; - } -}; - void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { // exensive checks are performed to make sure setfinalizer host function // will never fail @@ -51,8 +36,20 @@ void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { const std::string pk_prefix = "PUB_BLS"; const std::string sig_prefix = "SIG_BLS"; - // use raw affine format for uniqueness check + // use raw affine format (bls_g1 is std::array) for uniqueness check + struct g1_hash { + std::size_t operator()(const eosio::bls_g1& g1) const { + std::hash hash_func; + return hash_func(g1.data()); + } + }; + struct g1_equal { + bool operator()(const eosio::bls_g1& lhs, const eosio::bls_g1& rhs) const { + return std::memcmp(lhs.data(), rhs.data(), lhs.size()) == 0; + } + }; std::unordered_set unique_finalizer_keys; + uint64_t weight_sum = 0; for (const auto& f: finalizer_policy.finalizers) { From afe749af1584bee01685e75dfe8c116a57eeafe8 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 19 Dec 2023 15:16:58 -0600 Subject: [PATCH 17/94] GH-34 Update set_finalizer errors --- contracts/eosio.bios/src/eosio.bios.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/eosio.bios/src/eosio.bios.cpp b/contracts/eosio.bios/src/eosio.bios.cpp index a1a51e71..69183a6b 100644 --- a/contracts/eosio.bios/src/eosio.bios.cpp +++ b/contracts/eosio.bios/src/eosio.bios.cpp @@ -56,8 +56,8 @@ void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { check(f.description.size() <= max_finalizer_description_size, "Finalizer description greater than max allowed size"); // basic key format checks - check(f.public_key.substr(0, pk_prefix.length()) == pk_prefix, "public key not started with PUB_BLS"); - check(f.pop.substr(0, sig_prefix.length()) == sig_prefix, "proof of possession signature not started with SIG_BLS"); + check(f.public_key.substr(0, pk_prefix.length()) == pk_prefix, "public key shoud start with PUB_BLS"); + check(f.pop.substr(0, sig_prefix.length()) == sig_prefix, "proof of possession signature should start with SIG_BLS"); // check overflow check(std::numeric_limits::max() - weight_sum >= f.weight, "sum of weights causes uint64_t overflow"); @@ -78,7 +78,7 @@ void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { abi_finalizer_policy.finalizers.emplace_back(eosio::abi_finalizer_authority{f.description, f.weight, std::move(pk_vector)}); } - check(finalizer_policy.threshold > weight_sum / 2, "finalizer policy threshold cannot be met by finalizer weights"); + check(finalizer_policy.threshold > weight_sum / 2, "finalizer policy threshold must be greater than half of the sum of the weights"); set_finalizers(std::move(abi_finalizer_policy)); } From a3ee2ed80c092bb17df6f4deca7f653d697086c1 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 5 Jan 2024 14:56:58 -0600 Subject: [PATCH 18/94] GH-37 Update to use controller active_producers(0 instead of accessing head_block_state. --- tests/eosio.system_tester.hpp | 6 +++--- tests/eosio.system_tests.cpp | 28 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 6eae96d2..a5c38be4 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -1024,9 +1024,9 @@ class eosio_system_tester : public TESTER { } produce_blocks( 250 ); - auto producer_keys = control->head_block_state()->active_schedule.producers; - BOOST_REQUIRE_EQUAL( 21, producer_keys.size() ); - BOOST_REQUIRE_EQUAL( name("defproducera"), producer_keys[0].producer_name ); + auto producer_keys = control->active_producers(); + BOOST_REQUIRE_EQUAL( 21, producer_keys.producers.size() ); + BOOST_REQUIRE_EQUAL( name("defproducera"), producer_keys.producers[0].producer_name ); return producer_names; } diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 7ae4ed68..3b37bbec 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3187,9 +3187,9 @@ BOOST_FIXTURE_TEST_CASE( elect_producers /*_and_parameters*/, eosio_system_teste //vote for producers BOOST_REQUIRE_EQUAL( success(), vote( "alice1111111"_n, { "defproducer1"_n } ) ); produce_blocks(250); - auto producer_keys = control->head_block_state()->active_schedule.producers; - BOOST_REQUIRE_EQUAL( 1, producer_keys.size() ); - BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_keys[0].producer_name ); + auto producer_keys = control->active_producers(); + BOOST_REQUIRE_EQUAL( 1, producer_keys.producers.size() ); + BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_keys.producers[0].producer_name ); //auto config = config_to_variant( control->get_global_properties().configuration ); //auto prod1_config = testing::filter_fields( config, producer_parameters_example( 1 ) ); @@ -3203,10 +3203,10 @@ BOOST_FIXTURE_TEST_CASE( elect_producers /*_and_parameters*/, eosio_system_teste BOOST_REQUIRE_EQUAL( success(), vote( "bob111111111"_n, { "defproducer2"_n } ) ); ilog("."); produce_blocks(250); - producer_keys = control->head_block_state()->active_schedule.producers; - BOOST_REQUIRE_EQUAL( 2, producer_keys.size() ); - BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_keys[0].producer_name ); - BOOST_REQUIRE_EQUAL( name("defproducer2"), producer_keys[1].producer_name ); + producer_keys = control->active_producers(); + BOOST_REQUIRE_EQUAL( 2, producer_keys.producers.size() ); + BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_keys.producers[0].producer_name ); + BOOST_REQUIRE_EQUAL( name("defproducer2"), producer_keys.producers[1].producer_name ); //config = config_to_variant( control->get_global_properties().configuration ); //auto prod2_config = testing::filter_fields( config, producer_parameters_example( 2 ) ); //REQUIRE_EQUAL_OBJECTS(prod2_config, config); @@ -3214,19 +3214,19 @@ BOOST_FIXTURE_TEST_CASE( elect_producers /*_and_parameters*/, eosio_system_teste // elect 3 producers BOOST_REQUIRE_EQUAL( success(), vote( "bob111111111"_n, { "defproducer2"_n, "defproducer3"_n } ) ); produce_blocks(250); - producer_keys = control->head_block_state()->active_schedule.producers; - BOOST_REQUIRE_EQUAL( 3, producer_keys.size() ); - BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_keys[0].producer_name ); - BOOST_REQUIRE_EQUAL( name("defproducer2"), producer_keys[1].producer_name ); - BOOST_REQUIRE_EQUAL( name("defproducer3"), producer_keys[2].producer_name ); + producer_keys = control->active_producers(); + BOOST_REQUIRE_EQUAL( 3, producer_keys.producers.size() ); + BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_keys.producers[0].producer_name ); + BOOST_REQUIRE_EQUAL( name("defproducer2"), producer_keys.producers[1].producer_name ); + BOOST_REQUIRE_EQUAL( name("defproducer3"), producer_keys.producers[2].producer_name ); //config = config_to_variant( control->get_global_properties().configuration ); //REQUIRE_EQUAL_OBJECTS(prod2_config, config); // try to go back to 2 producers and fail BOOST_REQUIRE_EQUAL( success(), vote( "bob111111111"_n, { "defproducer3"_n } ) ); produce_blocks(250); - producer_keys = control->head_block_state()->active_schedule.producers; - BOOST_REQUIRE_EQUAL( 3, producer_keys.size() ); + producer_keys = control->active_producers(); + BOOST_REQUIRE_EQUAL( 3, producer_keys.producers.size() ); // The test below is invalid now, producer schedule is not updated if there are // fewer producers in the new schedule From 5e95bc2fa6f413226f9ad8733f87c12f6cd2494e Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 5 Jan 2024 14:57:35 -0600 Subject: [PATCH 19/94] GH-37 Use cdt finalizer_authority --- contracts/eosio.bios/src/eosio.bios.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/eosio.bios/src/eosio.bios.cpp b/contracts/eosio.bios/src/eosio.bios.cpp index 69183a6b..cd8cb437 100644 --- a/contracts/eosio.bios/src/eosio.bios.cpp +++ b/contracts/eosio.bios/src/eosio.bios.cpp @@ -29,9 +29,9 @@ void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { check(finalizer_policy.finalizers.size() <= max_finalizers, "number of finalizers exceeds the maximum allowed"); check(finalizer_policy.finalizers.size() > 0, "require at least one finalizer"); - eosio::abi_finalizer_policy abi_finalizer_policy; - abi_finalizer_policy.fthreshold = finalizer_policy.threshold; - abi_finalizer_policy.finalizers.reserve(finalizer_policy.finalizers.size()); + eosio::finalizer_policy fin_policy; + fin_policy.threshold = finalizer_policy.threshold; + fin_policy.finalizers.reserve(finalizer_policy.finalizers.size()); const std::string pk_prefix = "PUB_BLS"; const std::string sig_prefix = "SIG_BLS"; @@ -75,12 +75,12 @@ void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { check(eosio::bls_pop_verify(pk, signature), "proof of possession failed"); std::vector pk_vector(pk.begin(), pk.end()); - abi_finalizer_policy.finalizers.emplace_back(eosio::abi_finalizer_authority{f.description, f.weight, std::move(pk_vector)}); + fin_policy.finalizers.emplace_back(eosio::finalizer_authority{f.description, f.weight, std::move(pk_vector)}); } check(finalizer_policy.threshold > weight_sum / 2, "finalizer policy threshold must be greater than half of the sum of the weights"); - set_finalizers(std::move(abi_finalizer_policy)); + set_finalizers(std::move(fin_policy)); } void bios::onerror( ignore, ignore> ) { From e28a8eeb62ffe75ce0cda8278be70e8cc65a9671 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 5 Jan 2024 15:16:49 -0600 Subject: [PATCH 20/94] GH-37 Update to ubuntu-22.04 --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 9530f87f..1d9d7733 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -36,7 +36,7 @@ defaults: jobs: build-test: name: Build & Test - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Setup leap-dev & cdt versions id: versions From 25d6b283cfcab196e6b1de7dcd9d488183765379 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 9 Jan 2024 07:03:55 -0600 Subject: [PATCH 21/94] GH-37 New block extension for instant finality --- tests/eosio.bios_inst_fin_tests.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/eosio.bios_inst_fin_tests.cpp b/tests/eosio.bios_inst_fin_tests.cpp index 625e6398..f8fc10f5 100644 --- a/tests/eosio.bios_inst_fin_tests.cpp +++ b/tests/eosio.bios_inst_fin_tests.cpp @@ -54,13 +54,13 @@ BOOST_FIXTURE_TEST_CASE( set_1_finalizer, eosio_bios_if_tester ) try { fc::variant pretty_output; abi_serializer::to_variant( *cur_block, pretty_output, get_resolver(), fc::microseconds::maximum() ); - BOOST_REQUIRE(pretty_output.get_object().contains("proposed_finalizer_policy")); - BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["generation"], 1); - BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["fthreshold"], 2); - BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"].size(), 1u); - BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"][size_t(0)]["description"], "set_1_finalizer"); - BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"][size_t(0)]["fweight"], 1); - BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"][size_t(0)]["public_key"], "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ=="); + BOOST_REQUIRE(pretty_output.get_object().contains("instant_finality_extension")); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["generation"], 1); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["threshold"], 2); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"].size(), 1u); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["description"], "set_1_finalizer"); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["weight"], 1); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["public_key"], "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ=="); } FC_LOG_AND_RETHROW() // two finalizers in finalizer policy @@ -86,13 +86,13 @@ BOOST_FIXTURE_TEST_CASE( set_2_finalizers, eosio_bios_if_tester ) try { fc::variant pretty_output; abi_serializer::to_variant( *cur_block, pretty_output, get_resolver(), fc::microseconds::maximum() ); - BOOST_REQUIRE(pretty_output.get_object().contains("proposed_finalizer_policy")); - BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["generation"], 1); - BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["fthreshold"], 4); - BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"].size(), 2u); - BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"][size_t(1)]["description"], "set_2_finalizer_2"); - BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"][size_t(1)]["fweight"], 2); - BOOST_REQUIRE_EQUAL(pretty_output["proposed_finalizer_policy"]["finalizers"][size_t(1)]["public_key"], "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw=="); + BOOST_REQUIRE(pretty_output.get_object().contains("instant_finality_extension")); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["generation"], 1); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["threshold"], 4); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"].size(), 2u); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["description"], "set_2_finalizer_2"); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["weight"], 2); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["public_key"], "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw=="); } FC_LOG_AND_RETHROW() // finalizer cannot be empty From cae6ac4246613783e6d0aada424e63afea33fe4c Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 9 Jan 2024 10:50:34 -0600 Subject: [PATCH 22/94] Empty commit From 889d3e9c1ee5efc13f1758027fcdb4e413cde6dd Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 9 Jan 2024 15:52:33 -0600 Subject: [PATCH 23/94] GH-37 Rename variable to make clearer --- tests/eosio.system_tester.hpp | 6 +++--- tests/eosio.system_tests.cpp | 34 +++++++++++++++++----------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index a5c38be4..f2a6a823 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -1024,9 +1024,9 @@ class eosio_system_tester : public TESTER { } produce_blocks( 250 ); - auto producer_keys = control->active_producers(); - BOOST_REQUIRE_EQUAL( 21, producer_keys.producers.size() ); - BOOST_REQUIRE_EQUAL( name("defproducera"), producer_keys.producers[0].producer_name ); + auto producer_schedule = control->active_producers(); + BOOST_REQUIRE_EQUAL( 21, producer_schedule.producers.size() ); + BOOST_REQUIRE_EQUAL( name("defproducera"), producer_schedule.producers[0].producer_name ); return producer_names; } diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 3b37bbec..545a13c6 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3187,9 +3187,9 @@ BOOST_FIXTURE_TEST_CASE( elect_producers /*_and_parameters*/, eosio_system_teste //vote for producers BOOST_REQUIRE_EQUAL( success(), vote( "alice1111111"_n, { "defproducer1"_n } ) ); produce_blocks(250); - auto producer_keys = control->active_producers(); - BOOST_REQUIRE_EQUAL( 1, producer_keys.producers.size() ); - BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_keys.producers[0].producer_name ); + auto producer_schedule = control->active_producers(); + BOOST_REQUIRE_EQUAL( 1, producer_schedule.producers.size() ); + BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_schedule.producers[0].producer_name ); //auto config = config_to_variant( control->get_global_properties().configuration ); //auto prod1_config = testing::filter_fields( config, producer_parameters_example( 1 ) ); @@ -3203,10 +3203,10 @@ BOOST_FIXTURE_TEST_CASE( elect_producers /*_and_parameters*/, eosio_system_teste BOOST_REQUIRE_EQUAL( success(), vote( "bob111111111"_n, { "defproducer2"_n } ) ); ilog("."); produce_blocks(250); - producer_keys = control->active_producers(); - BOOST_REQUIRE_EQUAL( 2, producer_keys.producers.size() ); - BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_keys.producers[0].producer_name ); - BOOST_REQUIRE_EQUAL( name("defproducer2"), producer_keys.producers[1].producer_name ); + producer_schedule = control->active_producers(); + BOOST_REQUIRE_EQUAL( 2, producer_schedule.producers.size() ); + BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_schedule.producers[0].producer_name ); + BOOST_REQUIRE_EQUAL( name("defproducer2"), producer_schedule.producers[1].producer_name ); //config = config_to_variant( control->get_global_properties().configuration ); //auto prod2_config = testing::filter_fields( config, producer_parameters_example( 2 ) ); //REQUIRE_EQUAL_OBJECTS(prod2_config, config); @@ -3214,26 +3214,26 @@ BOOST_FIXTURE_TEST_CASE( elect_producers /*_and_parameters*/, eosio_system_teste // elect 3 producers BOOST_REQUIRE_EQUAL( success(), vote( "bob111111111"_n, { "defproducer2"_n, "defproducer3"_n } ) ); produce_blocks(250); - producer_keys = control->active_producers(); - BOOST_REQUIRE_EQUAL( 3, producer_keys.producers.size() ); - BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_keys.producers[0].producer_name ); - BOOST_REQUIRE_EQUAL( name("defproducer2"), producer_keys.producers[1].producer_name ); - BOOST_REQUIRE_EQUAL( name("defproducer3"), producer_keys.producers[2].producer_name ); + producer_schedule = control->active_producers(); + BOOST_REQUIRE_EQUAL( 3, producer_schedule.producers.size() ); + BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_schedule.producers[0].producer_name ); + BOOST_REQUIRE_EQUAL( name("defproducer2"), producer_schedule.producers[1].producer_name ); + BOOST_REQUIRE_EQUAL( name("defproducer3"), producer_schedule.producers[2].producer_name ); //config = config_to_variant( control->get_global_properties().configuration ); //REQUIRE_EQUAL_OBJECTS(prod2_config, config); // try to go back to 2 producers and fail BOOST_REQUIRE_EQUAL( success(), vote( "bob111111111"_n, { "defproducer3"_n } ) ); produce_blocks(250); - producer_keys = control->active_producers(); - BOOST_REQUIRE_EQUAL( 3, producer_keys.producers.size() ); + producer_schedule = control->active_producers(); + BOOST_REQUIRE_EQUAL( 3, producer_schedule.producers.size() ); // The test below is invalid now, producer schedule is not updated if there are // fewer producers in the new schedule /* - BOOST_REQUIRE_EQUAL( 2, producer_keys.size() ); - BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_keys[0].producer_name ); - BOOST_REQUIRE_EQUAL( name("defproducer3"), producer_keys[1].producer_name ); + BOOST_REQUIRE_EQUAL( 2, producer_schedule.size() ); + BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_schedule[0].producer_name ); + BOOST_REQUIRE_EQUAL( name("defproducer3"), producer_schedule[1].producer_name ); //config = config_to_variant( control->get_global_properties().configuration ); //auto prod3_config = testing::filter_fields( config, producer_parameters_example( 3 ) ); //REQUIRE_EQUAL_OBJECTS(prod3_config, config); From ea0835b61f12b1de52713e0783ef63f07b9b2ac6 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 25 Jan 2024 08:12:01 -0600 Subject: [PATCH 24/94] GH-41 Add verification that finalizer weight_sum is >= threshold --- contracts/eosio.bios/src/eosio.bios.cpp | 3 ++- tests/eosio.bios_inst_fin_tests.cpp | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/contracts/eosio.bios/src/eosio.bios.cpp b/contracts/eosio.bios/src/eosio.bios.cpp index cd8cb437..b8934003 100644 --- a/contracts/eosio.bios/src/eosio.bios.cpp +++ b/contracts/eosio.bios/src/eosio.bios.cpp @@ -78,7 +78,8 @@ void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { fin_policy.finalizers.emplace_back(eosio::finalizer_authority{f.description, f.weight, std::move(pk_vector)}); } - check(finalizer_policy.threshold > weight_sum / 2, "finalizer policy threshold must be greater than half of the sum of the weights"); + check( weight_sum >= finalizer_policy.threshold && finalizer_policy.threshold > weight_sum / 2, + "Finalizer policy threshold must be greater than half of the sum of the weights, and less than or equal to the sum of the weights"); set_finalizers(std::move(fin_policy)); } diff --git a/tests/eosio.bios_inst_fin_tests.cpp b/tests/eosio.bios_inst_fin_tests.cpp index f8fc10f5..84a494ab 100644 --- a/tests/eosio.bios_inst_fin_tests.cpp +++ b/tests/eosio.bios_inst_fin_tests.cpp @@ -46,7 +46,7 @@ BOOST_FIXTURE_TEST_CASE( set_1_finalizer, eosio_bios_if_tester ) try { ("finalizers", std::vector{ mvo() ("description", "set_1_finalizer") - ("weight", 1) + ("weight", 2) ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))); @@ -59,7 +59,7 @@ BOOST_FIXTURE_TEST_CASE( set_1_finalizer, eosio_bios_if_tester ) try { BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["threshold"], 2); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"].size(), 1u); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["description"], "set_1_finalizer"); - BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["weight"], 1); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["weight"], 5); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["public_key"], "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ=="); } FC_LOG_AND_RETHROW() @@ -68,16 +68,16 @@ BOOST_FIXTURE_TEST_CASE( set_2_finalizers, eosio_bios_if_tester ) try { // public_key and pop are generated by leap-util push_action("iftester"_n, "setfinalizer"_n, "iftester"_n, mvo() ("finalizer_policy", mvo() - ("threshold", 4) + ("threshold", 5) ("finalizers", std::vector{ mvo() ("description", "set_2_finalizer_1") - ("weight", 1) + ("weight", 3) ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg=="), mvo() ("description", "set_2_finalizer_2") - ("weight", 2) + ("weight", 5) ("public_key", "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw==") ("pop", "SIG_BLS_bFLCSmXqVrFqWo2mqxCeuLO5iAevMu/8qxpS7HkXSMmXuVLEytt+shDHn8FpcrUMlMHjxEAHOyRVi0ckvXYrCpHMx6floRvljJ1vV2FphGqgm24DxuB1BE3E21Okc0QS3GH6UCISfVBXuqoK+EfmoSGz3ssi0kzevE8MQitzGgK9EW3zTlZtvdRryI1OTUoUXkjTo1Q2VQIbqJZ55W7SNHUcIBZO5Ih4AXc7usjWUBXv1BK0NNcort4EAfOXnkIN47iRLQ==") }))); @@ -108,7 +108,7 @@ BOOST_FIXTURE_TEST_CASE( public_key_not_started_with_PUB_BLS, eosio_bios_if_test ("finalizer_policy", mvo()("threshold", 2) ("finalizers", std::vector{mvo() ("description", "set_1_finalizer") - ("weight", 1) + ("weight", 2) // PUB_BLS to UB_BLS ("public_key", "UB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); @@ -120,7 +120,7 @@ BOOST_FIXTURE_TEST_CASE( signature_not_started_with_SIG_BLS, eosio_bios_if_teste ("finalizer_policy", mvo()("threshold", 2) ("finalizers", std::vector{mvo() ("description", "set_1_finalizer") - ("weight", 1) + ("weight", 2) ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") // SIG_BLS changed to SIG_BL ("pop", "SIG_BL_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); @@ -132,7 +132,7 @@ BOOST_FIXTURE_TEST_CASE( pop_failed, eosio_bios_if_tester ) try { ("finalizer_policy", mvo()("threshold", 2) ("finalizers", std::vector{mvo() ("description", "set_1_finalizer") - ("weight", 1) + ("weight", 2) ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") // SIG_BLS_q changed to SIG_BLS_j ("pop", "SIG_BLS_jxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); @@ -201,7 +201,7 @@ BOOST_FIXTURE_TEST_CASE( long_description, eosio_bios_if_tester ) try { ("finalizer_policy", mvo()("threshold", 2) ("finalizers", std::vector{mvo() ("description", std::string(257, 'a')) - ("weight", 1) + ("weight", 2) ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); } FC_LOG_AND_RETHROW() @@ -212,7 +212,7 @@ BOOST_FIXTURE_TEST_CASE( description_size_equal_to_max, eosio_bios_if_tester ) t ("finalizer_policy", mvo()("threshold", 2) ("finalizers", std::vector{mvo() ("description", std::string(256, 'a')) - ("weight", 1) + ("weight", 2) ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")})))); } FC_LOG_AND_RETHROW() From a32800dd142e376aefec8c3bbfa0ef6638146075 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 25 Jan 2024 09:25:12 -0600 Subject: [PATCH 25/94] GH-41 Missed a couple of updates --- tests/eosio.bios_inst_fin_tests.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/eosio.bios_inst_fin_tests.cpp b/tests/eosio.bios_inst_fin_tests.cpp index 84a494ab..ecd94613 100644 --- a/tests/eosio.bios_inst_fin_tests.cpp +++ b/tests/eosio.bios_inst_fin_tests.cpp @@ -59,7 +59,7 @@ BOOST_FIXTURE_TEST_CASE( set_1_finalizer, eosio_bios_if_tester ) try { BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["threshold"], 2); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"].size(), 1u); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["description"], "set_1_finalizer"); - BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["weight"], 5); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["weight"], 2); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["public_key"], "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ=="); } FC_LOG_AND_RETHROW() @@ -88,10 +88,10 @@ BOOST_FIXTURE_TEST_CASE( set_2_finalizers, eosio_bios_if_tester ) try { BOOST_REQUIRE(pretty_output.get_object().contains("instant_finality_extension")); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["generation"], 1); - BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["threshold"], 4); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["threshold"], 5); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"].size(), 2u); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["description"], "set_2_finalizer_2"); - BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["weight"], 2); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["weight"], 3); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["public_key"], "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw=="); } FC_LOG_AND_RETHROW() From 401c8b104f72fded4dd3621c472b7dff41e97256 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 25 Jan 2024 09:49:04 -0600 Subject: [PATCH 26/94] GH-41 Missed one --- tests/eosio.bios_inst_fin_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/eosio.bios_inst_fin_tests.cpp b/tests/eosio.bios_inst_fin_tests.cpp index ecd94613..2518f144 100644 --- a/tests/eosio.bios_inst_fin_tests.cpp +++ b/tests/eosio.bios_inst_fin_tests.cpp @@ -91,7 +91,7 @@ BOOST_FIXTURE_TEST_CASE( set_2_finalizers, eosio_bios_if_tester ) try { BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["threshold"], 5); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"].size(), 2u); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["description"], "set_2_finalizer_2"); - BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["weight"], 3); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["weight"], 5); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["public_key"], "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw=="); } FC_LOG_AND_RETHROW() From 2977500e8df3d11a6260b33c6af737c580e3a951 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 6 Feb 2024 10:21:49 -0600 Subject: [PATCH 27/94] signals are now accessors not members --- tests/eosio.system_tests.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 545a13c6..6568a82f 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -2835,7 +2835,7 @@ BOOST_FIXTURE_TEST_CASE(producers_upgrade_system_contract, eosio_system_tester) ); transaction_trace_ptr trace; - control->applied_transaction.connect( + control->applied_transaction().connect( [&]( std::tuple p ) { trace = std::get<0>(p); } ); @@ -3601,7 +3601,7 @@ BOOST_FIXTURE_TEST_CASE( setparams, eosio_system_tester ) try { } transaction_trace_ptr trace; - control->applied_transaction.connect( + control->applied_transaction().connect( [&]( std::tuple p ) { trace = std::get<0>(p); } ); @@ -3691,7 +3691,7 @@ BOOST_FIXTURE_TEST_CASE( wasmcfg, eosio_system_tester ) try { } transaction_trace_ptr trace; - control->applied_transaction.connect( + control->applied_transaction().connect( [&]( std::tuple p ) { trace = std::get<0>(p); } ); From 635ff8631c36f5f4bb572a1d14592bf8cf88b321 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 6 Feb 2024 10:23:08 -0600 Subject: [PATCH 28/94] Temporarily change target --- .cicd/defaults.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/defaults.json b/.cicd/defaults.json index 136b822d..4ecdd5f0 100644 --- a/.cicd/defaults.json +++ b/.cicd/defaults.json @@ -1,6 +1,6 @@ { "leap-dev":{ - "target":"hotstuff_integration", + "target":"controller-self", "prerelease":false }, "cdt":{ From 3816c6970c14b80926f8ec9cba2308961899c4e0 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 6 Feb 2024 11:46:30 -0600 Subject: [PATCH 29/94] Switch back to instant-finality now that it is updated --- .cicd/defaults.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/defaults.json b/.cicd/defaults.json index 4ecdd5f0..7fc540b4 100644 --- a/.cicd/defaults.json +++ b/.cicd/defaults.json @@ -1,6 +1,6 @@ { "leap-dev":{ - "target":"controller-self", + "target":"instant-finality", "prerelease":false }, "cdt":{ From 2d30776dcc739808fd398ea8c1d778f30c3cdab3 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 6 Feb 2024 11:48:32 -0600 Subject: [PATCH 30/94] Should be hotstuff_integration --- .cicd/defaults.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/defaults.json b/.cicd/defaults.json index 7fc540b4..136b822d 100644 --- a/.cicd/defaults.json +++ b/.cicd/defaults.json @@ -1,6 +1,6 @@ { "leap-dev":{ - "target":"instant-finality", + "target":"hotstuff_integration", "prerelease":false }, "cdt":{ From 63bd2785f9d6d7fdc19de57f9e8c43a580a82673 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 26 Feb 2024 18:10:11 -0500 Subject: [PATCH 31/94] update bios finality tests using new keys and signatures in base64 url format --- tests/eosio.bios_inst_fin_tests.cpp | 62 ++++++++++++++--------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/tests/eosio.bios_inst_fin_tests.cpp b/tests/eosio.bios_inst_fin_tests.cpp index 2518f144..4c986b05 100644 --- a/tests/eosio.bios_inst_fin_tests.cpp +++ b/tests/eosio.bios_inst_fin_tests.cpp @@ -47,8 +47,8 @@ BOOST_FIXTURE_TEST_CASE( set_1_finalizer, eosio_bios_if_tester ) try { mvo() ("description", "set_1_finalizer") ("weight", 2) - ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") - ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))); + ("public_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA") + ("pop", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA")}))); signed_block_ptr cur_block = produce_block(); fc::variant pretty_output; @@ -60,7 +60,7 @@ BOOST_FIXTURE_TEST_CASE( set_1_finalizer, eosio_bios_if_tester ) try { BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"].size(), 1u); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["description"], "set_1_finalizer"); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["weight"], 2); - BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["public_key"], "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ=="); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(0)]["public_key"], "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA"); } FC_LOG_AND_RETHROW() // two finalizers in finalizer policy @@ -73,13 +73,13 @@ BOOST_FIXTURE_TEST_CASE( set_2_finalizers, eosio_bios_if_tester ) try { mvo() ("description", "set_2_finalizer_1") ("weight", 3) - ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") - ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg=="), + ("public_key", "PUB_BLS_gtaOjOTa0NzDt8etBDqLoZKlfKTpTalcdfmbTJknLUJB2Fu4Cv-uoa8unF3bJ5kFewaCzf3tjYUyNE6CDSrwvYP5Nw47Y9oE9x4nqJWfJykMOoaI0kJz-GDrGN2nZdUAp5tWEg") + ("pop", "SIG_BLS_9e1SzM60bWLdxwz4lYNQMNzMGeFuzFgJDYy7WykmynRVRQeIx2O2xnyzwv1WXvgYHLyMYZ4wK0Y_kU6jl330WazkBsw-_GzvIOGy8fnBnt5AyMaj9X5bhDbvB5MZc0QQz4-P2Z4SltTY17ZItGeekkjX_fgQ9kegM4qnuGU-2iqFj5i3Qf322L77b2SHjFoLmxdFOsfGpz7LyImSP8GcZH39W30cj5bmxfsp_90tGdAkz-7DG9nhSHYxFq6qTqMGijVPGg"), mvo() ("description", "set_2_finalizer_2") ("weight", 5) - ("public_key", "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw==") - ("pop", "SIG_BLS_bFLCSmXqVrFqWo2mqxCeuLO5iAevMu/8qxpS7HkXSMmXuVLEytt+shDHn8FpcrUMlMHjxEAHOyRVi0ckvXYrCpHMx6floRvljJ1vV2FphGqgm24DxuB1BE3E21Okc0QS3GH6UCISfVBXuqoK+EfmoSGz3ssi0kzevE8MQitzGgK9EW3zTlZtvdRryI1OTUoUXkjTo1Q2VQIbqJZ55W7SNHUcIBZO5Ih4AXc7usjWUBXv1BK0NNcort4EAfOXnkIN47iRLQ==") + ("public_key", "PUB_BLS_kV0d54mbPRbd65t4ttv_-CxNt8ktKmf8q4uKZzNTzFSHDSj5rLlP_hdovTsHAPQOAyyzJ4bRTheKjSUj-IoTW96v3VdlifgtDbSVmg4JZR8H_tlStQSWsTHGo8pTX8cR_HEVoA") + ("pop", "SIG_BLS_DsTwQvYa4uP51putCpLiZlJDyCL24l7bVu1kznc4X8GIYQdElYaCO88RFfCvncYFKwJfKZb-LNMW4GHZzhnyWu0Gp-ougZhSIq4mi1FrtM39uT6KP00-fYYPLOw5nzoLOl__f72qEkBluaaXKIiboWfQ-VnRdzvuE-8Y_m36u6d7bThWy1Lz27mUeelhLawEaKIW688HpFAQDEuvvKfAZYvsyPYXod6a_2KYS4rQkyAtjJXBWk4W0cuPU5n9lNYGyuzF4Q") }))); signed_block_ptr cur_block = produce_block(); @@ -92,7 +92,7 @@ BOOST_FIXTURE_TEST_CASE( set_2_finalizers, eosio_bios_if_tester ) try { BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"].size(), 2u); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["description"], "set_2_finalizer_2"); BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["weight"], 5); - BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["public_key"], "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw=="); + BOOST_REQUIRE_EQUAL(pretty_output["instant_finality_extension"]["new_finalizer_policy"]["finalizers"][size_t(1)]["public_key"], "PUB_BLS_kV0d54mbPRbd65t4ttv_-CxNt8ktKmf8q4uKZzNTzFSHDSj5rLlP_hdovTsHAPQOAyyzJ4bRTheKjSUj-IoTW96v3VdlifgtDbSVmg4JZR8H_tlStQSWsTHGo8pTX8cR_HEVoA"); } FC_LOG_AND_RETHROW() // finalizer cannot be empty @@ -110,8 +110,8 @@ BOOST_FIXTURE_TEST_CASE( public_key_not_started_with_PUB_BLS, eosio_bios_if_test ("description", "set_1_finalizer") ("weight", 2) // PUB_BLS to UB_BLS - ("public_key", "UB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") - ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); + ("public_key", "UB_BLS_lkixuIBmY1Xuc0GFnek0iDXitKAAQt87CL7Q1jZsjLid-9cruKfj_KjJk2P4GxsL7HnArD6F0lNAoxsLHISpsBBHqi-ET5JAYfKkS5lgG4To1vP48x6TtOPOslsr5D0YqKbtng") + ("pop", "SIG_BLS_ubO3gsBLRuXg1UWLvNg54B4Xr2c1wKmwIVUzAxKOCAVKmOHabYdm222v3Go8bPkU7R9sRq2qYkhJQGh3wLbtcIhc2D6CPMpRIUB6mIcX18X2l-3ceXWdWfQBFWs1sUoXfp2UpmeMIPVcDKqgKWnJGyYyei-ekE86XnWaA8bBMzxAcJpEml4E--PRe48m27gVKqaTb6oY27oZHiHbjocZi1TU0RsDNGJAjaIapZkBKRUStQymTE6mmgdgLRHlR4EFjsiRUA")}))), eosio_assert_message_exception); } FC_LOG_AND_RETHROW() // pop signature must start with SIG_BLS @@ -121,9 +121,9 @@ BOOST_FIXTURE_TEST_CASE( signature_not_started_with_SIG_BLS, eosio_bios_if_teste ("finalizers", std::vector{mvo() ("description", "set_1_finalizer") ("weight", 2) - ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") + ("public_key", "PUB_BLS_lkixuIBmY1Xuc0GFnek0iDXitKAAQt87CL7Q1jZsjLid-9cruKfj_KjJk2P4GxsL7HnArD6F0lNAoxsLHISpsBBHqi-ET5JAYfKkS5lgG4To1vP48x6TtOPOslsr5D0YqKbtng") // SIG_BLS changed to SIG_BL - ("pop", "SIG_BL_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); + ("pop", "SIG_BL_ubO3gsBLRuXg1UWLvNg54B4Xr2c1wKmwIVUzAxKOCAVKmOHabYdm222v3Go8bPkU7R9sRq2qYkhJQGh3wLbtcIhc2D6CPMpRIUB6mIcX18X2l-3ceXWdWfQBFWs1sUoXfp2UpmeMIPVcDKqgKWnJGyYyei-ekE86XnWaA8bBMzxAcJpEml4E--PRe48m27gVKqaTb6oY27oZHiHbjocZi1TU0RsDNGJAjaIapZkBKRUStQymTE6mmgdgLRHlR4EFjsiRUA")}))), eosio_assert_message_exception); } FC_LOG_AND_RETHROW() // test to verify POP verification failure @@ -133,9 +133,9 @@ BOOST_FIXTURE_TEST_CASE( pop_failed, eosio_bios_if_tester ) try { ("finalizers", std::vector{mvo() ("description", "set_1_finalizer") ("weight", 2) - ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") - // SIG_BLS_q changed to SIG_BLS_j - ("pop", "SIG_BLS_jxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); + ("public_key", "PUB_BLS_lkixuIBmY1Xuc0GFnek0iDXitKAAQt87CL7Q1jZsjLid-9cruKfj_KjJk2P4GxsL7HnArD6F0lNAoxsLHISpsBBHqi-ET5JAYfKkS5lgG4To1vP48x6TtOPOslsr5D0YqKbtng") + // SIG_BLS_u changed to SIG_BLS_v + ("pop", "SIG_BLS_vbO3gsBLRuXg1UWLvNg54B4Xr2c1wKmwIVUzAxKOCAVKmOHabYdm222v3Go8bPkU7R9sRq2qYkhJQGh3wLbtcIhc2D6CPMpRIUB6mIcX18X2l-3ceXWdWfQBFWs1sUoXfp2UpmeMIPVcDKqgKWnJGyYyei-ekE86XnWaA8bBMzxAcJpEml4E--PRe48m27gVKqaTb6oY27oZHiHbjocZi1TU0RsDNGJAjaIapZkBKRUStQymTE6mmgdgLRHlR4EFjsiRUA")}))), eosio_assert_message_exception); } FC_LOG_AND_RETHROW() // Verifies threshold must be greater than half the sum of the weights @@ -147,13 +147,13 @@ BOOST_FIXTURE_TEST_CASE( threshold_equal_to_half_weights, eosio_bios_if_tester ) mvo() ("description", "set_2_finalizer_1") ("weight", 5) - ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") - ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg=="), + ("public_key", "PUB_BLS_kV0d54mbPRbd65t4ttv_-CxNt8ktKmf8q4uKZzNTzFSHDSj5rLlP_hdovTsHAPQOAyyzJ4bRTheKjSUj-IoTW96v3VdlifgtDbSVmg4JZR8H_tlStQSWsTHGo8pTX8cR_HEVoA") + ("pop", "SIG_BLS_DsTwQvYa4uP51putCpLiZlJDyCL24l7bVu1kznc4X8GIYQdElYaCO88RFfCvncYFKwJfKZb-LNMW4GHZzhnyWu0Gp-ougZhSIq4mi1FrtM39uT6KP00-fYYPLOw5nzoLOl__f72qEkBluaaXKIiboWfQ-VnRdzvuE-8Y_m36u6d7bThWy1Lz27mUeelhLawEaKIW688HpFAQDEuvvKfAZYvsyPYXod6a_2KYS4rQkyAtjJXBWk4W0cuPU5n9lNYGyuzF4Q"), mvo() ("description", "set_2_finalizer_2") ("weight", 5) - ("public_key", "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw==") - ("pop", "SIG_BLS_bFLCSmXqVrFqWo2mqxCeuLO5iAevMu/8qxpS7HkXSMmXuVLEytt+shDHn8FpcrUMlMHjxEAHOyRVi0ckvXYrCpHMx6floRvljJ1vV2FphGqgm24DxuB1BE3E21Okc0QS3GH6UCISfVBXuqoK+EfmoSGz3ssi0kzevE8MQitzGgK9EW3zTlZtvdRryI1OTUoUXkjTo1Q2VQIbqJZ55W7SNHUcIBZO5Ih4AXc7usjWUBXv1BK0NNcort4EAfOXnkIN47iRLQ==") + ("public_key", "PUB_BLS_lkixuIBmY1Xuc0GFnek0iDXitKAAQt87CL7Q1jZsjLid-9cruKfj_KjJk2P4GxsL7HnArD6F0lNAoxsLHISpsBBHqi-ET5JAYfKkS5lgG4To1vP48x6TtOPOslsr5D0YqKbtng") + ("pop", "SIG_BLS_ubO3gsBLRuXg1UWLvNg54B4Xr2c1wKmwIVUzAxKOCAVKmOHabYdm222v3Go8bPkU7R9sRq2qYkhJQGh3wLbtcIhc2D6CPMpRIUB6mIcX18X2l-3ceXWdWfQBFWs1sUoXfp2UpmeMIPVcDKqgKWnJGyYyei-ekE86XnWaA8bBMzxAcJpEml4E--PRe48m27gVKqaTb6oY27oZHiHbjocZi1TU0RsDNGJAjaIapZkBKRUStQymTE6mmgdgLRHlR4EFjsiRUA") }))), eosio_assert_message_exception); } FC_LOG_AND_RETHROW() @@ -166,13 +166,13 @@ BOOST_FIXTURE_TEST_CASE( threshold_greater_than_by_one_half_weights, eosio_bios_ mvo() ("description", "set_2_finalizer_1") ("weight", 5) - ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") - ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg=="), + ("public_key", "PUB_BLS_kV0d54mbPRbd65t4ttv_-CxNt8ktKmf8q4uKZzNTzFSHDSj5rLlP_hdovTsHAPQOAyyzJ4bRTheKjSUj-IoTW96v3VdlifgtDbSVmg4JZR8H_tlStQSWsTHGo8pTX8cR_HEVoA") + ("pop", "SIG_BLS_DsTwQvYa4uP51putCpLiZlJDyCL24l7bVu1kznc4X8GIYQdElYaCO88RFfCvncYFKwJfKZb-LNMW4GHZzhnyWu0Gp-ougZhSIq4mi1FrtM39uT6KP00-fYYPLOw5nzoLOl__f72qEkBluaaXKIiboWfQ-VnRdzvuE-8Y_m36u6d7bThWy1Lz27mUeelhLawEaKIW688HpFAQDEuvvKfAZYvsyPYXod6a_2KYS4rQkyAtjJXBWk4W0cuPU5n9lNYGyuzF4Q"), mvo() ("description", "set_2_finalizer_2") ("weight", 5) - ("public_key", "PUB_BLS_UGcXVpLNrhdODrbI9Geaswu8wFnL+WMnphfTaCgehRxol5wI1qiU5zq6qHp9+CkFnmm2XWCcM/YEtqZYL6uTM1TXTpTm3LODI0s/ULO4iKSNYclsmDdh5cFSMmKKnloHudh3Zw==") - ("pop", "SIG_BLS_bFLCSmXqVrFqWo2mqxCeuLO5iAevMu/8qxpS7HkXSMmXuVLEytt+shDHn8FpcrUMlMHjxEAHOyRVi0ckvXYrCpHMx6floRvljJ1vV2FphGqgm24DxuB1BE3E21Okc0QS3GH6UCISfVBXuqoK+EfmoSGz3ssi0kzevE8MQitzGgK9EW3zTlZtvdRryI1OTUoUXkjTo1Q2VQIbqJZ55W7SNHUcIBZO5Ih4AXc7usjWUBXv1BK0NNcort4EAfOXnkIN47iRLQ==") + ("public_key", "PUB_BLS_lkixuIBmY1Xuc0GFnek0iDXitKAAQt87CL7Q1jZsjLid-9cruKfj_KjJk2P4GxsL7HnArD6F0lNAoxsLHISpsBBHqi-ET5JAYfKkS5lgG4To1vP48x6TtOPOslsr5D0YqKbtng") + ("pop", "SIG_BLS_ubO3gsBLRuXg1UWLvNg54B4Xr2c1wKmwIVUzAxKOCAVKmOHabYdm222v3Go8bPkU7R9sRq2qYkhJQGh3wLbtcIhc2D6CPMpRIUB6mIcX18X2l-3ceXWdWfQBFWs1sUoXfp2UpmeMIPVcDKqgKWnJGyYyei-ekE86XnWaA8bBMzxAcJpEml4E--PRe48m27gVKqaTb6oY27oZHiHbjocZi1TU0RsDNGJAjaIapZkBKRUStQymTE6mmgdgLRHlR4EFjsiRUA") })))); } FC_LOG_AND_RETHROW() @@ -185,13 +185,13 @@ BOOST_FIXTURE_TEST_CASE( duplicate_pub_keys, eosio_bios_if_tester ) try { mvo() ("description", "set_2_finalizer_1") ("weight", 5) - ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") - ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg=="), + ("public_key", "PUB_BLS_lkixuIBmY1Xuc0GFnek0iDXitKAAQt87CL7Q1jZsjLid-9cruKfj_KjJk2P4GxsL7HnArD6F0lNAoxsLHISpsBBHqi-ET5JAYfKkS5lgG4To1vP48x6TtOPOslsr5D0YqKbtng") + ("pop", "SIG_BLS_ubO3gsBLRuXg1UWLvNg54B4Xr2c1wKmwIVUzAxKOCAVKmOHabYdm222v3Go8bPkU7R9sRq2qYkhJQGh3wLbtcIhc2D6CPMpRIUB6mIcX18X2l-3ceXWdWfQBFWs1sUoXfp2UpmeMIPVcDKqgKWnJGyYyei-ekE86XnWaA8bBMzxAcJpEml4E--PRe48m27gVKqaTb6oY27oZHiHbjocZi1TU0RsDNGJAjaIapZkBKRUStQymTE6mmgdgLRHlR4EFjsiRUA"), mvo() ("description", "set_2_finalizer_2") ("weight", 5) - ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") - ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg=="), + ("public_key", "PUB_BLS_lkixuIBmY1Xuc0GFnek0iDXitKAAQt87CL7Q1jZsjLid-9cruKfj_KjJk2P4GxsL7HnArD6F0lNAoxsLHISpsBBHqi-ET5JAYfKkS5lgG4To1vP48x6TtOPOslsr5D0YqKbtng") + ("pop", "SIG_BLS_ubO3gsBLRuXg1UWLvNg54B4Xr2c1wKmwIVUzAxKOCAVKmOHabYdm222v3Go8bPkU7R9sRq2qYkhJQGh3wLbtcIhc2D6CPMpRIUB6mIcX18X2l-3ceXWdWfQBFWs1sUoXfp2UpmeMIPVcDKqgKWnJGyYyei-ekE86XnWaA8bBMzxAcJpEml4E--PRe48m27gVKqaTb6oY27oZHiHbjocZi1TU0RsDNGJAjaIapZkBKRUStQymTE6mmgdgLRHlR4EFjsiRUA") }))), eosio_assert_message_exception); } FC_LOG_AND_RETHROW() @@ -202,8 +202,8 @@ BOOST_FIXTURE_TEST_CASE( long_description, eosio_bios_if_tester ) try { ("finalizers", std::vector{mvo() ("description", std::string(257, 'a')) ("weight", 2) - ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") - ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")}))), eosio_assert_message_exception); + ("public_key", "PUB_BLS_lkixuIBmY1Xuc0GFnek0iDXitKAAQt87CL7Q1jZsjLid-9cruKfj_KjJk2P4GxsL7HnArD6F0lNAoxsLHISpsBBHqi-ET5JAYfKkS5lgG4To1vP48x6TtOPOslsr5D0YqKbtng") + ("pop", "SIG_BLS_ubO3gsBLRuXg1UWLvNg54B4Xr2c1wKmwIVUzAxKOCAVKmOHabYdm222v3Go8bPkU7R9sRq2qYkhJQGh3wLbtcIhc2D6CPMpRIUB6mIcX18X2l-3ceXWdWfQBFWs1sUoXfp2UpmeMIPVcDKqgKWnJGyYyei-ekE86XnWaA8bBMzxAcJpEml4E--PRe48m27gVKqaTb6oY27oZHiHbjocZi1TU0RsDNGJAjaIapZkBKRUStQymTE6mmgdgLRHlR4EFjsiRUA")}))), eosio_assert_message_exception); } FC_LOG_AND_RETHROW() // Verifies description equal to maximum allowed size (256 chars) @@ -213,8 +213,8 @@ BOOST_FIXTURE_TEST_CASE( description_size_equal_to_max, eosio_bios_if_tester ) t ("finalizers", std::vector{mvo() ("description", std::string(256, 'a')) ("weight", 2) - ("public_key", "PUB_BLS_jpMTmybJZvf4k6fR7Bgu7wrNjwQLK/IBdjhZHWTjoohgdUMi8VpTGsyYpzP1+ekMzUuZ8LqFcnfO0myTwH9Y2YeabhhowSp7nzJJhgO4XWCpcGCLssOjVWh3/D9wMIISVUwfsQ==") - ("pop", "SIG_BLS_qxozxdQngA4iDidRNJXwKML7VhawRi6XGMXeBc55MzDaAyixR5D3Ys7d72IiwroUkWDqEVQrPq+u/ukICWD9g+LeE9JNxn8IBMLpotXu728ezyal6g5tMoDf8PQuZSEP6yPSMGo7ajbHVe+ehcgWs+/zpxWH1WgCTgU3Bc5Qy32z6L0ztK3WLuW25OmK3EQLbIP5sPMv07gMWP4aDNLAor6IzQYMvxFaibiWsSqMt4YxB6eONetmdftCn5Om3NcHwW7Ueg==")})))); + ("public_key", "PUB_BLS_lkixuIBmY1Xuc0GFnek0iDXitKAAQt87CL7Q1jZsjLid-9cruKfj_KjJk2P4GxsL7HnArD6F0lNAoxsLHISpsBBHqi-ET5JAYfKkS5lgG4To1vP48x6TtOPOslsr5D0YqKbtng") + ("pop", "SIG_BLS_ubO3gsBLRuXg1UWLvNg54B4Xr2c1wKmwIVUzAxKOCAVKmOHabYdm222v3Go8bPkU7R9sRq2qYkhJQGh3wLbtcIhc2D6CPMpRIUB6mIcX18X2l-3ceXWdWfQBFWs1sUoXfp2UpmeMIPVcDKqgKWnJGyYyei-ekE86XnWaA8bBMzxAcJpEml4E--PRe48m27gVKqaTb6oY27oZHiHbjocZi1TU0RsDNGJAjaIapZkBKRUStQymTE6mmgdgLRHlR4EFjsiRUA")})))); } FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_SUITE_END() From 5ff038dd46dddf9d09a6df9ba00758681381d035 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 26 Feb 2024 18:11:31 -0500 Subject: [PATCH 32/94] temporarily change leap-dev target to pubkey_base64url for build --- .cicd/defaults.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/defaults.json b/.cicd/defaults.json index 136b822d..2dc5147b 100644 --- a/.cicd/defaults.json +++ b/.cicd/defaults.json @@ -1,6 +1,6 @@ { "leap-dev":{ - "target":"hotstuff_integration", + "target":"pubkey_base64url", "prerelease":false }, "cdt":{ From e09fd4e7bdc675f5b105973a89a7768807b33f51 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 27 Feb 2024 09:08:44 -0500 Subject: [PATCH 33/94] change leap-dev target back to hotstuff_integration --- .cicd/defaults.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/defaults.json b/.cicd/defaults.json index 2dc5147b..136b822d 100644 --- a/.cicd/defaults.json +++ b/.cicd/defaults.json @@ -1,6 +1,6 @@ { "leap-dev":{ - "target":"pubkey_base64url", + "target":"hotstuff_integration", "prerelease":false }, "cdt":{ From 5d7b0f2a76e2c3e03c4de9c211286af98cf8e021 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 26 Mar 2024 21:35:02 -0400 Subject: [PATCH 34/94] Add core contract actions to support Savanna draft version --- contracts/eosio.system/CMakeLists.txt | 1 + .../include/eosio.system/eosio.system.hpp | 87 ++++++++++ contracts/eosio.system/src/finalizer_key.cpp | 158 ++++++++++++++++++ contracts/eosio.system/src/voting.cpp | 7 + 4 files changed, 253 insertions(+) create mode 100644 contracts/eosio.system/src/finalizer_key.cpp diff --git a/contracts/eosio.system/CMakeLists.txt b/contracts/eosio.system/CMakeLists.txt index 0e77e7f5..6848e838 100644 --- a/contracts/eosio.system/CMakeLists.txt +++ b/contracts/eosio.system/CMakeLists.txt @@ -4,6 +4,7 @@ add_contract( ${CMAKE_CURRENT_SOURCE_DIR}/src/eosio.system.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/delegate_bandwidth.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/exchange_state.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/finalizer_key.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/name_bidding.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/native.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/producer_pay.cpp diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 4c2574fa..5d87a492 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -197,6 +197,15 @@ namespace eosiosystem { EOSLIB_SERIALIZE( eosio_global_state4, (continuous_rate)(inflation_pay_factor)(votepay_factor) ) }; + // Defines new global state parameters to store last finalizer set. + // It is also used as an indicator Savanna consensus has been switched over. + struct [[eosio::table("global5"), eosio::contract("eosio.system")]] eosio_global_state5 { + eosio_global_state5() { } + std::vector last_finalizers; + + EOSLIB_SERIALIZE( eosio_global_state5, (last_finalizers) ) + }; + inline eosio::block_signing_authority convert_to_block_signing_authority( const eosio::public_key& producer_key ) { return eosio::block_signing_authority_v0{ .threshold = 1, .keys = {{producer_key, 1}} }; } @@ -282,6 +291,18 @@ namespace eosiosystem { EOSLIB_SERIALIZE( producer_info2, (owner)(votepay_share)(last_votepay_share_update) ) }; + // Defines finalizer_key info structure to be stored in finalizer_keys info table, added after version 6.0 + struct [[eosio::table, eosio::contract("eosio.system")]] finalizer_key_info { + name producer; + std::string active_finalizer_key; // the currently active key + std::unordered_set registered_finalizer_keys; // including the active_finalizer_key + + uint64_t primary_key()const { return producer.value; } + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE( finalizer_key_info, (producer)(active_finalizer_key)(active_finalizer_key) ) + }; + // Voter info. Voter info stores information about the voter: // - `owner` the voter // - `proxy` the proxy set by the voter, if any @@ -329,6 +350,7 @@ namespace eosiosystem { typedef eosio::multi_index< "producers2"_n, producer_info2 > producers_table2; + typedef eosio::multi_index< "finalizer_key"_n, finalizer_key_info > finalizer_keys_table; typedef eosio::singleton< "global"_n, eosio_global_state > global_state_singleton; @@ -338,6 +360,8 @@ namespace eosiosystem { typedef eosio::singleton< "global4"_n, eosio_global_state4 > global_state4_singleton; + typedef eosio::singleton< "global5"_n, eosio_global_state5 > global_state5_singleton; + struct [[eosio::table, eosio::contract("eosio.system")]] user_resources { name owner; asset net_weight; @@ -682,14 +706,17 @@ namespace eosiosystem { voters_table _voters; producers_table _producers; producers_table2 _producers2; + finalizer_keys_table _finalizer_keys; global_state_singleton _global; global_state2_singleton _global2; global_state3_singleton _global3; global_state4_singleton _global4; + global_state5_singleton _global5; eosio_global_state _gstate; eosio_global_state2 _gstate2; eosio_global_state3 _gstate3; eosio_global_state4 _gstate4; + eosio_global_state5 _gstate5; rammarket _rammarket; rex_pool_table _rexpool; rex_return_pool_table _rexretpool; @@ -1172,6 +1199,66 @@ namespace eosiosystem { [[eosio::action]] void unregprod( const name& producer ); + /** + * Action to permanently transition to Savanna consensus. + * Create the first generation of finalizer policy and activate + * the policy by using `set_finalizers` host function + * + * @pre Require the authority of the contract itself + * @pre A sufficient number (15) of the top 21 block producers have registered a finalizer key + */ + [[eosio::action]] + void switchtosvnn(); + + /** + * Register a finalizer key action by a registered producer. + * If this is the first registered finalizer key of the producer, + * it will also implicitly be marked active. + * If this finalizer key was registered before (and still exists) even + * by other block producers, the registration will fail. + * A registered producer can have multiple registered finalizer keys. + * + * @param producer - account registering `finalizer_key`, + * @param finalizer_key - key to be registered. The key is in base64url format. + * @param proof_of_possession - a valid Proof of Possession signature to show the producer owns the private key of the finalizer_key. The signature is in base64url format. + * + * @pre `producer` must be a registered producer + * @pre Authority of `producer` to register + */ + [[eosio::action]] + void regfinkey( const name& producer, const std::string& finalizer_key, const std::string& proof_of_possession); + + /** + * Activate a finalizer key action. If the block producer is currently + * active (in top 21), then immediately change Finalizer Policy. + * Activating a finalizer key of a block producer implicitly deactivates + * the previously active finalizer key of that block producer. + * + * @param producer - account activating `finalizer_key`, + * @param finalizer_key - key to be activated. + * + * @pre `producer` must be a registered producer + * @pre `finalizer_key` must be a registered finalizer key + * @pre Authority of `producer` + */ + [[eosio::action]] + void actfinkey( const name& producer, const std::string& finalizer_key ); + + /** + * Delete a finalizer key action which is not active unless it is the + * last regitered finalizer key. + * + * @param producer - account deleting `finalizer_key`, + * @param finalizer_key - key to be deleted. + * + * @pre `producer` must be a registered producer + * @pre `finalizer_key` must be a registered finalizer key + * @pre `finalizer_key` must be not be active, unless it is the last regitered finalizer key + * @pre Authority of `producer` + */ + [[eosio::action]] + void delfinkey( const name& producer, const std::string& finalizer_key ); + /** * Set ram action sets the ram supply. * @param max_ram_size - the amount of ram supply to set. diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp new file mode 100644 index 00000000..386bfd1d --- /dev/null +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -0,0 +1,158 @@ +#include + +#include +#include +#include + +namespace eosiosystem { + + bool system_contract::is_savanna_consensus() { + return !_gstate5.last_finalizers.empty(); + } + + bool system_contract::is_registered_producer( const name& producer ) { + // Returns true if `producer` is a registered producer + } + + bool system_contract::is_active_producer( const name& producer ) { + // Returns true if `producer` is an active producer (top 21) + } + + bool set_next_finalizers_set(const std::vector& producers ) { + // Build finalizer set + std::vector finalizers; + for ( const auto p&: producers ) { + auto it = _finalizer_keys.find( p.value ); + if( it != _finalizer_keys.end() ) { // p has registered a finalizer key + finalizers.emplace_back( + finalizer_authority{ + .description = "", + .weight = 1, + .public_key = it->active_key + } + ); + } + } + + // Abort if less than 15 top producers have registered a finalizer key + if( finalizers.size < 15 ) { + return false; + } + + // Establish finalizer policy and call set_finalizers() host function + finalizer_policy fin_policy { + .generation = 0; + .threshold = 15; + .finalizers = finalizers; + }; + set_finalizers(std::move(fin_policy)); + + _gstate5.last_finalizers = finalizers; + + return true; + } + + void replace_key_in_finalizer_policy(const name& producer, const std::string& finalizer_key) { + // replace the key in last finalizer policy and call set_finalizers + // host function immediately + } + + void delete_key_in_finalizer_policy(const name& producer, const std::string& finalizer_key) { + // replace the key in last finalizer policy and call set_finalizers + // host function immediately + } + + void system_contract::switchtosvnn() { + require_auth(get_self()); + + check(!is_savanna_consensus(), "switchtosvnn can only be run once"); + + // Find top 21 block producers + auto idx = _producers.get_index<"prototalvote"_n>(); + std::vector top_producers; + top_producers.reserve(21); + for( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active(); ++it ) { + top_producers.emplace_back(it->owner); + } + if( top_producers.size() < 21 ) { + return; + } + + set_next_finalizers_set(top_producers); + } + + void system_contract::regfinkey( const name& producer, const std::string& finalizer_key, const std::string& proof_of_possession) { + require_auth( producer ); + + check( is_registered_producer(producer), "The producer is not a registered producer"); + + // Basic key and signature format check + check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key must start with PUB_BLS"); + check(proof_of_possession.compare(0, 7, "SIG_BLS") == 0, "proof of possession siganture must start with SIG_BLS"); + + // Proof of possession check + const auto pk = eosio::decode_bls_public_key_to_g1(finalizer_key); + const auto signature = eosio::decode_bls_signature_to_g2(proof_of_possession); + check(eosio::bls_pop_verify(pk, signature), "proof of possession check failed"); + + // Todo: Go over finalizer_keys_table to make sure no duplicate keys are + // registered. + + auto it = _finalizer_keys.find( producer.value ); + if( it != _finalizer_keys.end() ) { + _finalizer_keys.modify( it, same_payer, [&]( auto& k ) { + k.registered_finalizer_keys.insert(finalizer_key); + }); + } else { + // The first time the producer registers a finalizer key + _finalizer_keys.emplace( producer, [&]( auto& p ) { + k.producer = producer; + k.registered_finalizer_keys.insert(finalizer_key); + k.active_key = finalizer_key; + }); + + if( is_active_producer(producer) ) { + replace_key_in_finalizer_policy(producer, finalizer_key); + } + } + } + + void system_contract::actfinkey( const name& producer, const std::string& finalizer_key ) { + require_auth( producer ); + + check( is_registered_producer(producer), "The producer is not a registered producer"); + + auto it = _finalizer_keys.find( producer.value ); + check(it != _finalizer_keys.end(), "producer has not registered any keys"); + + check(it->registered_finalizer_keys.find(finalizer_key) != it->registered_finalizer_keys.end(), "finalizer_key was not registered"); + + _finalizer_keys.modify( it, same_payer, [&]( auto& k ) { + k.active_finalizer_key = finalizer_key; + }); + + if( is_active_producer(producer) ) { + replace_key_in_finalizer_policy(producer, finalizer_key); + } + } + + void system_contract::delfinkey( const name& producer, const std::string& finalizer_key ) { + require_auth( producer ); + + check( is_registered_producer(producer), "The producer is not a registered producer"); + + auto it = _finalizer_keys.find( producer.value ); + check(it != _finalizer_keys.end(), "producer has not registered any keys"); + + check(it->registered_finalizer_keys.find(finalizer_key) != it->registered_finalizer_keys.end(), "finalizer_key was not registered"); + + _finalizer_keys.erase( it ); + + if( is_active_producer(producer) ) { + delete_key_in_finalizer_policy(producer); + } + + // should we allow to delete a key if that makes the number of producers + // having registered keys drop below 15? + } +} /// namespace eosiosystem diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index 9f47d23b..75b85fe5 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -110,7 +110,9 @@ namespace eosiosystem { using value_type = std::pair; std::vector< value_type > top_producers; + std::vector< name > top_producer_names; top_producers.reserve(21); + top_producer_names.reserve(21); for( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active(); ++it ) { top_producers.emplace_back( @@ -120,6 +122,7 @@ namespace eosiosystem { }, it->location ); + top_producer_names.emplace_back(it->owner); } if( top_producers.size() == 0 || top_producers.size() < _gstate.last_producer_schedule_size ) { @@ -140,6 +143,10 @@ namespace eosiosystem { if( set_proposed_producers( producers ) >= 0 ) { _gstate.last_producer_schedule_size = static_cast( top_producers.size() ); } + + if( is_savanna_consensus() ) { + check(set_next_finalizers_set( top_producer_names ), "set_next_finalizers_set failed (less than 15 producers have registered keys"); + } } double stake2vote( int64_t staked ) { From 96d4877edf319905a86dce42b6eafce95061be9e Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 1 Apr 2024 13:37:50 -0400 Subject: [PATCH 35/94] First working version of core contact actions for Savanna --- .../include/eosio.system/eosio.system.hpp | 50 ++- contracts/eosio.system/src/eosio.system.cpp | 5 + contracts/eosio.system/src/finalizer_key.cpp | 296 ++++++++++++------ contracts/eosio.system/src/voting.cpp | 37 ++- tests/eosio.finalizer_key_tests.cpp | 182 +++++++++++ 5 files changed, 455 insertions(+), 115 deletions(-) create mode 100644 tests/eosio.finalizer_key_tests.cpp diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 5d87a492..81a0dbfe 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include #include #ifdef CHANNEL_RAM_AND_NAMEBID_FEES_TO_REX @@ -201,9 +203,13 @@ namespace eosiosystem { // It is also used as an indicator Savanna consensus has been switched over. struct [[eosio::table("global5"), eosio::contract("eosio.system")]] eosio_global_state5 { eosio_global_state5() { } - std::vector last_finalizers; + // The data structure was chosen to optimize for fast check whether a finalizer + // key is used in last finalizer policy. + // Could cache entire finalizer_authorities; but that's only needed when + // replacing an active producer's active key, which happens rarely. + std::set last_finalizer_key_ids; - EOSLIB_SERIALIZE( eosio_global_state5, (last_finalizers) ) + EOSLIB_SERIALIZE( eosio_global_state5, (last_finalizer_key_ids) ) }; inline eosio::block_signing_authority convert_to_block_signing_authority( const eosio::public_key& producer_key ) { @@ -292,17 +298,33 @@ namespace eosiosystem { }; // Defines finalizer_key info structure to be stored in finalizer_keys info table, added after version 6.0 - struct [[eosio::table, eosio::contract("eosio.system")]] finalizer_key_info { - name producer; - std::string active_finalizer_key; // the currently active key - std::unordered_set registered_finalizer_keys; // including the active_finalizer_key + struct [[eosio::table("finkeys"), eosio::contract("eosio.system")]] finalizer_key_info { + uint64_t id; + name finalizer; + std::string finalizer_key; // base64url + + uint64_t primary_key() const { return id; } + uint64_t by_finalizer() const { return finalizer.value; } + checksum256 by_fin_key() const { auto g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); return eosio::sha256(g1.data(), g1.size()); } + }; - uint64_t primary_key()const { return producer.value; } + typedef eosio::multi_index< + "finkeys"_n, finalizer_key_info, + indexed_by<"byfinalizer"_n, const_mem_fun>, + indexed_by<"byfinkey"_n, const_mem_fun> + > finalizer_keys_table; - // explicit serialization macro is not necessary, used here only to improve compilation time - EOSLIB_SERIALIZE( finalizer_key_info, (producer)(active_finalizer_key)(active_finalizer_key) ) + struct [[eosio::table("finalizers"), eosio::contract("eosio.system")]] finalizer_info { + name finalizer; + uint64_t active_key_id; + std::vector active_key; // Affine little endian non-montgomery g1 + uint32_t num_registered_keys; + + uint64_t primary_key() const { return finalizer.value; } }; + typedef eosio::multi_index< "finalizers"_n, finalizer_info > finalizers_table; + // Voter info. Voter info stores information about the voter: // - `owner` the voter // - `proxy` the proxy set by the voter, if any @@ -350,8 +372,6 @@ namespace eosiosystem { typedef eosio::multi_index< "producers2"_n, producer_info2 > producers_table2; - typedef eosio::multi_index< "finalizer_key"_n, finalizer_key_info > finalizer_keys_table; - typedef eosio::singleton< "global"_n, eosio_global_state > global_state_singleton; typedef eosio::singleton< "global2"_n, eosio_global_state2 > global_state2_singleton; @@ -707,6 +727,7 @@ namespace eosiosystem { producers_table _producers; producers_table2 _producers2; finalizer_keys_table _finalizer_keys; + finalizers_table _finalizers; global_state_singleton _global; global_state2_singleton _global2; global_state3_singleton _global3; @@ -1226,7 +1247,7 @@ namespace eosiosystem { * @pre Authority of `producer` to register */ [[eosio::action]] - void regfinkey( const name& producer, const std::string& finalizer_key, const std::string& proof_of_possession); + void regfinkey( const name& finalizer, const std::string& finalizer_key, const std::string& proof_of_possession); /** * Activate a finalizer key action. If the block producer is currently @@ -1595,6 +1616,11 @@ namespace eosiosystem { double update_total_votepay_share( const time_point& ct, double additional_shares_delta = 0.0, double shares_rate_delta = 0.0 ); + // defined in finalizer_key.cpp + bool is_savanna_consensus() const; + void set_finalizers( const std::vector& finalizer_authorities, const std::set& finalizer_key_ids ); + void replace_key_in_finalizer_policy(const name& finalizer, uint64_t old_id, uint64_t new_id); + template class registration { public: diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index 527b0324..b85720f1 100644 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -20,10 +20,13 @@ namespace eosiosystem { _voters(get_self(), get_self().value), _producers(get_self(), get_self().value), _producers2(get_self(), get_self().value), + _finalizer_keys(get_self(), get_self().value), + _finalizers(get_self(), get_self().value), _global(get_self(), get_self().value), _global2(get_self(), get_self().value), _global3(get_self(), get_self().value), _global4(get_self(), get_self().value), + _global5(get_self(), get_self().value), _rammarket(get_self(), get_self().value), _rexpool(get_self(), get_self().value), _rexretpool(get_self(), get_self().value), @@ -36,6 +39,7 @@ namespace eosiosystem { _gstate2 = _global2.exists() ? _global2.get() : eosio_global_state2{}; _gstate3 = _global3.exists() ? _global3.get() : eosio_global_state3{}; _gstate4 = _global4.exists() ? _global4.get() : get_default_inflation_parameters(); + _gstate5 = _global5.exists() ? _global5.get() : eosio_global_state5{}; } eosio_global_state system_contract::get_default_parameters() { @@ -62,6 +66,7 @@ namespace eosiosystem { _global2.set( _gstate2, get_self() ); _global3.set( _gstate3, get_self() ); _global4.set( _gstate4, get_self() ); + _global5.set( _gstate5, get_self() ); } void system_contract::setram( uint64_t max_ram_size ) { diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 386bfd1d..1e0f0490 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -2,157 +2,251 @@ #include #include -#include namespace eosiosystem { - bool system_contract::is_savanna_consensus() { - return !_gstate5.last_finalizers.empty(); - } + // Action to switch to Savanna + void system_contract::switchtosvnn() { + require_auth(get_self()); - bool system_contract::is_registered_producer( const name& producer ) { - // Returns true if `producer` is a registered producer - } + check(!is_savanna_consensus(), "switchtosvnn can be run only once"); - bool system_contract::is_active_producer( const name& producer ) { - // Returns true if `producer` is an active producer (top 21) - } + using value_type = std::pair; + std::vector top_producers; + std::vector top_producer_names; + std::vector finalizer_authorities; + std::set next_finalizer_key_ids; + top_producers.reserve(21); + top_producer_names.reserve(21); + finalizer_authorities.reserve(21); - bool set_next_finalizers_set(const std::vector& producers ) { - // Build finalizer set - std::vector finalizers; - for ( const auto p&: producers ) { - auto it = _finalizer_keys.find( p.value ); - if( it != _finalizer_keys.end() ) { // p has registered a finalizer key - finalizers.emplace_back( - finalizer_authority{ - .description = "", + // From up to 30 top producers, find 21 producers that meet all the normal requirements + // for being a proposer and also have an active finalizer key + uint32_t n = 0; + auto idx = _producers.get_index<"prototalvote"_n>(); + for( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active(); ++it ) { + if( n > 30 ) { + break; + } + ++n; + + auto finalizer = _finalizers.find( it->owner.value ); + // If a producer is found in finalizers_table, it means it has at least one finalizer + // key registered, and one of them must be active + if( finalizer != _finalizers.end() ) { + check( !finalizer->active_key.empty(), "Active finalizer key of a finalizer in finalizers_table cannot be empty" ); + + // builds up producer_authority + top_producers.emplace_back( + eosio::producer_authority{ + .producer_name = it->owner, + .authority = it->get_producer_authority() + }, + it->location + ); + top_producer_names.emplace_back(it->owner); + + // builds up finalizer_authorities + next_finalizer_key_ids.insert(finalizer->active_key_id); + finalizer_authorities.emplace_back( + eosio::finalizer_authority{ + .description = it->owner.to_string(), .weight = 1, - .public_key = it->active_key + .public_key = finalizer->active_key } ); } } - // Abort if less than 15 top producers have registered a finalizer key - if( finalizers.size < 15 ) { - return false; - } + check( top_producers.size() > 0 && top_producers.size() >= _gstate.last_producer_schedule_size, "not enough top producers have registered finalizer keys" ); - // Establish finalizer policy and call set_finalizers() host function - finalizer_policy fin_policy { - .generation = 0; - .threshold = 15; - .finalizers = finalizers; - }; - set_finalizers(std::move(fin_policy)); + std::sort( top_producers.begin(), top_producers.end(), []( const value_type& lhs, const value_type& rhs ) { + return lhs.first.producer_name < rhs.first.producer_name; // sort by producer name + // return lhs.second < rhs.second; // sort by location + } ); - _gstate5.last_finalizers = finalizers; + std::vector producers; - return true; - } + producers.reserve(top_producers.size()); + for( auto& item : top_producers ) + producers.push_back( std::move(item.first) ); - void replace_key_in_finalizer_policy(const name& producer, const std::string& finalizer_key) { - // replace the key in last finalizer policy and call set_finalizers - // host function immediately - } + if( set_proposed_producers( producers ) >= 0 ) { + // what block_time to use here? + //_gstate.last_producer_schedule_update = block_time; + _gstate.last_producer_schedule_size = static_cast( top_producers.size() ); + } - void delete_key_in_finalizer_policy(const name& producer, const std::string& finalizer_key) { - // replace the key in last finalizer policy and call set_finalizers - // host function immediately + set_finalizers(finalizer_authorities, next_finalizer_key_ids); } - void system_contract::switchtosvnn() { - require_auth(get_self()); - - check(!is_savanna_consensus(), "switchtosvnn can only be run once"); + bool system_contract::is_savanna_consensus() const { + return !_gstate5.last_finalizer_key_ids.empty(); + } - // Find top 21 block producers - auto idx = _producers.get_index<"prototalvote"_n>(); - std::vector top_producers; - top_producers.reserve(21); - for( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active(); ++it ) { - top_producers.emplace_back(it->owner); - } - if( top_producers.size() < 21 ) { - return; - } + void system_contract::set_finalizers( const std::vector& finalizer_authorities, const std::set& finalizer_key_ids ) { + // Establish finalizer policy and call set_finalizers() host function + eosio::finalizer_policy fin_policy { + .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, // or hardcoded to 15? + .finalizers = finalizer_authorities + }; + eosio::set_finalizers(std::move(fin_policy)); // call host function - set_next_finalizers_set(top_producers); + _gstate5.last_finalizer_key_ids = finalizer_key_ids; } - void system_contract::regfinkey( const name& producer, const std::string& finalizer_key, const std::string& proof_of_possession) { - require_auth( producer ); + // Action to register a finalizer key + void system_contract::regfinkey( const name& finalizer, const std::string& finalizer_key, const std::string& proof_of_possession) { + require_auth( finalizer ); - check( is_registered_producer(producer), "The producer is not a registered producer"); + auto producer = _producers.find( finalizer.value ); + check( producer != _producers.end(), "finalizer is not a registered producer"); // Basic key and signature format check check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key must start with PUB_BLS"); check(proof_of_possession.compare(0, 7, "SIG_BLS") == 0, "proof of possession siganture must start with SIG_BLS"); - // Proof of possession check - const auto pk = eosio::decode_bls_public_key_to_g1(finalizer_key); + // Convert to binary form + const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); const auto signature = eosio::decode_bls_signature_to_g2(proof_of_possession); - check(eosio::bls_pop_verify(pk, signature), "proof of possession check failed"); - // Todo: Go over finalizer_keys_table to make sure no duplicate keys are - // registered. + // Duplication check across all registered keys + auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); + auto hash = eosio::sha256(fin_key_g1.data(), fin_key_g1.size()); + check(idx.lower_bound(hash) == idx.end(), "duplicate finalizer key"); + + // Proof of possession check is expensive, do it at last + check(eosio::bls_pop_verify(fin_key_g1, signature), "proof of possession check failed"); - auto it = _finalizer_keys.find( producer.value ); - if( it != _finalizer_keys.end() ) { - _finalizer_keys.modify( it, same_payer, [&]( auto& k ) { - k.registered_finalizer_keys.insert(finalizer_key); + // Insert into finalyzer_keys table + auto key_itr = _finalizer_keys.emplace( finalizer, [&]( auto& k ) { + k.id = _finalizer_keys.available_primary_key(); + k.finalizer = finalizer; + k.finalizer_key = finalizer_key; + }); + + // Update finalizers table + auto f_itr = _finalizers.find(finalizer.value); + if( f_itr == _finalizers.end() ) { + // First time the finalizer to register a finalier key, + // make the key active + _finalizers.emplace( finalizer, [&]( auto& f ) { + f.finalizer = finalizer; + f.active_key_id = key_itr->id; + f.active_key = { fin_key_g1.begin(), fin_key_g1.end() }; + f.num_registered_keys = 1; }); } else { - // The first time the producer registers a finalizer key - _finalizer_keys.emplace( producer, [&]( auto& p ) { - k.producer = producer; - k.registered_finalizer_keys.insert(finalizer_key); - k.active_key = finalizer_key; + // Update num_registered_keys + _finalizers.modify( f_itr, same_payer, [&]( auto& f ) { + ++f.num_registered_keys; }); - - if( is_active_producer(producer) ) { - replace_key_in_finalizer_policy(producer, finalizer_key); - } } } - void system_contract::actfinkey( const name& producer, const std::string& finalizer_key ) { - require_auth( producer ); + // Action to activate a finalizer key + void system_contract::actfinkey( const name& finalizer, const std::string& finalizer_key ) { + require_auth( finalizer ); - check( is_registered_producer(producer), "The producer is not a registered producer"); + auto producer = _producers.find( finalizer.value ); + check( producer != _producers.end(), "finalizer is not a registered producer"); - auto it = _finalizer_keys.find( producer.value ); - check(it != _finalizer_keys.end(), "producer has not registered any keys"); - - check(it->registered_finalizer_keys.find(finalizer_key) != it->registered_finalizer_keys.end(), "finalizer_key was not registered"); - - _finalizer_keys.modify( it, same_payer, [&]( auto& k ) { - k.active_finalizer_key = finalizer_key; + // Check the key is registered + const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); + auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); + auto hash = eosio::sha256(fin_key_g1.data(), fin_key_g1.size()); + auto fin_key = idx.lower_bound(hash); + check(fin_key != idx.end(), "finalizer key was not registered"); + + // Check the key belongs to finalizer + check(fin_key->finalizer == finalizer, "finalizer_key was not registered by the finalizer"); + + // Check finalizer itself + auto fin = _finalizers.find(finalizer.value); + check( fin != _finalizers.end(), "finalizer is not in the finalizers table" ); + check( fin->num_registered_keys > 0, "num_registered_keys of the finalizer must be greater than one" ); + + // Check if the finalizer key is not already active + check( fin_key->id != fin->active_key_id, "the finalizer key was already active" ); + + auto old_active_key_id = fin->active_key_id; + + _finalizers.modify( fin, same_payer, [&]( auto& f ) { + f.active_key_id = fin_key->id; + f.active_key = { fin_key_g1.begin(), fin_key_g1.end() }; }); - if( is_active_producer(producer) ) { - replace_key_in_finalizer_policy(producer, finalizer_key); + // Replace the finalizer policy immediately if the finalizer is + // participating in current voting + if( _gstate5.last_finalizer_key_ids.contains(old_active_key_id) ) { + replace_key_in_finalizer_policy(finalizer, old_active_key_id, fin_key->id); } } - void system_contract::delfinkey( const name& producer, const std::string& finalizer_key ) { - require_auth( producer ); + // replace the key in last finalizer policy and call set_finalizers host function immediately + void system_contract::replace_key_in_finalizer_policy(const name& finalizer, uint64_t old_id, uint64_t new_id) { + std::set next_finalizer_key_ids {_gstate5.last_finalizer_key_ids}; + std::vector finalizer_authorities; + finalizer_authorities.reserve(next_finalizer_key_ids.size()); + + // replace key ID in last_finalizer_key_ids + next_finalizer_key_ids.erase(old_id); + next_finalizer_key_ids.insert(new_id); + + for( const auto id : next_finalizer_key_ids ) { + auto key = _finalizer_keys.find(id); + check( key != _finalizer_keys.end(), "key not found in finalizer_keys table for replace_key_in_finalizer_policy"); + const auto pk = eosio::decode_bls_public_key_to_g1(key->finalizer_key); + finalizer_authorities.emplace_back( + eosio::finalizer_authority{ + .description = key->finalizer.to_string(), + .weight = 1, + .public_key = { pk.begin(), pk.end() } + } + ); + } - check( is_registered_producer(producer), "The producer is not a registered producer"); + set_finalizers(finalizer_authorities, next_finalizer_key_ids); + } - auto it = _finalizer_keys.find( producer.value ); - check(it != _finalizer_keys.end(), "producer has not registered any keys"); + // Action to delete a registered finalizer key + void system_contract::delfinkey( const name& finalizer, const std::string& finalizer_key ) { + require_auth( finalizer ); + + auto producer = _producers.find( finalizer.value ); + check( producer != _producers.end(), "finalizer is not a registered producer"); + + // Check the key is registered + const auto pk = eosio::decode_bls_public_key_to_g1(finalizer_key); + auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); + auto hash = eosio::sha256(pk.data(), pk.size()); + auto fin_key = idx.lower_bound(hash); + check(fin_key != idx.end(), "finalizer_key was not registered"); + + // Check the key belongs to finalizer + check(fin_key->finalizer == finalizer, "finalizer_key was not registered by the finalizer"); - check(it->registered_finalizer_keys.find(finalizer_key) != it->registered_finalizer_keys.end(), "finalizer_key was not registered"); + // Cross check finalizers table + auto fin = _finalizers.find(finalizer.value); + check( fin != _finalizers.end(), "finalizer is not in the finalizers table" ); + check( fin->num_registered_keys > 0, "num_registered_keys of the finalizer must be greater than one" ); - _finalizer_keys.erase( it ); - - if( is_active_producer(producer) ) { - delete_key_in_finalizer_policy(producer); + if( fin_key->id == fin->active_key_id ) { + check( fin->num_registered_keys == 1, "cannot delete an active key unless it is the last registered finalizer key"); } - // should we allow to delete a key if that makes the number of producers - // having registered keys drop below 15? + // Remove the key from finalizer_keys table + idx.erase( fin_key ); + + // Update finalizers table + if( fin->num_registered_keys == 1 ) { + // The finalizer does not have any registered keys. Remove it from finalizers table. + _finalizers.erase( fin ); + } else { + // Decrement num_registered_keys finalizers table + _finalizers.modify( fin, same_payer, [&]( auto& f ) { + --f.num_registered_keys; + }); + } } } /// namespace eosiosystem diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index 75b85fe5..50c63623 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -111,10 +111,40 @@ namespace eosiosystem { using value_type = std::pair; std::vector< value_type > top_producers; std::vector< name > top_producer_names; + std::vector< eosio::finalizer_authority > next_finalizer_authorities; + std::set< uint64_t > next_finalizer_key_ids; top_producers.reserve(21); top_producer_names.reserve(21); + next_finalizer_authorities.reserve(21); + bool new_finalizer_keys_found = false; for( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active(); ++it ) { + if( is_savanna_consensus() ) { + auto finalizer = _finalizers.find( it->owner.value ); + if( finalizer == _finalizers.end() ) { + // The producer is not in finalizers table, indicating it does not have an + // active registered finalizer key. Try next one. + continue; + } + + // If the producer's finalizer_key_id is not in last_finalizer_key_ids, + // it means a new finalizer policy is needed. + if( !_gstate5.last_finalizer_key_ids.contains(finalizer->active_key_id) ) { + new_finalizer_keys_found = true; + } + + // Store finalizer key ID and pre-build finalizer_authorities in case + // we need to set new finalizer policy + next_finalizer_key_ids.insert(finalizer->active_key_id); + next_finalizer_authorities.emplace_back( + eosio::finalizer_authority{ + .description = it->owner.to_string(), + .weight = 1, + .public_key = finalizer->active_key + } + ); + } + top_producers.emplace_back( eosio::producer_authority{ .producer_name = it->owner, @@ -144,8 +174,11 @@ namespace eosiosystem { _gstate.last_producer_schedule_size = static_cast( top_producers.size() ); } - if( is_savanna_consensus() ) { - check(set_next_finalizers_set( top_producer_names ), "set_next_finalizers_set failed (less than 15 producers have registered keys"); + // Only set a new finalizer policy if it has changed. + // Even if no new finalizer key found, the size must be match to account for if + // any finalizers are removed. + if( is_savanna_consensus() && (new_finalizer_keys_found || next_finalizer_authorities.size() != _gstate5.last_finalizer_key_ids.size()) ) { + set_finalizers( next_finalizer_authorities, next_finalizer_key_ids ); } } diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp new file mode 100644 index 00000000..51270cb7 --- /dev/null +++ b/tests/eosio.finalizer_key_tests.cpp @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "eosio.system_tester.hpp" + +using namespace eosio_system; + +struct finalizer_key_tester : eosio_system_tester { + fc::variant get_finalizer_info( const account_name& act ) { + vector data = get_row_by_account( config::system_account_name, config::system_account_name, "finalizers"_n, act ); + return abi_ser.binary_to_variant( "finalizer_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); + } +}; + +BOOST_AUTO_TEST_SUITE(eosio_system_finalizer_key_tests) + +BOOST_FIXTURE_TEST_CASE(register_finalizer_key_invalid_key_tests, finalizer_key_tester) try { + { // attempt to register finalizer_key for an unregistered producer + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer is not a registered producer" ), + push_action("alice1111111"_n, "regfinkey"_n, mvo() + ("finalizer", "alice1111111") + ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) + ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") + ) ); + } + + // Now alice1111111 registers as a producer + BOOST_REQUIRE_EQUAL( success(), regproducer("alice1111111"_n) ); + + { // finalizer key does not start with PUB_BLS + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key must start with PUB_BLS" ), + push_action("alice1111111"_n, "regfinkey"_n, mvo() + ("finalizer", "alice1111111") + ("finalizer_key", "UB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) + ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") + ) ); + } + + { // proof_of_possession does not start with SIG_BLS + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "proof of possession siganture must start with SIG_BLS" ), + push_action("alice1111111"_n, "regfinkey"_n, mvo() + ("finalizer", "alice1111111") + ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) + ("proof_of_possession", "XIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") + ) ); + } + + { // proof_of_possession fails + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "proof of possession check failed" ), + push_action("alice1111111"_n, "regfinkey"_n, mvo() + ("finalizer", "alice1111111") + // use a valid formatted finalizer_key for another signature + ("finalizer_key", "PUB_BLS_gtaOjOTa0NzDt8etBDqLoZKlfKTpTalcdfmbTJknLUJB2Fu4Cv-uoa8unF3bJ5kFewaCzf3tjYUyNE6CDSrwvYP5Nw47Y9oE9x4nqJWfJykMOoaI0kJz-GDrGN2nZdUAp5tWEg" ) + ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") + ) ); + } +} // register_finalizer_key_invalid_key_tests +FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_same_finalizer_tests, finalizer_key_tester) try { + BOOST_REQUIRE_EQUAL( success(), regproducer("alice1111111"_n) ); + + // First finalizer key + BOOST_REQUIRE_EQUAL( success(), + push_action("alice1111111"_n, "regfinkey"_n, mvo() + ("finalizer", "alice1111111"_n) + ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) + ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") + ) ); + + auto fin_info = get_finalizer_info("alice1111111"_n); + BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer"].as_string() ); + BOOST_REQUIRE_EQUAL( 1, fin_info["num_registered_keys"].as_uint64() ); + uint64_t active_key_id = fin_info["active_key_id"].as_uint64(); + + // ToDo: cross check finalizer keys table + + // Second finalizer key + BOOST_REQUIRE_EQUAL( success(), + push_action("alice1111111"_n, "regfinkey"_n, mvo() + ("finalizer", "alice1111111"_n) + ("finalizer_key", "PUB_BLS_gtaOjOTa0NzDt8etBDqLoZKlfKTpTalcdfmbTJknLUJB2Fu4Cv-uoa8unF3bJ5kFewaCzf3tjYUyNE6CDSrwvYP5Nw47Y9oE9x4nqJWfJykMOoaI0kJz-GDrGN2nZdUAp5tWEg" ) + ("proof_of_possession", "SIG_BLS_9e1SzM60bWLdxwz4lYNQMNzMGeFuzFgJDYy7WykmynRVRQeIx2O2xnyzwv1WXvgYHLyMYZ4wK0Y_kU6jl330WazkBsw-_GzvIOGy8fnBnt5AyMaj9X5bhDbvB5MZc0QQz4-P2Z4SltTY17ZItGeekkjX_fgQ9kegM4qnuGU-2iqFj5i3Qf322L77b2SHjFoLmxdFOsfGpz7LyImSP8GcZH39W30cj5bmxfsp_90tGdAkz-7DG9nhSHYxFq6qTqMGijVPGg") + ) ); + + auto fin_info2 = get_finalizer_info("alice1111111"_n); + BOOST_REQUIRE_EQUAL( 2, fin_info2["num_registered_keys"].as_uint64() ); // count incremented by 1 + BOOST_REQUIRE_EQUAL( active_key_id, fin_info2["active_key_id"].as_uint64() ); // active key should not change +} +FC_LOG_AND_RETHROW() // register_finalizer_key_by_same_finalizer_tests + +BOOST_FIXTURE_TEST_CASE(register_finalizer_key_duplicate_key_tests, finalizer_key_tester) try { + BOOST_REQUIRE_EQUAL( success(), regproducer("alice1111111"_n) ); + + // The first finalizer key + BOOST_REQUIRE_EQUAL( success(), + push_action("alice1111111"_n, "regfinkey"_n, mvo() + ("finalizer", "alice1111111"_n) + ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) + ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") + ) ); + + auto fin_info = get_finalizer_info("alice1111111"_n); + BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer"].as_string() ); + BOOST_REQUIRE_EQUAL( 1, fin_info["num_registered_keys"].as_uint64() ); + + // Same finalizer key as the first one + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "duplicate finalizer key" ), + push_action("alice1111111"_n, "regfinkey"_n, mvo() + ("finalizer", "alice1111111"_n) + ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) + ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") + ) ); +} +FC_LOG_AND_RETHROW() // register_finalizer_key_duplicate_key_tests + +BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_different_finalizers_tests, finalizer_key_tester) try { + // register 2 producers + BOOST_REQUIRE_EQUAL( success(), regproducer("alice1111111"_n) ); + BOOST_REQUIRE_EQUAL( success(), regproducer("bob111111111"_n) ); + + // alice1111111 registers a finalizer key + BOOST_REQUIRE_EQUAL( success(), + push_action("alice1111111"_n, "regfinkey"_n, mvo() + ("finalizer", "alice1111111"_n) + ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) + ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") + ) ); + + auto fin_info = get_finalizer_info("alice1111111"_n); + BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer"].as_string() ); + BOOST_REQUIRE_EQUAL( 1, fin_info["num_registered_keys"].as_uint64() ); + + // bob111111111 registers another finalizer key + BOOST_REQUIRE_EQUAL( success(), + push_action("bob111111111"_n, "regfinkey"_n, mvo() + ("finalizer", "bob111111111"_n) + ("finalizer_key", "PUB_BLS_gtaOjOTa0NzDt8etBDqLoZKlfKTpTalcdfmbTJknLUJB2Fu4Cv-uoa8unF3bJ5kFewaCzf3tjYUyNE6CDSrwvYP5Nw47Y9oE9x4nqJWfJykMOoaI0kJz-GDrGN2nZdUAp5tWEg" ) + ("proof_of_possession", "SIG_BLS_9e1SzM60bWLdxwz4lYNQMNzMGeFuzFgJDYy7WykmynRVRQeIx2O2xnyzwv1WXvgYHLyMYZ4wK0Y_kU6jl330WazkBsw-_GzvIOGy8fnBnt5AyMaj9X5bhDbvB5MZc0QQz4-P2Z4SltTY17ZItGeekkjX_fgQ9kegM4qnuGU-2iqFj5i3Qf322L77b2SHjFoLmxdFOsfGpz7LyImSP8GcZH39W30cj5bmxfsp_90tGdAkz-7DG9nhSHYxFq6qTqMGijVPGg") + ) ); + + auto fin_info2 = get_finalizer_info("bob111111111"_n); + BOOST_REQUIRE_EQUAL( 1, fin_info2["num_registered_keys"].as_uint64() ); +} +FC_LOG_AND_RETHROW() // register_finalizer_key_by_different_finalizers_tests + + +BOOST_FIXTURE_TEST_CASE(register_duplicate_key_from_different_finalizers_tests, finalizer_key_tester) try { + BOOST_REQUIRE_EQUAL( success(), regproducer("alice1111111"_n) ); + BOOST_REQUIRE_EQUAL( success(), regproducer("bob111111111"_n) ); + + // The first finalizer key + BOOST_REQUIRE_EQUAL( success(), + push_action("alice1111111"_n, "regfinkey"_n, mvo() + ("finalizer", "alice1111111"_n) + ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) + ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") + ) ); + + auto fin_info = get_finalizer_info("alice1111111"_n); + BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer"].as_string() ); + BOOST_REQUIRE_EQUAL( 1, fin_info["num_registered_keys"].as_uint64() ); + + // bob111111111 tries to register the same finalizer key as the first one + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "duplicate finalizer key" ), + push_action("bob111111111"_n, "regfinkey"_n, mvo() + ("finalizer", "bob111111111"_n) + ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) + ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") + ) ); +} +FC_LOG_AND_RETHROW() // register_duplicate_key_from_different_finalizers_tests + +BOOST_AUTO_TEST_SUITE_END() From c929439ae129212cd10b2c4c029e723b59e8fb7a Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 2 Apr 2024 21:52:06 -0400 Subject: [PATCH 36/94] rename producer to finalizer in all finalizer key actions --- .../include/eosio.system/eosio.system.hpp | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 81a0dbfe..9528e6d4 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1239,12 +1239,12 @@ namespace eosiosystem { * by other block producers, the registration will fail. * A registered producer can have multiple registered finalizer keys. * - * @param producer - account registering `finalizer_key`, + * @param finalizer - account registering `finalizer_key`, * @param finalizer_key - key to be registered. The key is in base64url format. * @param proof_of_possession - a valid Proof of Possession signature to show the producer owns the private key of the finalizer_key. The signature is in base64url format. * - * @pre `producer` must be a registered producer - * @pre Authority of `producer` to register + * @pre `finalizer` must be a registered producer + * @pre Authority of `finalizer` to register */ [[eosio::action]] void regfinkey( const name& finalizer, const std::string& finalizer_key, const std::string& proof_of_possession); @@ -1255,30 +1255,30 @@ namespace eosiosystem { * Activating a finalizer key of a block producer implicitly deactivates * the previously active finalizer key of that block producer. * - * @param producer - account activating `finalizer_key`, + * @param finalizer - account activating `finalizer_key`, * @param finalizer_key - key to be activated. * - * @pre `producer` must be a registered producer + * @pre `finalizer` must be a registered producer * @pre `finalizer_key` must be a registered finalizer key - * @pre Authority of `producer` + * @pre Authority of `finalizer` */ [[eosio::action]] - void actfinkey( const name& producer, const std::string& finalizer_key ); + void actfinkey( const name& finalizer, const std::string& finalizer_key ); /** * Delete a finalizer key action which is not active unless it is the * last regitered finalizer key. * - * @param producer - account deleting `finalizer_key`, + * @param finalizer - account deleting `finalizer_key`, * @param finalizer_key - key to be deleted. * - * @pre `producer` must be a registered producer + * @pre `finalizer` must be a registered producer * @pre `finalizer_key` must be a registered finalizer key * @pre `finalizer_key` must be not be active, unless it is the last regitered finalizer key - * @pre Authority of `producer` + * @pre Authority of `finalizer` */ [[eosio::action]] - void delfinkey( const name& producer, const std::string& finalizer_key ); + void delfinkey( const name& finalizer, const std::string& finalizer_key ); /** * Set ram action sets the ram supply. From bdd7f8e149845390640f1462cb9f994e05acdca1 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 2 Apr 2024 21:53:54 -0400 Subject: [PATCH 37/94] Check if finalizer has registered any keys earlier --- contracts/eosio.system/src/finalizer_key.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 1e0f0490..a4f8cf17 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -151,6 +151,11 @@ namespace eosiosystem { auto producer = _producers.find( finalizer.value ); check( producer != _producers.end(), "finalizer is not a registered producer"); + // Check finalizer has registered keys + auto fin = _finalizers.find(finalizer.value); + check( fin != _finalizers.end(), "finalizer has not registered any finalizer keys" ); + check( fin->num_registered_keys > 0, "num_registered_keys of the finalizer must be greater than one" ); + // Check the key is registered const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); @@ -161,11 +166,6 @@ namespace eosiosystem { // Check the key belongs to finalizer check(fin_key->finalizer == finalizer, "finalizer_key was not registered by the finalizer"); - // Check finalizer itself - auto fin = _finalizers.find(finalizer.value); - check( fin != _finalizers.end(), "finalizer is not in the finalizers table" ); - check( fin->num_registered_keys > 0, "num_registered_keys of the finalizer must be greater than one" ); - // Check if the finalizer key is not already active check( fin_key->id != fin->active_key_id, "the finalizer key was already active" ); From c4dbf90220301e82eaf714bd2711feb88a35ad87 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 3 Apr 2024 10:10:51 -0400 Subject: [PATCH 38/94] Remove unused top_producer_names and change a check() to an assert() --- contracts/eosio.system/src/finalizer_key.cpp | 5 +---- contracts/eosio.system/src/voting.cpp | 3 --- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index a4f8cf17..7bb67e0d 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -13,11 +13,9 @@ namespace eosiosystem { using value_type = std::pair; std::vector top_producers; - std::vector top_producer_names; std::vector finalizer_authorities; std::set next_finalizer_key_ids; top_producers.reserve(21); - top_producer_names.reserve(21); finalizer_authorities.reserve(21); // From up to 30 top producers, find 21 producers that meet all the normal requirements @@ -34,7 +32,7 @@ namespace eosiosystem { // If a producer is found in finalizers_table, it means it has at least one finalizer // key registered, and one of them must be active if( finalizer != _finalizers.end() ) { - check( !finalizer->active_key.empty(), "Active finalizer key of a finalizer in finalizers_table cannot be empty" ); + assert( !finalizer->active_key.empty() ); // builds up producer_authority top_producers.emplace_back( @@ -44,7 +42,6 @@ namespace eosiosystem { }, it->location ); - top_producer_names.emplace_back(it->owner); // builds up finalizer_authorities next_finalizer_key_ids.insert(finalizer->active_key_id); diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index 50c63623..14aa2ad0 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -110,11 +110,9 @@ namespace eosiosystem { using value_type = std::pair; std::vector< value_type > top_producers; - std::vector< name > top_producer_names; std::vector< eosio::finalizer_authority > next_finalizer_authorities; std::set< uint64_t > next_finalizer_key_ids; top_producers.reserve(21); - top_producer_names.reserve(21); next_finalizer_authorities.reserve(21); bool new_finalizer_keys_found = false; @@ -152,7 +150,6 @@ namespace eosiosystem { }, it->location ); - top_producer_names.emplace_back(it->owner); } if( top_producers.size() == 0 || top_producers.size() < _gstate.last_producer_schedule_size ) { From 097cd79686537ae0d572dd7b18ec401b1a37dca7 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 3 Apr 2024 10:21:00 -0400 Subject: [PATCH 39/94] Change er_authorities parameter in set_finalizers() to move semantics --- .../eosio.system/include/eosio.system/eosio.system.hpp | 2 +- contracts/eosio.system/src/finalizer_key.cpp | 6 +++--- contracts/eosio.system/src/voting.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 9528e6d4..bafaa932 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1618,7 +1618,7 @@ namespace eosiosystem { // defined in finalizer_key.cpp bool is_savanna_consensus() const; - void set_finalizers( const std::vector& finalizer_authorities, const std::set& finalizer_key_ids ); + void set_finalizers( std::vector&& finalizer_authorities, const std::set& finalizer_key_ids ); void replace_key_in_finalizer_policy(const name& finalizer, uint64_t old_id, uint64_t new_id); template diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 7bb67e0d..d105123d 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -74,14 +74,14 @@ namespace eosiosystem { _gstate.last_producer_schedule_size = static_cast( top_producers.size() ); } - set_finalizers(finalizer_authorities, next_finalizer_key_ids); + set_finalizers(std::move(finalizer_authorities), next_finalizer_key_ids); } bool system_contract::is_savanna_consensus() const { return !_gstate5.last_finalizer_key_ids.empty(); } - void system_contract::set_finalizers( const std::vector& finalizer_authorities, const std::set& finalizer_key_ids ) { + void system_contract::set_finalizers( std::vector&& finalizer_authorities, const std::set& finalizer_key_ids ) { // Establish finalizer policy and call set_finalizers() host function eosio::finalizer_policy fin_policy { .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, // or hardcoded to 15? @@ -203,7 +203,7 @@ namespace eosiosystem { ); } - set_finalizers(finalizer_authorities, next_finalizer_key_ids); + set_finalizers(std::move(finalizer_authorities), next_finalizer_key_ids); } // Action to delete a registered finalizer key diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index 14aa2ad0..051a439b 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -175,7 +175,7 @@ namespace eosiosystem { // Even if no new finalizer key found, the size must be match to account for if // any finalizers are removed. if( is_savanna_consensus() && (new_finalizer_keys_found || next_finalizer_authorities.size() != _gstate5.last_finalizer_key_ids.size()) ) { - set_finalizers( next_finalizer_authorities, next_finalizer_key_ids ); + set_finalizers( std::move(next_finalizer_authorities), next_finalizer_key_ids ); } } From a70ea4653c8445835cd05cc783bf4053455c1741 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 3 Apr 2024 10:22:52 -0400 Subject: [PATCH 40/94] Use eosio::current_time_point() for _gstate.last_producer_schedule_update in switchtosvnn --- contracts/eosio.system/src/finalizer_key.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index d105123d..7418c9c1 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -69,8 +69,7 @@ namespace eosiosystem { producers.push_back( std::move(item.first) ); if( set_proposed_producers( producers ) >= 0 ) { - // what block_time to use here? - //_gstate.last_producer_schedule_update = block_time; + _gstate.last_producer_schedule_update = eosio::current_time_point(); _gstate.last_producer_schedule_size = static_cast( top_producers.size() ); } From 5908fb94ecb774886516b50386488a595a7883da Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 3 Apr 2024 10:29:51 -0400 Subject: [PATCH 41/94] Use producers.size() instead of top_producers.size() as that is what is actually used --- contracts/eosio.system/src/finalizer_key.cpp | 2 +- contracts/eosio.system/src/voting.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 7418c9c1..8b584ccd 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -70,7 +70,7 @@ namespace eosiosystem { if( set_proposed_producers( producers ) >= 0 ) { _gstate.last_producer_schedule_update = eosio::current_time_point(); - _gstate.last_producer_schedule_size = static_cast( top_producers.size() ); + _gstate.last_producer_schedule_size = static_cast( producers.size() ); } set_finalizers(std::move(finalizer_authorities), next_finalizer_key_ids); diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index 051a439b..a358d35c 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -168,7 +168,7 @@ namespace eosiosystem { producers.push_back( std::move(item.first) ); if( set_proposed_producers( producers ) >= 0 ) { - _gstate.last_producer_schedule_size = static_cast( top_producers.size() ); + _gstate.last_producer_schedule_size = static_cast( producers.size() ); } // Only set a new finalizer policy if it has changed. From 47535c2f08d95d039697080a815d20a3d890d715 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 3 Apr 2024 11:03:02 -0400 Subject: [PATCH 42/94] Update action descriptions --- .../include/eosio.system/eosio.system.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index bafaa932..a4bd6941 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1232,7 +1232,7 @@ namespace eosiosystem { void switchtosvnn(); /** - * Register a finalizer key action by a registered producer. + * Action to register a finalizer key by a registered producer. * If this is the first registered finalizer key of the producer, * it will also implicitly be marked active. * If this finalizer key was registered before (and still exists) even @@ -1250,13 +1250,13 @@ namespace eosiosystem { void regfinkey( const name& finalizer, const std::string& finalizer_key, const std::string& proof_of_possession); /** - * Activate a finalizer key action. If the block producer is currently + * Action to activate a finalizer key. If the block producer is currently * active (in top 21), then immediately change Finalizer Policy. * Activating a finalizer key of a block producer implicitly deactivates * the previously active finalizer key of that block producer. * * @param finalizer - account activating `finalizer_key`, - * @param finalizer_key - key to be activated. + * @param finalizer_key - key to be activated, in base64url format. * * @pre `finalizer` must be a registered producer * @pre `finalizer_key` must be a registered finalizer key @@ -1266,15 +1266,16 @@ namespace eosiosystem { void actfinkey( const name& finalizer, const std::string& finalizer_key ); /** - * Delete a finalizer key action which is not active unless it is the - * last regitered finalizer key. + * Action to delete a finalizer key. The key cannot be active unless + * it is the last registered finalizer key. If it is the last one, + * it will be deleted. * * @param finalizer - account deleting `finalizer_key`, * @param finalizer_key - key to be deleted. * * @pre `finalizer` must be a registered producer * @pre `finalizer_key` must be a registered finalizer key - * @pre `finalizer_key` must be not be active, unless it is the last regitered finalizer key + * @pre `finalizer_key` must be not be active, unless it is the last registered finalizer key * @pre Authority of `finalizer` */ [[eosio::action]] From 21e8dcb06c8e5c64c7baa857797b6550bd0a5482 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 3 Apr 2024 11:25:57 -0400 Subject: [PATCH 43/94] Use sha256 of base64url as the hash of the key, cache the hash to avoid re-hashing --- .../include/eosio.system/eosio.system.hpp | 3 ++- contracts/eosio.system/src/finalizer_key.cpp | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index a4bd6941..3c8425a9 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -302,10 +302,11 @@ namespace eosiosystem { uint64_t id; name finalizer; std::string finalizer_key; // base64url + checksum256 finalizer_key_hash; uint64_t primary_key() const { return id; } uint64_t by_finalizer() const { return finalizer.value; } - checksum256 by_fin_key() const { auto g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); return eosio::sha256(g1.data(), g1.size()); } + checksum256 by_fin_key() const { return finalizer_key_hash; } }; typedef eosio::multi_index< diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 8b584ccd..ccf53574 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -108,7 +108,7 @@ namespace eosiosystem { // Duplication check across all registered keys auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); - auto hash = eosio::sha256(fin_key_g1.data(), fin_key_g1.size()); + auto hash = eosio::sha256(finalizer_key.data(), finalizer_key.size()); check(idx.lower_bound(hash) == idx.end(), "duplicate finalizer key"); // Proof of possession check is expensive, do it at last @@ -116,9 +116,10 @@ namespace eosiosystem { // Insert into finalyzer_keys table auto key_itr = _finalizer_keys.emplace( finalizer, [&]( auto& k ) { - k.id = _finalizer_keys.available_primary_key(); - k.finalizer = finalizer; - k.finalizer_key = finalizer_key; + k.id = _finalizer_keys.available_primary_key(); + k.finalizer = finalizer; + k.finalizer_key = finalizer_key; + k.finalizer_key_hash = eosio::sha256(finalizer_key.data(), finalizer_key.size()); }); // Update finalizers table @@ -155,7 +156,7 @@ namespace eosiosystem { // Check the key is registered const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); - auto hash = eosio::sha256(fin_key_g1.data(), fin_key_g1.size()); + auto hash = eosio::sha256(finalizer_key.data(), finalizer_key.size()); auto fin_key = idx.lower_bound(hash); check(fin_key != idx.end(), "finalizer key was not registered"); @@ -213,9 +214,8 @@ namespace eosiosystem { check( producer != _producers.end(), "finalizer is not a registered producer"); // Check the key is registered - const auto pk = eosio::decode_bls_public_key_to_g1(finalizer_key); auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); - auto hash = eosio::sha256(pk.data(), pk.size()); + auto hash = eosio::sha256(finalizer_key.data(), finalizer_key.size()); auto fin_key = idx.lower_bound(hash); check(fin_key != idx.end(), "finalizer_key was not registered"); From cf14212a546b5673abd3352c66b641ac6ee9b879 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 3 Apr 2024 12:26:18 -0400 Subject: [PATCH 44/94] Rename finalizer to finalizer_name in actions and tables so it is more clear --- .../include/eosio.system/eosio.system.hpp | 28 +++++++++---------- contracts/eosio.system/src/finalizer_key.cpp | 10 +++---- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 3c8425a9..261a8e3c 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -300,28 +300,28 @@ namespace eosiosystem { // Defines finalizer_key info structure to be stored in finalizer_keys info table, added after version 6.0 struct [[eosio::table("finkeys"), eosio::contract("eosio.system")]] finalizer_key_info { uint64_t id; - name finalizer; + name finalizer_name; std::string finalizer_key; // base64url checksum256 finalizer_key_hash; - uint64_t primary_key() const { return id; } - uint64_t by_finalizer() const { return finalizer.value; } - checksum256 by_fin_key() const { return finalizer_key_hash; } + uint64_t primary_key() const { return id; } + uint64_t by_fin_name() const { return finalizer_name.value; } + checksum256 by_fin_key() const { return finalizer_key_hash; } }; typedef eosio::multi_index< "finkeys"_n, finalizer_key_info, - indexed_by<"byfinalizer"_n, const_mem_fun>, + indexed_by<"byfinname"_n, const_mem_fun>, indexed_by<"byfinkey"_n, const_mem_fun> > finalizer_keys_table; struct [[eosio::table("finalizers"), eosio::contract("eosio.system")]] finalizer_info { - name finalizer; + name finalizer_name; uint64_t active_key_id; std::vector active_key; // Affine little endian non-montgomery g1 uint32_t num_registered_keys; - uint64_t primary_key() const { return finalizer.value; } + uint64_t primary_key() const { return finalizer_name.value; } }; typedef eosio::multi_index< "finalizers"_n, finalizer_info > finalizers_table; @@ -1248,7 +1248,7 @@ namespace eosiosystem { * @pre Authority of `finalizer` to register */ [[eosio::action]] - void regfinkey( const name& finalizer, const std::string& finalizer_key, const std::string& proof_of_possession); + void regfinkey( const name& finalizer_name, const std::string& finalizer_key, const std::string& proof_of_possession); /** * Action to activate a finalizer key. If the block producer is currently @@ -1256,31 +1256,31 @@ namespace eosiosystem { * Activating a finalizer key of a block producer implicitly deactivates * the previously active finalizer key of that block producer. * - * @param finalizer - account activating `finalizer_key`, + * @param finalizer_name - account activating `finalizer_key`, * @param finalizer_key - key to be activated, in base64url format. * - * @pre `finalizer` must be a registered producer + * @pre `finalizer_name` must be a registered producer * @pre `finalizer_key` must be a registered finalizer key * @pre Authority of `finalizer` */ [[eosio::action]] - void actfinkey( const name& finalizer, const std::string& finalizer_key ); + void actfinkey( const name& finalizer_name, const std::string& finalizer_key ); /** * Action to delete a finalizer key. The key cannot be active unless * it is the last registered finalizer key. If it is the last one, * it will be deleted. * - * @param finalizer - account deleting `finalizer_key`, + * @param finalizer_name - account deleting `finalizer_key`, * @param finalizer_key - key to be deleted. * - * @pre `finalizer` must be a registered producer + * @pre `finalizer_name` must be a registered producer * @pre `finalizer_key` must be a registered finalizer key * @pre `finalizer_key` must be not be active, unless it is the last registered finalizer key * @pre Authority of `finalizer` */ [[eosio::action]] - void delfinkey( const name& finalizer, const std::string& finalizer_key ); + void delfinkey( const name& finalizer_name, const std::string& finalizer_key ); /** * Set ram action sets the ram supply. diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index ccf53574..3487d9a1 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -117,7 +117,7 @@ namespace eosiosystem { // Insert into finalyzer_keys table auto key_itr = _finalizer_keys.emplace( finalizer, [&]( auto& k ) { k.id = _finalizer_keys.available_primary_key(); - k.finalizer = finalizer; + k.finalizer_name = finalizer; k.finalizer_key = finalizer_key; k.finalizer_key_hash = eosio::sha256(finalizer_key.data(), finalizer_key.size()); }); @@ -128,7 +128,7 @@ namespace eosiosystem { // First time the finalizer to register a finalier key, // make the key active _finalizers.emplace( finalizer, [&]( auto& f ) { - f.finalizer = finalizer; + f.finalizer_name = finalizer; f.active_key_id = key_itr->id; f.active_key = { fin_key_g1.begin(), fin_key_g1.end() }; f.num_registered_keys = 1; @@ -161,7 +161,7 @@ namespace eosiosystem { check(fin_key != idx.end(), "finalizer key was not registered"); // Check the key belongs to finalizer - check(fin_key->finalizer == finalizer, "finalizer_key was not registered by the finalizer"); + check(fin_key->finalizer_name == finalizer, "finalizer_key was not registered by the finalizer"); // Check if the finalizer key is not already active check( fin_key->id != fin->active_key_id, "the finalizer key was already active" ); @@ -196,7 +196,7 @@ namespace eosiosystem { const auto pk = eosio::decode_bls_public_key_to_g1(key->finalizer_key); finalizer_authorities.emplace_back( eosio::finalizer_authority{ - .description = key->finalizer.to_string(), + .description = key->finalizer_name.to_string(), .weight = 1, .public_key = { pk.begin(), pk.end() } } @@ -220,7 +220,7 @@ namespace eosiosystem { check(fin_key != idx.end(), "finalizer_key was not registered"); // Check the key belongs to finalizer - check(fin_key->finalizer == finalizer, "finalizer_key was not registered by the finalizer"); + check(fin_key->finalizer_name == finalizer, "finalizer_key was not registered by the finalizer"); // Cross check finalizers table auto fin = _finalizers.find(finalizer.value); From 95cf0f9e208ac434cfc8793419e7a4e4be410bbc Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 3 Apr 2024 14:30:23 -0400 Subject: [PATCH 45/94] Use a table to store last finalizer key IDs --- .../include/eosio.system/eosio.system.hpp | 29 +++++--------- contracts/eosio.system/src/eosio.system.cpp | 4 +- contracts/eosio.system/src/finalizer_key.cpp | 40 +++++++++++-------- contracts/eosio.system/src/voting.cpp | 9 +++-- 4 files changed, 40 insertions(+), 42 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 261a8e3c..45c527ba 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #ifdef CHANNEL_RAM_AND_NAMEBID_FEES_TO_REX @@ -199,19 +198,6 @@ namespace eosiosystem { EOSLIB_SERIALIZE( eosio_global_state4, (continuous_rate)(inflation_pay_factor)(votepay_factor) ) }; - // Defines new global state parameters to store last finalizer set. - // It is also used as an indicator Savanna consensus has been switched over. - struct [[eosio::table("global5"), eosio::contract("eosio.system")]] eosio_global_state5 { - eosio_global_state5() { } - // The data structure was chosen to optimize for fast check whether a finalizer - // key is used in last finalizer policy. - // Could cache entire finalizer_authorities; but that's only needed when - // replacing an active producer's active key, which happens rarely. - std::set last_finalizer_key_ids; - - EOSLIB_SERIALIZE( eosio_global_state5, (last_finalizer_key_ids) ) - }; - inline eosio::block_signing_authority convert_to_block_signing_authority( const eosio::public_key& producer_key ) { return eosio::block_signing_authority_v0{ .threshold = 1, .keys = {{producer_key, 1}} }; } @@ -326,6 +312,14 @@ namespace eosiosystem { typedef eosio::multi_index< "finalizers"_n, finalizer_info > finalizers_table; + struct [[eosio::table("lastfkeyids"), eosio::contract("eosio.system")]] last_finkey_id_info { + uint64_t key_id; + + uint64_t primary_key() const { return key_id; } + }; + + typedef eosio::multi_index< "lastfkeyids"_n, last_finkey_id_info > last_finkey_ids_table; + // Voter info. Voter info stores information about the voter: // - `owner` the voter // - `proxy` the proxy set by the voter, if any @@ -381,8 +375,6 @@ namespace eosiosystem { typedef eosio::singleton< "global4"_n, eosio_global_state4 > global_state4_singleton; - typedef eosio::singleton< "global5"_n, eosio_global_state5 > global_state5_singleton; - struct [[eosio::table, eosio::contract("eosio.system")]] user_resources { name owner; asset net_weight; @@ -729,16 +721,15 @@ namespace eosiosystem { producers_table2 _producers2; finalizer_keys_table _finalizer_keys; finalizers_table _finalizers; + last_finkey_ids_table _last_finkey_ids; global_state_singleton _global; global_state2_singleton _global2; global_state3_singleton _global3; global_state4_singleton _global4; - global_state5_singleton _global5; eosio_global_state _gstate; eosio_global_state2 _gstate2; eosio_global_state3 _gstate3; eosio_global_state4 _gstate4; - eosio_global_state5 _gstate5; rammarket _rammarket; rex_pool_table _rexpool; rex_return_pool_table _rexretpool; @@ -1620,7 +1611,7 @@ namespace eosiosystem { // defined in finalizer_key.cpp bool is_savanna_consensus() const; - void set_finalizers( std::vector&& finalizer_authorities, const std::set& finalizer_key_ids ); + void set_finalizers( std::vector&& finalizer_authorities, const std::vector& finalizer_key_ids ); void replace_key_in_finalizer_policy(const name& finalizer, uint64_t old_id, uint64_t new_id); template diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index b85720f1..13215983 100644 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -22,11 +22,11 @@ namespace eosiosystem { _producers2(get_self(), get_self().value), _finalizer_keys(get_self(), get_self().value), _finalizers(get_self(), get_self().value), + _last_finkey_ids(get_self(), get_self().value), _global(get_self(), get_self().value), _global2(get_self(), get_self().value), _global3(get_self(), get_self().value), _global4(get_self(), get_self().value), - _global5(get_self(), get_self().value), _rammarket(get_self(), get_self().value), _rexpool(get_self(), get_self().value), _rexretpool(get_self(), get_self().value), @@ -39,7 +39,6 @@ namespace eosiosystem { _gstate2 = _global2.exists() ? _global2.get() : eosio_global_state2{}; _gstate3 = _global3.exists() ? _global3.get() : eosio_global_state3{}; _gstate4 = _global4.exists() ? _global4.get() : get_default_inflation_parameters(); - _gstate5 = _global5.exists() ? _global5.get() : eosio_global_state5{}; } eosio_global_state system_contract::get_default_parameters() { @@ -66,7 +65,6 @@ namespace eosiosystem { _global2.set( _gstate2, get_self() ); _global3.set( _gstate3, get_self() ); _global4.set( _gstate4, get_self() ); - _global5.set( _gstate5, get_self() ); } void system_contract::setram( uint64_t max_ram_size ) { diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 3487d9a1..c860790f 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -14,9 +14,10 @@ namespace eosiosystem { using value_type = std::pair; std::vector top_producers; std::vector finalizer_authorities; - std::set next_finalizer_key_ids; + std::vector next_finalizer_key_ids; top_producers.reserve(21); finalizer_authorities.reserve(21); + next_finalizer_key_ids.reserve(21); // From up to 30 top producers, find 21 producers that meet all the normal requirements // for being a proposer and also have an active finalizer key @@ -44,7 +45,7 @@ namespace eosiosystem { ); // builds up finalizer_authorities - next_finalizer_key_ids.insert(finalizer->active_key_id); + next_finalizer_key_ids.emplace_back(finalizer->active_key_id); finalizer_authorities.emplace_back( eosio::finalizer_authority{ .description = it->owner.to_string(), @@ -77,10 +78,10 @@ namespace eosiosystem { } bool system_contract::is_savanna_consensus() const { - return !_gstate5.last_finalizer_key_ids.empty(); + return _last_finkey_ids.begin() != _last_finkey_ids.end(); } - void system_contract::set_finalizers( std::vector&& finalizer_authorities, const std::set& finalizer_key_ids ) { + void system_contract::set_finalizers( std::vector&& finalizer_authorities, const std::vector& finalizer_key_ids ) { // Establish finalizer policy and call set_finalizers() host function eosio::finalizer_policy fin_policy { .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, // or hardcoded to 15? @@ -88,7 +89,14 @@ namespace eosiosystem { }; eosio::set_finalizers(std::move(fin_policy)); // call host function - _gstate5.last_finalizer_key_ids = finalizer_key_ids; + for (auto id: finalizer_key_ids ) { + // Insert it into last_finkey_ids_table if the key is new + if( _last_finkey_ids.find(id) == _last_finkey_ids.end() ) { + _last_finkey_ids.emplace( get_self(), [&]( auto& f ) { + f.key_id = id; + }); + } + } } // Action to register a finalizer key @@ -175,24 +183,24 @@ namespace eosiosystem { // Replace the finalizer policy immediately if the finalizer is // participating in current voting - if( _gstate5.last_finalizer_key_ids.contains(old_active_key_id) ) { + if( _last_finkey_ids.find(old_active_key_id) != _last_finkey_ids.end() ) { replace_key_in_finalizer_policy(finalizer, old_active_key_id, fin_key->id); } } // replace the key in last finalizer policy and call set_finalizers host function immediately void system_contract::replace_key_in_finalizer_policy(const name& finalizer, uint64_t old_id, uint64_t new_id) { - std::set next_finalizer_key_ids {_gstate5.last_finalizer_key_ids}; - std::vector finalizer_authorities; - finalizer_authorities.reserve(next_finalizer_key_ids.size()); + // replace key ID in last_finkey_ids_table + auto id_itr = _last_finkey_ids.find(old_id); + _last_finkey_ids.modify( id_itr, get_self(), [&]( auto& f ) { + f.key_id = new_id; + }); - // replace key ID in last_finalizer_key_ids - next_finalizer_key_ids.erase(old_id); - next_finalizer_key_ids.insert(new_id); + std::vector finalizer_authorities; - for( const auto id : next_finalizer_key_ids ) { - auto key = _finalizer_keys.find(id); - check( key != _finalizer_keys.end(), "key not found in finalizer_keys table for replace_key_in_finalizer_policy"); + for (auto itr = _last_finkey_ids.begin(); itr != _last_finkey_ids.end(); ++itr) { + auto key = _finalizer_keys.find(itr->key_id); + assert( key != _finalizer_keys.end() ); const auto pk = eosio::decode_bls_public_key_to_g1(key->finalizer_key); finalizer_authorities.emplace_back( eosio::finalizer_authority{ @@ -203,7 +211,7 @@ namespace eosiosystem { ); } - set_finalizers(std::move(finalizer_authorities), next_finalizer_key_ids); + set_finalizers(std::move(finalizer_authorities), {}); // last_finkey_ids_table has already updated. Pass an empty finalizer_key_ids to set_finalizers } // Action to delete a registered finalizer key diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index a358d35c..3d1e61ab 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -111,9 +111,10 @@ namespace eosiosystem { using value_type = std::pair; std::vector< value_type > top_producers; std::vector< eosio::finalizer_authority > next_finalizer_authorities; - std::set< uint64_t > next_finalizer_key_ids; + std::vector< uint64_t > next_finalizer_key_ids; top_producers.reserve(21); next_finalizer_authorities.reserve(21); + next_finalizer_key_ids.reserve(21); bool new_finalizer_keys_found = false; for( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active(); ++it ) { @@ -127,13 +128,13 @@ namespace eosiosystem { // If the producer's finalizer_key_id is not in last_finalizer_key_ids, // it means a new finalizer policy is needed. - if( !_gstate5.last_finalizer_key_ids.contains(finalizer->active_key_id) ) { + if( _last_finkey_ids.find(finalizer->active_key_id) == _last_finkey_ids.end() ) { new_finalizer_keys_found = true; } // Store finalizer key ID and pre-build finalizer_authorities in case // we need to set new finalizer policy - next_finalizer_key_ids.insert(finalizer->active_key_id); + next_finalizer_key_ids.emplace_back(finalizer->active_key_id); next_finalizer_authorities.emplace_back( eosio::finalizer_authority{ .description = it->owner.to_string(), @@ -174,7 +175,7 @@ namespace eosiosystem { // Only set a new finalizer policy if it has changed. // Even if no new finalizer key found, the size must be match to account for if // any finalizers are removed. - if( is_savanna_consensus() && (new_finalizer_keys_found || next_finalizer_authorities.size() != _gstate5.last_finalizer_key_ids.size()) ) { + if( is_savanna_consensus() && new_finalizer_keys_found ) { set_finalizers( std::move(next_finalizer_authorities), next_finalizer_key_ids ); } } From 41e3a302bd1c867ab53dd29ae5f5527c12029019 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 3 Apr 2024 14:58:37 -0400 Subject: [PATCH 46/94] check if the finalizer_key starts with PUB_BLS in actfinkey action --- contracts/eosio.system/src/finalizer_key.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index c860790f..6631a692 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -161,6 +161,9 @@ namespace eosiosystem { check( fin != _finalizers.end(), "finalizer has not registered any finalizer keys" ); check( fin->num_registered_keys > 0, "num_registered_keys of the finalizer must be greater than one" ); + // Basic format check + check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key must start with PUB_BLS"); + // Check the key is registered const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); From 689a4eac178b3165fb949b0a3f867af61b7f9e58 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 3 Apr 2024 15:22:04 -0400 Subject: [PATCH 47/94] remove key id from last_finkey_ids table if the removed key is the last registered one --- contracts/eosio.system/src/finalizer_key.cpp | 6 ++++++ contracts/eosio.system/src/voting.cpp | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 6631a692..aea96eb6 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -89,6 +89,7 @@ namespace eosiosystem { }; eosio::set_finalizers(std::move(fin_policy)); // call host function + // Insert new ones for (auto id: finalizer_key_ids ) { // Insert it into last_finkey_ids_table if the key is new if( _last_finkey_ids.find(id) == _last_finkey_ids.end() ) { @@ -249,6 +250,11 @@ namespace eosiosystem { if( fin->num_registered_keys == 1 ) { // The finalizer does not have any registered keys. Remove it from finalizers table. _finalizers.erase( fin ); + + // This is the last registered and must be active and in last_finkey_ids table + auto itr = _last_finkey_ids.find(fin_key->id); + assert(itr); + _last_finkey_ids.erase( itr ); } else { // Decrement num_registered_keys finalizers table _finalizers.modify( fin, same_payer, [&]( auto& f ) { diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index 3d1e61ab..da4ac74a 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -173,8 +173,6 @@ namespace eosiosystem { } // Only set a new finalizer policy if it has changed. - // Even if no new finalizer key found, the size must be match to account for if - // any finalizers are removed. if( is_savanna_consensus() && new_finalizer_keys_found ) { set_finalizers( std::move(next_finalizer_authorities), next_finalizer_key_ids ); } From 95afd18215ca535de21ad7964baeab6ec98918ff Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 3 Apr 2024 15:22:38 -0400 Subject: [PATCH 48/94] Simplify tests --- tests/eosio.finalizer_key_tests.cpp | 202 +++++++++++++++------------- 1 file changed, 105 insertions(+), 97 deletions(-) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 51270cb7..9a653718 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -1,182 +1,190 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "eosio.system_tester.hpp" +#include + using namespace eosio_system; struct finalizer_key_tester : eosio_system_tester { + static const std::string finalizer_key_1; + static const std::string pop_1; + static const std::string finalizer_key_2; + static const std::string pop_2; + + fc::variant get_finalizer_key_info( uint64_t id ) { + vector data = get_row_by_id( config::system_account_name, config::system_account_name, "finkeys"_n, id ); + return abi_ser.binary_to_variant( + "finalizer_key_info", + data, + abi_serializer::create_yield_function(abi_serializer_max_time) ); + } + fc::variant get_finalizer_info( const account_name& act ) { vector data = get_row_by_account( config::system_account_name, config::system_account_name, "finalizers"_n, act ); - return abi_ser.binary_to_variant( "finalizer_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); + return abi_ser.binary_to_variant( + "finalizer_info", + data, + abi_serializer::create_yield_function(abi_serializer_max_time) ); + } + + action_result register_finalizer_key( const account_name& act, const std::string& finalizer_key, const std::string& pop ) { + return push_action( act, "regfinkey"_n, mvo() + ("finalizer_name", act) + ("finalizer_key", finalizer_key) + ("proof_of_possession", pop) ); + } + + action_result activate_finalizer_key( const account_name& act, const std::string& finalizer_key ) { + return push_action( act, "actfinkey"_n, mvo() + ("finalizer_name", act) + ("finalizer_key", finalizer_key) ); } }; +const std::string finalizer_key_tester::finalizer_key_1 = "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA"; +const std::string finalizer_key_tester::finalizer_key_2 = "PUB_BLS_gtaOjOTa0NzDt8etBDqLoZKlfKTpTalcdfmbTJknLUJB2Fu4Cv-uoa8unF3bJ5kFewaCzf3tjYUyNE6CDSrwvYP5Nw47Y9oE9x4nqJWfJykMOoaI0kJz-GDrGN2nZdUAp5tWEg"; +const std::string pop1 = "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA"; +const std::string pop2 = "SIG_BLS_9e1SzM60bWLdxwz4lYNQMNzMGeFuzFgJDYy7WykmynRVRQeIx2O2xnyzwv1WXvgYHLyMYZ4wK0Y_kU6jl330WazkBsw-_GzvIOGy8fnBnt5AyMaj9X5bhDbvB5MZc0QQz4-P2Z4SltTY17ZItGeekkjX_fgQ9kegM4qnuGU-2iqFj5i3Qf322L77b2SHjFoLmxdFOsfGpz7LyImSP8GcZH39W30cj5bmxfsp_90tGdAkz-7DG9nhSHYxFq6qTqMGijVPGg"; + BOOST_AUTO_TEST_SUITE(eosio_system_finalizer_key_tests) +const name alice = "alice1111111"_n; +const name bob = "bob111111111"_n; + BOOST_FIXTURE_TEST_CASE(register_finalizer_key_invalid_key_tests, finalizer_key_tester) try { { // attempt to register finalizer_key for an unregistered producer BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer is not a registered producer" ), - push_action("alice1111111"_n, "regfinkey"_n, mvo() - ("finalizer", "alice1111111") - ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) - ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") - ) ); + register_finalizer_key(alice, finalizer_key_1, pop1)); } // Now alice1111111 registers as a producer - BOOST_REQUIRE_EQUAL( success(), regproducer("alice1111111"_n) ); + BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); { // finalizer key does not start with PUB_BLS BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key must start with PUB_BLS" ), - push_action("alice1111111"_n, "regfinkey"_n, mvo() - ("finalizer", "alice1111111") + push_action(alice, "regfinkey"_n, mvo() + ("finalizer_name", "alice1111111") ("finalizer_key", "UB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) - ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") + ("proof_of_possession", pop1 ) ) ); } { // proof_of_possession does not start with SIG_BLS BOOST_REQUIRE_EQUAL( wasm_assert_msg( "proof of possession siganture must start with SIG_BLS" ), - push_action("alice1111111"_n, "regfinkey"_n, mvo() - ("finalizer", "alice1111111") - ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) + push_action(alice, "regfinkey"_n, mvo() + ("finalizer_name", "alice1111111") + ("finalizer_key", finalizer_key_1) ("proof_of_possession", "XIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") ) ); } { // proof_of_possession fails BOOST_REQUIRE_EQUAL( wasm_assert_msg( "proof of possession check failed" ), - push_action("alice1111111"_n, "regfinkey"_n, mvo() - ("finalizer", "alice1111111") + push_action(alice, "regfinkey"_n, mvo() + ("finalizer_name", "alice1111111") // use a valid formatted finalizer_key for another signature - ("finalizer_key", "PUB_BLS_gtaOjOTa0NzDt8etBDqLoZKlfKTpTalcdfmbTJknLUJB2Fu4Cv-uoa8unF3bJ5kFewaCzf3tjYUyNE6CDSrwvYP5Nw47Y9oE9x4nqJWfJykMOoaI0kJz-GDrGN2nZdUAp5tWEg" ) - ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") + ("finalizer_key", finalizer_key_1) + ("proof_of_possession", pop2) ) ); } } // register_finalizer_key_invalid_key_tests FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_same_finalizer_tests, finalizer_key_tester) try { - BOOST_REQUIRE_EQUAL( success(), regproducer("alice1111111"_n) ); + BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); // First finalizer key - BOOST_REQUIRE_EQUAL( success(), - push_action("alice1111111"_n, "regfinkey"_n, mvo() - ("finalizer", "alice1111111"_n) - ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) - ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") - ) ); - - auto fin_info = get_finalizer_info("alice1111111"_n); - BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer"].as_string() ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); + + auto fin_info = get_finalizer_info(alice); + BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( 1, fin_info["num_registered_keys"].as_uint64() ); uint64_t active_key_id = fin_info["active_key_id"].as_uint64(); - // ToDo: cross check finalizer keys table + // Cross check finalizer keys table + auto fin_key_info = get_finalizer_key_info(active_key_id); + BOOST_REQUIRE_EQUAL( "alice1111111", fin_key_info["finalizer_name"].as_string() ); + BOOST_REQUIRE_EQUAL( finalizer_key_1, fin_key_info["finalizer_key"].as_string() ); // Second finalizer key - BOOST_REQUIRE_EQUAL( success(), - push_action("alice1111111"_n, "regfinkey"_n, mvo() - ("finalizer", "alice1111111"_n) - ("finalizer_key", "PUB_BLS_gtaOjOTa0NzDt8etBDqLoZKlfKTpTalcdfmbTJknLUJB2Fu4Cv-uoa8unF3bJ5kFewaCzf3tjYUyNE6CDSrwvYP5Nw47Y9oE9x4nqJWfJykMOoaI0kJz-GDrGN2nZdUAp5tWEg" ) - ("proof_of_possession", "SIG_BLS_9e1SzM60bWLdxwz4lYNQMNzMGeFuzFgJDYy7WykmynRVRQeIx2O2xnyzwv1WXvgYHLyMYZ4wK0Y_kU6jl330WazkBsw-_GzvIOGy8fnBnt5AyMaj9X5bhDbvB5MZc0QQz4-P2Z4SltTY17ZItGeekkjX_fgQ9kegM4qnuGU-2iqFj5i3Qf322L77b2SHjFoLmxdFOsfGpz7LyImSP8GcZH39W30cj5bmxfsp_90tGdAkz-7DG9nhSHYxFq6qTqMGijVPGg") - ) ); - - auto fin_info2 = get_finalizer_info("alice1111111"_n); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_2, pop2 )); + + auto fin_info2 = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( 2, fin_info2["num_registered_keys"].as_uint64() ); // count incremented by 1 BOOST_REQUIRE_EQUAL( active_key_id, fin_info2["active_key_id"].as_uint64() ); // active key should not change } FC_LOG_AND_RETHROW() // register_finalizer_key_by_same_finalizer_tests BOOST_FIXTURE_TEST_CASE(register_finalizer_key_duplicate_key_tests, finalizer_key_tester) try { - BOOST_REQUIRE_EQUAL( success(), regproducer("alice1111111"_n) ); + BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); // The first finalizer key - BOOST_REQUIRE_EQUAL( success(), - push_action("alice1111111"_n, "regfinkey"_n, mvo() - ("finalizer", "alice1111111"_n) - ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) - ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") - ) ); - - auto fin_info = get_finalizer_info("alice1111111"_n); - BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer"].as_string() ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); + + auto fin_info = get_finalizer_info(alice); + BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( 1, fin_info["num_registered_keys"].as_uint64() ); // Same finalizer key as the first one BOOST_REQUIRE_EQUAL( wasm_assert_msg( "duplicate finalizer key" ), - push_action("alice1111111"_n, "regfinkey"_n, mvo() - ("finalizer", "alice1111111"_n) - ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) - ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") - ) ); + register_finalizer_key(alice, finalizer_key_1, pop1) ); } FC_LOG_AND_RETHROW() // register_finalizer_key_duplicate_key_tests BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_different_finalizers_tests, finalizer_key_tester) try { // register 2 producers - BOOST_REQUIRE_EQUAL( success(), regproducer("alice1111111"_n) ); - BOOST_REQUIRE_EQUAL( success(), regproducer("bob111111111"_n) ); + BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); + BOOST_REQUIRE_EQUAL( success(), regproducer(bob) ); // alice1111111 registers a finalizer key - BOOST_REQUIRE_EQUAL( success(), - push_action("alice1111111"_n, "regfinkey"_n, mvo() - ("finalizer", "alice1111111"_n) - ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) - ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") - ) ); - - auto fin_info = get_finalizer_info("alice1111111"_n); - BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer"].as_string() ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); + + auto fin_info = get_finalizer_info(alice); + BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( 1, fin_info["num_registered_keys"].as_uint64() ); // bob111111111 registers another finalizer key - BOOST_REQUIRE_EQUAL( success(), - push_action("bob111111111"_n, "regfinkey"_n, mvo() - ("finalizer", "bob111111111"_n) - ("finalizer_key", "PUB_BLS_gtaOjOTa0NzDt8etBDqLoZKlfKTpTalcdfmbTJknLUJB2Fu4Cv-uoa8unF3bJ5kFewaCzf3tjYUyNE6CDSrwvYP5Nw47Y9oE9x4nqJWfJykMOoaI0kJz-GDrGN2nZdUAp5tWEg" ) - ("proof_of_possession", "SIG_BLS_9e1SzM60bWLdxwz4lYNQMNzMGeFuzFgJDYy7WykmynRVRQeIx2O2xnyzwv1WXvgYHLyMYZ4wK0Y_kU6jl330WazkBsw-_GzvIOGy8fnBnt5AyMaj9X5bhDbvB5MZc0QQz4-P2Z4SltTY17ZItGeekkjX_fgQ9kegM4qnuGU-2iqFj5i3Qf322L77b2SHjFoLmxdFOsfGpz7LyImSP8GcZH39W30cj5bmxfsp_90tGdAkz-7DG9nhSHYxFq6qTqMGijVPGg") - ) ); - - auto fin_info2 = get_finalizer_info("bob111111111"_n); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop2) ); + + auto fin_info2 = get_finalizer_info(bob); BOOST_REQUIRE_EQUAL( 1, fin_info2["num_registered_keys"].as_uint64() ); } FC_LOG_AND_RETHROW() // register_finalizer_key_by_different_finalizers_tests BOOST_FIXTURE_TEST_CASE(register_duplicate_key_from_different_finalizers_tests, finalizer_key_tester) try { - BOOST_REQUIRE_EQUAL( success(), regproducer("alice1111111"_n) ); - BOOST_REQUIRE_EQUAL( success(), regproducer("bob111111111"_n) ); + BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); + BOOST_REQUIRE_EQUAL( success(), regproducer(bob) ); // The first finalizer key - BOOST_REQUIRE_EQUAL( success(), - push_action("alice1111111"_n, "regfinkey"_n, mvo() - ("finalizer", "alice1111111"_n) - ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) - ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") - ) ); - - auto fin_info = get_finalizer_info("alice1111111"_n); - BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer"].as_string() ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); + + auto fin_info = get_finalizer_info(alice); + BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( 1, fin_info["num_registered_keys"].as_uint64() ); // bob111111111 tries to register the same finalizer key as the first one BOOST_REQUIRE_EQUAL( wasm_assert_msg( "duplicate finalizer key" ), - push_action("bob111111111"_n, "regfinkey"_n, mvo() - ("finalizer", "bob111111111"_n) - ("finalizer_key", "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) - ("proof_of_possession", "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA") - ) ); + register_finalizer_key(bob, finalizer_key_1, pop1) ); } FC_LOG_AND_RETHROW() // register_duplicate_key_from_different_finalizers_tests +BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_failure_tests, finalizer_key_tester) try { + { // attempt to activate finalizer_key for an unregistered producer + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer is not a registered producer" ), + activate_finalizer_key(alice, finalizer_key_1) ); + } + + BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); + BOOST_REQUIRE_EQUAL( success(), regproducer(bob) ); + + { // finalizer has not registered any finalizer keys yet. + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer has not registered any finalizer keys" ), + activate_finalizer_key(alice, finalizer_key_1) ); + } + + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop2) ); +} // activate_finalizer_key_failure_tests +FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() From 40d2daf480e8420cb758bab96fb67c244e7ac55c Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 3 Apr 2024 21:16:26 -0400 Subject: [PATCH 49/94] Add activating finalizer key tests --- contracts/eosio.system/src/finalizer_key.cpp | 26 ++++---- tests/eosio.finalizer_key_tests.cpp | 65 +++++++++++++++++--- 2 files changed, 68 insertions(+), 23 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index aea96eb6..e0ea921d 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -118,7 +118,7 @@ namespace eosiosystem { // Duplication check across all registered keys auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); auto hash = eosio::sha256(finalizer_key.data(), finalizer_key.size()); - check(idx.lower_bound(hash) == idx.end(), "duplicate finalizer key"); + check(idx.find(hash) == idx.end(), "duplicate finalizer key"); // Proof of possession check is expensive, do it at last check(eosio::bls_pop_verify(fin_key_g1, signature), "proof of possession check failed"); @@ -151,16 +151,16 @@ namespace eosiosystem { } // Action to activate a finalizer key - void system_contract::actfinkey( const name& finalizer, const std::string& finalizer_key ) { - require_auth( finalizer ); + void system_contract::actfinkey( const name& finalizer_name, const std::string& finalizer_key ) { + require_auth( finalizer_name ); - auto producer = _producers.find( finalizer.value ); + auto producer = _producers.find( finalizer_name.value ); check( producer != _producers.end(), "finalizer is not a registered producer"); // Check finalizer has registered keys - auto fin = _finalizers.find(finalizer.value); - check( fin != _finalizers.end(), "finalizer has not registered any finalizer keys" ); - check( fin->num_registered_keys > 0, "num_registered_keys of the finalizer must be greater than one" ); + auto finalizer = _finalizers.find(finalizer_name.value); + check( finalizer != _finalizers.end(), "finalizer has not registered any finalizer keys" ); + check( finalizer->num_registered_keys > 0, "num_registered_keys of the finalizer must be greater than one" ); // Basic format check check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key must start with PUB_BLS"); @@ -169,18 +169,18 @@ namespace eosiosystem { const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); auto hash = eosio::sha256(finalizer_key.data(), finalizer_key.size()); - auto fin_key = idx.lower_bound(hash); + auto fin_key = idx.find(hash); check(fin_key != idx.end(), "finalizer key was not registered"); // Check the key belongs to finalizer - check(fin_key->finalizer_name == finalizer, "finalizer_key was not registered by the finalizer"); + check(fin_key->finalizer_name == name(finalizer_name), "finalizer_key was not registered by the finalizer"); // Check if the finalizer key is not already active - check( fin_key->id != fin->active_key_id, "the finalizer key was already active" ); + check( fin_key->id != finalizer->active_key_id, "the finalizer key was already active" ); - auto old_active_key_id = fin->active_key_id; + auto old_active_key_id = finalizer->active_key_id; - _finalizers.modify( fin, same_payer, [&]( auto& f ) { + _finalizers.modify( finalizer, same_payer, [&]( auto& f ) { f.active_key_id = fin_key->id; f.active_key = { fin_key_g1.begin(), fin_key_g1.end() }; }); @@ -188,7 +188,7 @@ namespace eosiosystem { // Replace the finalizer policy immediately if the finalizer is // participating in current voting if( _last_finkey_ids.find(old_active_key_id) != _last_finkey_ids.end() ) { - replace_key_in_finalizer_policy(finalizer, old_active_key_id, fin_key->id); + replace_key_in_finalizer_policy(finalizer_name, old_active_key_id, fin_key->id); } } diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 9a653718..99df5bf8 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -9,6 +9,8 @@ struct finalizer_key_tester : eosio_system_tester { static const std::string pop_1; static const std::string finalizer_key_2; static const std::string pop_2; + static const std::string finalizer_key_3; + static const std::string pop_3; fc::variant get_finalizer_key_info( uint64_t id ) { vector data = get_row_by_id( config::system_account_name, config::system_account_name, "finkeys"_n, id ); @@ -42,8 +44,11 @@ struct finalizer_key_tester : eosio_system_tester { const std::string finalizer_key_tester::finalizer_key_1 = "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA"; const std::string finalizer_key_tester::finalizer_key_2 = "PUB_BLS_gtaOjOTa0NzDt8etBDqLoZKlfKTpTalcdfmbTJknLUJB2Fu4Cv-uoa8unF3bJ5kFewaCzf3tjYUyNE6CDSrwvYP5Nw47Y9oE9x4nqJWfJykMOoaI0kJz-GDrGN2nZdUAp5tWEg"; +const std::string finalizer_key_tester::finalizer_key_3 = "PUB_BLS_CT8khvZYYZdObeIV9aTnd8fZ8bdaCL1UpSRyqNLZZM5sdrOSpOjDTAY2drTYGvQPVS21BhtD8acLJhqGyTfjqrWjyY5FTfqLdcligofSpa2lrG3FqKVNeUULR5QgcIMYga4vkQ"; + const std::string pop1 = "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA"; const std::string pop2 = "SIG_BLS_9e1SzM60bWLdxwz4lYNQMNzMGeFuzFgJDYy7WykmynRVRQeIx2O2xnyzwv1WXvgYHLyMYZ4wK0Y_kU6jl330WazkBsw-_GzvIOGy8fnBnt5AyMaj9X5bhDbvB5MZc0QQz4-P2Z4SltTY17ZItGeekkjX_fgQ9kegM4qnuGU-2iqFj5i3Qf322L77b2SHjFoLmxdFOsfGpz7LyImSP8GcZH39W30cj5bmxfsp_90tGdAkz-7DG9nhSHYxFq6qTqMGijVPGg"; +const std::string pop3 = "SIG_BLS_cJTQMGv1isqpcHEfhogLhlU56bKpGgo-Svi3Z4NXvWcly5TJo8hDChodIV-aEHgMqr06LuZftR7WFvgGkbOSdmwdO4t58R3RYOMSK-jjif2z-fEwCl7jsxUutASIRwIYtTI7h6NLCjARiKNi5BkES33xY8wYMWf-JkgbpsD2cGsZW4hkMW7T2j_1w89HmNwCn4V_hjlPM_kgz45RoYpKq4w2QEaLdCYTJ6xYOfc9Occc15c76dd1jjty_yT2RMAKO0mfUA"; BOOST_AUTO_TEST_SUITE(eosio_system_finalizer_key_tests) @@ -169,22 +174,62 @@ BOOST_FIXTURE_TEST_CASE(register_duplicate_key_from_different_finalizers_tests, FC_LOG_AND_RETHROW() // register_duplicate_key_from_different_finalizers_tests BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_failure_tests, finalizer_key_tester) try { - { // attempt to activate finalizer_key for an unregistered producer - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer is not a registered producer" ), - activate_finalizer_key(alice, finalizer_key_1) ); - } + // attempt to activate finalizer_key for an unregistered producer + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer is not a registered producer" ), + activate_finalizer_key(alice, finalizer_key_1) ); + // Register producers BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); BOOST_REQUIRE_EQUAL( success(), regproducer(bob) ); - { // finalizer has not registered any finalizer keys yet. - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer has not registered any finalizer keys" ), - activate_finalizer_key(alice, finalizer_key_1) ); - } + // finalizer has not registered any finalizer keys yet. + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer has not registered any finalizer keys" ), + activate_finalizer_key(alice, finalizer_key_1) ); + // Alice registers a finalizer key BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop2) ); -} // activate_finalizer_key_failure_tests -FC_LOG_AND_RETHROW() + + // Activate a finalizer key not registered by Alice + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered" ), + activate_finalizer_key(alice, finalizer_key_3) ); + + // Activate a finalizer key not registered by Alice + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer_key was not registered by the finalizer" ), + activate_finalizer_key(alice, finalizer_key_2) ); + + // Activate a finalizer key that is already active (the first key registered is + // automatically set to active + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "the finalizer key was already active" ), + activate_finalizer_key(alice, finalizer_key_1) ); +} +FC_LOG_AND_RETHROW() // activate_finalizer_key_failure_tests + +BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_success_tests, finalizer_key_tester) try { + // Alice registers as a producer + BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); + + // Alice registers two finalizer keys. The first key is active + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_2, pop2) ); + + // Check finalizer_key_1 is the active key + auto alice_info = get_finalizer_info(alice); + uint64_t active_key_id = alice_info["active_key_id"].as_uint64(); + auto finalizer_key_info = get_finalizer_key_info(active_key_id); + BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); + BOOST_REQUIRE_EQUAL( finalizer_key_1, finalizer_key_info["finalizer_key"].as_string() ); + + // Activate the second key + BOOST_REQUIRE_EQUAL( success(), activate_finalizer_key(alice, finalizer_key_2) ); + + // Check finalizer_key_2 is the active key + alice_info = get_finalizer_info(alice); + active_key_id = alice_info["active_key_id"].as_uint64(); + finalizer_key_info = get_finalizer_key_info(active_key_id); + BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); + BOOST_REQUIRE_EQUAL( finalizer_key_2, finalizer_key_info["finalizer_key"].as_string() ); +} +FC_LOG_AND_RETHROW() // activate_finalizer_key_success_tests BOOST_AUTO_TEST_SUITE_END() From 8ee26c4099c4a9461b9f5c5b969dae425d5cf0a6 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 3 Apr 2024 21:53:25 -0400 Subject: [PATCH 50/94] Partial delete finalizer key tests --- contracts/eosio.system/src/finalizer_key.cpp | 34 ++++++------- tests/eosio.finalizer_key_tests.cpp | 51 ++++++++++++++++++-- 2 files changed, 64 insertions(+), 21 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index e0ea921d..f23522ca 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -173,7 +173,7 @@ namespace eosiosystem { check(fin_key != idx.end(), "finalizer key was not registered"); // Check the key belongs to finalizer - check(fin_key->finalizer_name == name(finalizer_name), "finalizer_key was not registered by the finalizer"); + check(fin_key->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer"); // Check if the finalizer key is not already active check( fin_key->id != finalizer->active_key_id, "the finalizer key was already active" ); @@ -219,37 +219,37 @@ namespace eosiosystem { } // Action to delete a registered finalizer key - void system_contract::delfinkey( const name& finalizer, const std::string& finalizer_key ) { - require_auth( finalizer ); + void system_contract::delfinkey( const name& finalizer_name, const std::string& finalizer_key ) { + require_auth( finalizer_name ); - auto producer = _producers.find( finalizer.value ); + auto producer = _producers.find( finalizer_name.value ); check( producer != _producers.end(), "finalizer is not a registered producer"); + // Check finalizer has registered keys + auto finalizer = _finalizers.find(finalizer_name.value); + check( finalizer != _finalizers.end(), "finalizer has not registered any finalizer keys" ); + assert( finalizer->num_registered_keys > 0 ); + // Check the key is registered auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); auto hash = eosio::sha256(finalizer_key.data(), finalizer_key.size()); - auto fin_key = idx.lower_bound(hash); - check(fin_key != idx.end(), "finalizer_key was not registered"); + auto fin_key = idx.find(hash); + check(fin_key != idx.end(), "finalizer key was not registered"); // Check the key belongs to finalizer - check(fin_key->finalizer_name == finalizer, "finalizer_key was not registered by the finalizer"); - - // Cross check finalizers table - auto fin = _finalizers.find(finalizer.value); - check( fin != _finalizers.end(), "finalizer is not in the finalizers table" ); - check( fin->num_registered_keys > 0, "num_registered_keys of the finalizer must be greater than one" ); + check(fin_key->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer"); - if( fin_key->id == fin->active_key_id ) { - check( fin->num_registered_keys == 1, "cannot delete an active key unless it is the last registered finalizer key"); + if( fin_key->id == finalizer->active_key_id ) { + check( finalizer->num_registered_keys == 1, "cannot delete an active key unless it is the last registered finalizer key"); } // Remove the key from finalizer_keys table idx.erase( fin_key ); // Update finalizers table - if( fin->num_registered_keys == 1 ) { + if( finalizer->num_registered_keys == 1 ) { // The finalizer does not have any registered keys. Remove it from finalizers table. - _finalizers.erase( fin ); + _finalizers.erase( finalizer ); // This is the last registered and must be active and in last_finkey_ids table auto itr = _last_finkey_ids.find(fin_key->id); @@ -257,7 +257,7 @@ namespace eosiosystem { _last_finkey_ids.erase( itr ); } else { // Decrement num_registered_keys finalizers table - _finalizers.modify( fin, same_payer, [&]( auto& f ) { + _finalizers.modify( finalizer, same_payer, [&]( auto& f ) { --f.num_registered_keys; }); } diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 99df5bf8..b1468867 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -6,11 +6,13 @@ using namespace eosio_system; struct finalizer_key_tester : eosio_system_tester { static const std::string finalizer_key_1; - static const std::string pop_1; static const std::string finalizer_key_2; - static const std::string pop_2; static const std::string finalizer_key_3; + static const std::string finalizer_key_4; + static const std::string pop_1; + static const std::string pop_2; static const std::string pop_3; + static const std::string pop_4; fc::variant get_finalizer_key_info( uint64_t id ) { vector data = get_row_by_id( config::system_account_name, config::system_account_name, "finkeys"_n, id ); @@ -40,15 +42,23 @@ struct finalizer_key_tester : eosio_system_tester { ("finalizer_name", act) ("finalizer_key", finalizer_key) ); } + + action_result delete_finalizer_key( const account_name& act, const std::string& finalizer_key ) { + return push_action( act, "delfinkey"_n, mvo() + ("finalizer_name", act) + ("finalizer_key", finalizer_key) ); + } }; const std::string finalizer_key_tester::finalizer_key_1 = "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA"; const std::string finalizer_key_tester::finalizer_key_2 = "PUB_BLS_gtaOjOTa0NzDt8etBDqLoZKlfKTpTalcdfmbTJknLUJB2Fu4Cv-uoa8unF3bJ5kFewaCzf3tjYUyNE6CDSrwvYP5Nw47Y9oE9x4nqJWfJykMOoaI0kJz-GDrGN2nZdUAp5tWEg"; const std::string finalizer_key_tester::finalizer_key_3 = "PUB_BLS_CT8khvZYYZdObeIV9aTnd8fZ8bdaCL1UpSRyqNLZZM5sdrOSpOjDTAY2drTYGvQPVS21BhtD8acLJhqGyTfjqrWjyY5FTfqLdcligofSpa2lrG3FqKVNeUULR5QgcIMYga4vkQ"; +const std::string finalizer_key_tester::finalizer_key_4 = "PUB_BLS_hJYC9REVk4Pzgt3NMycIaCRpRqTX8IIEAB8xhWg6pOYsV7n9gJnTTUOzPGH8VE4FPhxvzJuvrb5TNeR5MHwIjPMMKVPYHI-dDFwl5Oqj0yH9uoKRcMqjEaFZ5VYX3zMJuA1jQQ"; const std::string pop1 = "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA"; const std::string pop2 = "SIG_BLS_9e1SzM60bWLdxwz4lYNQMNzMGeFuzFgJDYy7WykmynRVRQeIx2O2xnyzwv1WXvgYHLyMYZ4wK0Y_kU6jl330WazkBsw-_GzvIOGy8fnBnt5AyMaj9X5bhDbvB5MZc0QQz4-P2Z4SltTY17ZItGeekkjX_fgQ9kegM4qnuGU-2iqFj5i3Qf322L77b2SHjFoLmxdFOsfGpz7LyImSP8GcZH39W30cj5bmxfsp_90tGdAkz-7DG9nhSHYxFq6qTqMGijVPGg"; const std::string pop3 = "SIG_BLS_cJTQMGv1isqpcHEfhogLhlU56bKpGgo-Svi3Z4NXvWcly5TJo8hDChodIV-aEHgMqr06LuZftR7WFvgGkbOSdmwdO4t58R3RYOMSK-jjif2z-fEwCl7jsxUutASIRwIYtTI7h6NLCjARiKNi5BkES33xY8wYMWf-JkgbpsD2cGsZW4hkMW7T2j_1w89HmNwCn4V_hjlPM_kgz45RoYpKq4w2QEaLdCYTJ6xYOfc9Occc15c76dd1jjty_yT2RMAKO0mfUA"; +const std::string pop4 = "SIG_BLS_GNlwGxjL-LCVDApTHernv8Hj6EqlsxWlZBUzOu6DcJmNNuHsfetXK14RPJ-L63wVnhPRL9aNrQAURy2wYJ1__rNiGk-nUMZ5RDTO7tO2EPTiyySq9cbzgn43vKG8FgsA4gbNlqVFeTCbo5CgGj8m9vXNV4-Cv68WW-ivcwJzDtnNA3O9PPIpRY6_HhbmwTUVrHL2v7X_arNCyAf29nucAYNOsCM-br6F6HwpSjqSxi4-KqcFfQCWbAbn_SgJNVAA4yx5fQ"; BOOST_AUTO_TEST_SUITE(eosio_system_finalizer_key_tests) @@ -190,12 +200,12 @@ BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_failure_tests, finalizer_key_test BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop2) ); - // Activate a finalizer key not registered by Alice + // Activate a finalizer key not registered by anyone BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered" ), activate_finalizer_key(alice, finalizer_key_3) ); // Activate a finalizer key not registered by Alice - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer_key was not registered by the finalizer" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered by the finalizer" ), activate_finalizer_key(alice, finalizer_key_2) ); // Activate a finalizer key that is already active (the first key registered is @@ -232,4 +242,37 @@ BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_success_tests, finalizer_key_test } FC_LOG_AND_RETHROW() // activate_finalizer_key_success_tests +BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_failure_tests, finalizer_key_tester) try { + // attempt to delete finalizer_key for an unregistered producer + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer is not a registered producer" ), + delete_finalizer_key(alice, finalizer_key_1) ); + + // Register producers + BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); + BOOST_REQUIRE_EQUAL( success(), regproducer(bob) ); + + // finalizer has not registered any finalizer keys yet. + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer has not registered any finalizer keys" ), + delete_finalizer_key(alice, finalizer_key_1) ); + + // Alice and Bob register finalizer keys + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop2) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_3, pop3) ); + + // Delete a finalizer key not registered by anyone + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered" ), + delete_finalizer_key(alice, finalizer_key_4) ); + + // Delete a finalizer key not registered by Alice + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered by the finalizer" ), + delete_finalizer_key(alice, finalizer_key_2) ); + + // Delete a finalizer key whose finalizer has more than one key and the key is active + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "cannot delete an active key unless it is the last registered finalizer key" ), + delete_finalizer_key(bob, finalizer_key_2) ); + +} +FC_LOG_AND_RETHROW() // delete_finalizer_key_failure_tests + BOOST_AUTO_TEST_SUITE_END() From aede338df54ed55d40edbae01d2ed72a8f2e1dde Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 4 Apr 2024 12:21:05 -0400 Subject: [PATCH 51/94] more delete finalizer key tests --- tests/eosio.finalizer_key_tests.cpp | 55 ++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index b1468867..d9dfec05 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -16,18 +16,12 @@ struct finalizer_key_tester : eosio_system_tester { fc::variant get_finalizer_key_info( uint64_t id ) { vector data = get_row_by_id( config::system_account_name, config::system_account_name, "finkeys"_n, id ); - return abi_ser.binary_to_variant( - "finalizer_key_info", - data, - abi_serializer::create_yield_function(abi_serializer_max_time) ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "finalizer_key_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_finalizer_info( const account_name& act ) { vector data = get_row_by_account( config::system_account_name, config::system_account_name, "finalizers"_n, act ); - return abi_ser.binary_to_variant( - "finalizer_info", - data, - abi_serializer::create_yield_function(abi_serializer_max_time) ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "finalizer_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } action_result register_finalizer_key( const account_name& act, const std::string& finalizer_key, const std::string& pop ) { @@ -275,4 +269,49 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_failure_tests, finalizer_key_tester } FC_LOG_AND_RETHROW() // delete_finalizer_key_failure_tests +BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_success_test, finalizer_key_tester) try { + // Alice registers as a producer + BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); + + // Alice registers two keys and the first key is active + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_2, pop2) ); + + // Check finalizer_key_1 is the active key + auto alice_info = get_finalizer_info(alice); + uint64_t active_key_id = alice_info["active_key_id"].as_uint64(); + auto finalizer_key_info = get_finalizer_key_info(active_key_id); + BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); + BOOST_REQUIRE_EQUAL( finalizer_key_1, finalizer_key_info["finalizer_key"].as_string() ); + + // Delete the non-active key + BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(alice, finalizer_key_2) ); + + // ToDo: Need to check finalizer_key_2 is removed from the finalizer_key table using finalizer_key +} +FC_LOG_AND_RETHROW() // delete_finalizer_key_success_test + +BOOST_FIXTURE_TEST_CASE(delete_last_finalizer_key_test, finalizer_key_tester) try { + // Alice registers as a producer + BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); + + // Alice registers one key and it is active + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); + + // Check finalizer_key_1 is the active key + auto alice_info = get_finalizer_info(alice); + uint64_t active_key_id = alice_info["active_key_id"].as_uint64(); + auto finalizer_key_info = get_finalizer_key_info(active_key_id); + BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); + BOOST_REQUIRE_EQUAL( finalizer_key_1, finalizer_key_info["finalizer_key"].as_string() ); + + // Delete it + BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(alice, finalizer_key_1) ); + + // Both finalizer_key_1 and alice should be removed from finalizers and finalizer_keys tables + BOOST_REQUIRE_EQUAL( true, get_finalizer_key_info(active_key_id).is_null() ); + BOOST_REQUIRE_EQUAL( true, get_finalizer_info(alice).is_null() ); +} +FC_LOG_AND_RETHROW() // delete_last_finalizer_key_test + BOOST_AUTO_TEST_SUITE_END() From c676d31e2cbd4371f9a7b63ac867665ee1667dc4 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 4 Apr 2024 12:21:58 -0400 Subject: [PATCH 52/94] more efficiently updating last finalizer keys table --- .../include/eosio.system/eosio.system.hpp | 3 +- contracts/eosio.system/src/finalizer_key.cpp | 42 +++++++++++-------- contracts/eosio.system/src/voting.cpp | 22 +++++----- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 45c527ba..0fd0b09e 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef CHANNEL_RAM_AND_NAMEBID_FEES_TO_REX #undef CHANNEL_RAM_AND_NAMEBID_FEES_TO_REX @@ -1611,7 +1612,7 @@ namespace eosiosystem { // defined in finalizer_key.cpp bool is_savanna_consensus() const; - void set_finalizers( std::vector&& finalizer_authorities, const std::vector& finalizer_key_ids ); + void set_finalizers( std::vector&& finalizer_authorities, const std::vector& finalizer_key_ids, const std::unordered_set& kept_key_ids ); void replace_key_in_finalizer_policy(const name& finalizer, uint64_t old_id, uint64_t new_id); template diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index f23522ca..960499a1 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -14,10 +14,10 @@ namespace eosiosystem { using value_type = std::pair; std::vector top_producers; std::vector finalizer_authorities; - std::vector next_finalizer_key_ids; + std::vector new_finalizer_key_ids; top_producers.reserve(21); finalizer_authorities.reserve(21); - next_finalizer_key_ids.reserve(21); + new_finalizer_key_ids.reserve(21); // From up to 30 top producers, find 21 producers that meet all the normal requirements // for being a proposer and also have an active finalizer key @@ -45,7 +45,7 @@ namespace eosiosystem { ); // builds up finalizer_authorities - next_finalizer_key_ids.emplace_back(finalizer->active_key_id); + new_finalizer_key_ids.emplace_back(finalizer->active_key_id); finalizer_authorities.emplace_back( eosio::finalizer_authority{ .description = it->owner.to_string(), @@ -74,14 +74,14 @@ namespace eosiosystem { _gstate.last_producer_schedule_size = static_cast( producers.size() ); } - set_finalizers(std::move(finalizer_authorities), next_finalizer_key_ids); + set_finalizers(std::move(finalizer_authorities), new_finalizer_key_ids, {}); } bool system_contract::is_savanna_consensus() const { return _last_finkey_ids.begin() != _last_finkey_ids.end(); } - void system_contract::set_finalizers( std::vector&& finalizer_authorities, const std::vector& finalizer_key_ids ) { + void system_contract::set_finalizers( std::vector&& finalizer_authorities, const std::vector& new_key_ids, const std::unordered_set& kept_key_ids ) { // Establish finalizer policy and call set_finalizers() host function eosio::finalizer_policy fin_policy { .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, // or hardcoded to 15? @@ -89,15 +89,21 @@ namespace eosiosystem { }; eosio::set_finalizers(std::move(fin_policy)); // call host function - // Insert new ones - for (auto id: finalizer_key_ids ) { - // Insert it into last_finkey_ids_table if the key is new - if( _last_finkey_ids.find(id) == _last_finkey_ids.end() ) { - _last_finkey_ids.emplace( get_self(), [&]( auto& f ) { - f.key_id = id; - }); + // Purge any ids not in kept_key_ids from _last_finkey_ids + for (auto itr = _last_finkey_ids.begin(); itr != _last_finkey_ids.end(); /* intentionally empty */ ) { + if( kept_key_ids.contains(itr->key_id) ) { + ++itr; + } else { + itr = _last_finkey_ids.erase(itr); } } + + // Add new_key_ids to _last_finkey_ids + for (auto id: new_key_ids ) { + _last_finkey_ids.emplace( get_self(), [&]( auto& f ) { + f.key_id = id; + }); + } } // Action to register a finalizer key @@ -215,7 +221,12 @@ namespace eosiosystem { ); } - set_finalizers(std::move(finalizer_authorities), {}); // last_finkey_ids_table has already updated. Pass an empty finalizer_key_ids to set_finalizers + // last_finkey_ids table has already been updated. Call set_finalizers host function directly + eosio::finalizer_policy fin_policy { + .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, + .finalizers = finalizer_authorities + }; + eosio::set_finalizers(std::move(fin_policy)); // call host function } // Action to delete a registered finalizer key @@ -250,11 +261,6 @@ namespace eosiosystem { if( finalizer->num_registered_keys == 1 ) { // The finalizer does not have any registered keys. Remove it from finalizers table. _finalizers.erase( finalizer ); - - // This is the last registered and must be active and in last_finkey_ids table - auto itr = _last_finkey_ids.find(fin_key->id); - assert(itr); - _last_finkey_ids.erase( itr ); } else { // Decrement num_registered_keys finalizers table _finalizers.modify( finalizer, same_payer, [&]( auto& f ) { diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index da4ac74a..9536ec19 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -111,10 +111,11 @@ namespace eosiosystem { using value_type = std::pair; std::vector< value_type > top_producers; std::vector< eosio::finalizer_authority > next_finalizer_authorities; - std::vector< uint64_t > next_finalizer_key_ids; + std::vector< uint64_t > new_finalizer_key_ids; + std::unordered_set< uint64_t > kept_finalizer_key_ids; top_producers.reserve(21); next_finalizer_authorities.reserve(21); - next_finalizer_key_ids.reserve(21); + new_finalizer_key_ids.reserve(21); bool new_finalizer_keys_found = false; for( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active(); ++it ) { @@ -126,15 +127,16 @@ namespace eosiosystem { continue; } - // If the producer's finalizer_key_id is not in last_finalizer_key_ids, - // it means a new finalizer policy is needed. if( _last_finkey_ids.find(finalizer->active_key_id) == _last_finkey_ids.end() ) { - new_finalizer_keys_found = true; + // If any producer's active finalizer_key_id is not in + // last_finalizer_key_ids, it means a new finalizer policy is needed. + new_finalizer_key_ids.emplace_back(finalizer->active_key_id); + } else { + // the active_key is the same as last round for the producer + kept_finalizer_key_ids.insert(finalizer->active_key_id); } - // Store finalizer key ID and pre-build finalizer_authorities in case - // we need to set new finalizer policy - next_finalizer_key_ids.emplace_back(finalizer->active_key_id); + // Pre-build next_finalizer_authorities in case it is needed. next_finalizer_authorities.emplace_back( eosio::finalizer_authority{ .description = it->owner.to_string(), @@ -173,8 +175,8 @@ namespace eosiosystem { } // Only set a new finalizer policy if it has changed. - if( is_savanna_consensus() && new_finalizer_keys_found ) { - set_finalizers( std::move(next_finalizer_authorities), next_finalizer_key_ids ); + if( is_savanna_consensus() && !new_finalizer_key_ids.empty() ) { + set_finalizers( std::move(next_finalizer_authorities), new_finalizer_key_ids, kept_finalizer_key_ids ); } } From 3b9c2c44915f4c9a31c85ae7b858b9e9614ede9a Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 4 Apr 2024 15:40:55 -0400 Subject: [PATCH 53/94] Add the first switch-to-Savanna action test --- tests/eosio.finalizer_key_tests.cpp | 111 +++++++++++++++++++++------- 1 file changed, 86 insertions(+), 25 deletions(-) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index d9dfec05..3eaf3934 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -4,6 +4,11 @@ using namespace eosio_system; +struct key_pair_t { + std::string pub_key; + std::string pop; +}; + struct finalizer_key_tester : eosio_system_tester { static const std::string finalizer_key_1; static const std::string finalizer_key_2; @@ -14,6 +19,8 @@ struct finalizer_key_tester : eosio_system_tester { static const std::string pop_3; static const std::string pop_4; + static const std::vector key_pair; + fc::variant get_finalizer_key_info( uint64_t id ) { vector data = get_row_by_id( config::system_account_name, config::system_account_name, "finkeys"_n, id ); return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "finalizer_key_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); @@ -24,6 +31,11 @@ struct finalizer_key_tester : eosio_system_tester { return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "finalizer_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } + fc::variant get_last_finkey_id_info( uint64_t id ) { + vector data = get_row_by_id( config::system_account_name, config::system_account_name, "lastfkeyids"_n, id ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "last_finkey_id_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); + } + action_result register_finalizer_key( const account_name& act, const std::string& finalizer_key, const std::string& pop ) { return push_action( act, "regfinkey"_n, mvo() ("finalizer_name", act) @@ -42,6 +54,14 @@ struct finalizer_key_tester : eosio_system_tester { ("finalizer_name", act) ("finalizer_key", finalizer_key) ); } + + void register_finalizer_keys(const std::vector& producer_names) { + uint32_t i = 0; + for (const auto& p: producer_names) { + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(p, key_pair[i].pub_key, key_pair[i].pop)); + ++i; + } + } }; const std::string finalizer_key_tester::finalizer_key_1 = "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA"; @@ -49,10 +69,35 @@ const std::string finalizer_key_tester::finalizer_key_2 = "PUB_BLS_gtaOjOTa0NzDt const std::string finalizer_key_tester::finalizer_key_3 = "PUB_BLS_CT8khvZYYZdObeIV9aTnd8fZ8bdaCL1UpSRyqNLZZM5sdrOSpOjDTAY2drTYGvQPVS21BhtD8acLJhqGyTfjqrWjyY5FTfqLdcligofSpa2lrG3FqKVNeUULR5QgcIMYga4vkQ"; const std::string finalizer_key_tester::finalizer_key_4 = "PUB_BLS_hJYC9REVk4Pzgt3NMycIaCRpRqTX8IIEAB8xhWg6pOYsV7n9gJnTTUOzPGH8VE4FPhxvzJuvrb5TNeR5MHwIjPMMKVPYHI-dDFwl5Oqj0yH9uoKRcMqjEaFZ5VYX3zMJuA1jQQ"; -const std::string pop1 = "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA"; -const std::string pop2 = "SIG_BLS_9e1SzM60bWLdxwz4lYNQMNzMGeFuzFgJDYy7WykmynRVRQeIx2O2xnyzwv1WXvgYHLyMYZ4wK0Y_kU6jl330WazkBsw-_GzvIOGy8fnBnt5AyMaj9X5bhDbvB5MZc0QQz4-P2Z4SltTY17ZItGeekkjX_fgQ9kegM4qnuGU-2iqFj5i3Qf322L77b2SHjFoLmxdFOsfGpz7LyImSP8GcZH39W30cj5bmxfsp_90tGdAkz-7DG9nhSHYxFq6qTqMGijVPGg"; -const std::string pop3 = "SIG_BLS_cJTQMGv1isqpcHEfhogLhlU56bKpGgo-Svi3Z4NXvWcly5TJo8hDChodIV-aEHgMqr06LuZftR7WFvgGkbOSdmwdO4t58R3RYOMSK-jjif2z-fEwCl7jsxUutASIRwIYtTI7h6NLCjARiKNi5BkES33xY8wYMWf-JkgbpsD2cGsZW4hkMW7T2j_1w89HmNwCn4V_hjlPM_kgz45RoYpKq4w2QEaLdCYTJ6xYOfc9Occc15c76dd1jjty_yT2RMAKO0mfUA"; -const std::string pop4 = "SIG_BLS_GNlwGxjL-LCVDApTHernv8Hj6EqlsxWlZBUzOu6DcJmNNuHsfetXK14RPJ-L63wVnhPRL9aNrQAURy2wYJ1__rNiGk-nUMZ5RDTO7tO2EPTiyySq9cbzgn43vKG8FgsA4gbNlqVFeTCbo5CgGj8m9vXNV4-Cv68WW-ivcwJzDtnNA3O9PPIpRY6_HhbmwTUVrHL2v7X_arNCyAf29nucAYNOsCM-br6F6HwpSjqSxi4-KqcFfQCWbAbn_SgJNVAA4yx5fQ"; +const std::string finalizer_key_tester::pop_1 = "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA"; +const std::string finalizer_key_tester::pop_2 = "SIG_BLS_9e1SzM60bWLdxwz4lYNQMNzMGeFuzFgJDYy7WykmynRVRQeIx2O2xnyzwv1WXvgYHLyMYZ4wK0Y_kU6jl330WazkBsw-_GzvIOGy8fnBnt5AyMaj9X5bhDbvB5MZc0QQz4-P2Z4SltTY17ZItGeekkjX_fgQ9kegM4qnuGU-2iqFj5i3Qf322L77b2SHjFoLmxdFOsfGpz7LyImSP8GcZH39W30cj5bmxfsp_90tGdAkz-7DG9nhSHYxFq6qTqMGijVPGg"; +const std::string finalizer_key_tester::pop_3 = "SIG_BLS_cJTQMGv1isqpcHEfhogLhlU56bKpGgo-Svi3Z4NXvWcly5TJo8hDChodIV-aEHgMqr06LuZftR7WFvgGkbOSdmwdO4t58R3RYOMSK-jjif2z-fEwCl7jsxUutASIRwIYtTI7h6NLCjARiKNi5BkES33xY8wYMWf-JkgbpsD2cGsZW4hkMW7T2j_1w89HmNwCn4V_hjlPM_kgz45RoYpKq4w2QEaLdCYTJ6xYOfc9Occc15c76dd1jjty_yT2RMAKO0mfUA"; +const std::string finalizer_key_tester::pop_4 = "SIG_BLS_GNlwGxjL-LCVDApTHernv8Hj6EqlsxWlZBUzOu6DcJmNNuHsfetXK14RPJ-L63wVnhPRL9aNrQAURy2wYJ1__rNiGk-nUMZ5RDTO7tO2EPTiyySq9cbzgn43vKG8FgsA4gbNlqVFeTCbo5CgGj8m9vXNV4-Cv68WW-ivcwJzDtnNA3O9PPIpRY6_HhbmwTUVrHL2v7X_arNCyAf29nucAYNOsCM-br6F6HwpSjqSxi4-KqcFfQCWbAbn_SgJNVAA4yx5fQ"; + +const std::vector finalizer_key_tester::key_pair { + {"PUB_BLS_9Pbv53DbC9EDGGPEZUrlKuMGeXYWHzIPfmn-Ncrxj7sOTiTEOYIkcCgBrvfKYiIG0BsiafG1dRK9MV40aGWKREE4rWHpiDLIkHR91huq9CEdeZHUb2bRXvcxs0RAa7oADXSTmw", "SIG_BLS_IyjIzDWKzlekYSiRbJmBqYmWoiMsmHX_1aB0Hkqk1woeSJLbtd9D83lMDi6LiMEEpP79rP-AKiJAg1rKHODkt2habnn-y4jFMl76egQOv2KHLjobVzWWj_nz667VxeoF2FwF-NMnX7FQfpPgVRINSDKc5maRADRYQGrnlE-boh_23GBuCaxELnAFD-4L_ZEZRr8B9UIA62Vj9JBS_dExquL3wtlhx7vNq0MAGf9J3_Q69BsTuH_OMH6bs5m2AF4ZqiKpdQ" }, + { "PUB_BLS_WIuHboHhjl3zxB3pt1bdSdF9O6GPOmjMgQvxbzpJBPYYIrWIpcHr6uGbuNGHh8ITlMwLhb_7Fe2QTUStMU0sOgLlXl737hu9GBNyF9W7ZIc7U1xSOmBS5-OpCjViTs4DXQJrjg", "SIG_BLS_RL0hu5YQiXvuvDYdi6LuQqPAISBmS0OuUzGhRezqRYHQC1yL2VlV4lg17rDFzekFCYeB4Agtv0P3Zs3mCDRVwnIbZ3ETin-ONvXKo78Vi71BM4g-AWqdbXbvIbp86u0IXzWjQgSNTuKP2Jj4AqKwhNbDhMiqH5VXUuV1Ogp7P-kN6TcJiqQfqs69iAWklDgYMeDT9Y6qvrb7E1ZtkRbFzISKBrKDYCJ1KFYL7XgknPdqydjPiHEJEIX8ORNwPEgG11PbZQ"}, + {"PUB_BLS_OKI5k1cZcEAvkXQqWCMICE5BSXd1lI5VH_n-PagmHOP6MnKPpydAcS9qgHxm0bIWJwyzvMUdpm-TNqlQQGcQggAn_3GUQx7zSlrdzSFZ3h2kIXjpIDNDB2ZMQJ6wqYIXNX3kZg", "SIG_BLS_BGQbDqe4kpCtMEZsl4cfsSYGwquW8jGeq_9zppptRU4XQvAqRT_flXSg84sR9PMY9_m1lMsa6S9nnlilQ7SdMooOzOXVvYzNFmLuCR6b2c4jDZrJQGtgYleUINFQZEgBhzYS1WRbnlDIsRCBPbS_mDbfqQ80g-DKkUCcyeY0Cr7CJ9IoafmcVWJLFPWV0ukRcGAk0XKBWVbI23REXbgBeKD_XNMJe5PHJS36gZYWyaiO_wHIXAbUuYgOptmC0rAIEPVGow"}, + {"PUB_BLS_0kQpMupOH51c0cFLk-IoFALA9ePsCWys46A7HgExjvHzVqFNYBGIO4-SzhcdqToMCrs457K092irPa1JlUGCxdO0rluiyu6bJAYemTqPQZvzNYihZJ8OULOObIcsN8gW1aZNmA", "SIG_BLS_lTVkt0YINpwBIHXbthD_b21srBBJB5C6BMeyhA4RUCP4tkiyw9I4DUlJyR90v7AS-yhOHCFwDNmB1ld0wQYxnhxim1xB0zThhH9PZkkQH-Iksh46EujwEDSMQ7tLaqcXFEB9SmO9Yf8uaNEzY0qn11dgOWnAyxH4wb73QHE0g75gutiZ8XwugjPrpXUSj_ERiJcXE15_jr1TGGVYo1AIJYvhkiIpT4K3mNqtcFnawbhw2hr5Q0RXLGrSHCq21ncTRvtEUw"}, + {"PUB_BLS_pCUtXfVRKcErpxc0nh4wfSyEsCwj2pdQadJiXxArz-OTxhbkl12rezpiSlff01YWYvwGf_N11z1p6KyBUEyJFmOGTi-o89InkPoanMLe-CH9_HoifsbXLgKISdfs7CAZ-_DELA","SIG_BLS_R-vksnp0wpwJ0I8E0d4DIk4AuGsL6q3tzwoqk7wzKbPoQhHdtAcD1D00um8WQoUSdSAT1Z9PtFRFOUdsvS5oBLmOPqCtXW-GWiKH4GonU-NttXGdAnndPNTchvXzkEkSWSPl-2NUx1Ep2TUxvxyLuSkjE5-HFYGFZQuYTClf5-YZzstUUgAARrk2IZtsMpsI4l3_LM6bgfCrVNLxA5INOut1-EheK1M8ZBupmY9Ue6pMOJ4Po6LF8uAeLDxvDOgAToKDIQ"}, + {"PUB_BLS_FUu1bOokTWaf00LpoZl1OaO1Rr01EjxZ46fOs4FIgLVSf_n-WDG7QhMYFj5JGBoTWxUe-Hkk0VsvBzwVM85F4ZBEa8H6dLgQhevdjiYth8TDC2ZOSkcQdEUmtpcn4-8Hjy9aMg", "SIG_BLS_2nCBKKw377gYomeIq3_3kktsry6lZPr4_pCggFBL6sQSvkCuCeAi5igbdY9tNEkVJ9u6NVH5_JhkLvN7-oyw83B9WwajWZf7sERxebilDl5Spy-YLxXvorH8BOFap1kEIf5JktH4tsmwwJgySqZTGsGXzRIu3K1fk3F2rZ0I9aAE5XR2hYPrIIhV0Vv2T68PpAg1RUDuaxhXSM1woMA0IeCIvSISLF52m4XOvAu4tBRf03sNQzc2oXCLb9BZ4HYHJK7rSQ"}, + {"PUB_BLS_kYxGibaaU5EfQrnJpWcjwmY07j6px-uwJ0J_6RE7f9DrqhI3-NVyjw_jayvZ03wUjt96D7mecxSjEw3ZVHlguTykrjkI06otfpvv9Go_yS0gGmNYIRSWpOKtBIY8cIkEFVc8Ng", "SIG_BLS_NdXmsMAdWh8qSvUqDjKCJVjCjnCuDIeXQ_4XzFvCNGxZGwEDNhWgMVNdcLoEl7cUbiiuIdZVPC16E5_iYbSGfkPUBfx3Vh03GTy31a3dsXSciEM2VVGlBg5c_2vZTwEAbyYrVUT-sdt0nxO139I3Mk6Y6bauELYVkMVvv9E9Y_MjbkRnKDNQDqJACg46FEkFk-YQ0vvOA7sDyTP70BFwvF89DsE3db_g1sPjDfj7Kk3bda4KqMFncDObXIPk8QsY6gqzvw"}, + {"PUB_BLS_p819OPn04Fz4EI1QKrAOY0cKeGBPAyM1vFOc7yZn-cMSjIgyuSy3VVqNl8SgS2wRVE_kW9Ix2DIowByUsUrDVhJ-aay-VeP-EGzqpJLXu-baMRiGO5Wq8HQHMv-70zsXicba1Q", "SIG_BLS_38H7fX82apWxSCHS9-r3xW14hoH0zeFjqCq3bKajptvsEREzvY-m8njOocQJpQwJWmG5lxQ0Ij9JAu1qS9NMvnzt3tGWYWPK5cvczO6y4JrGPsa9c_Qx-g4YEFvj0oILtypCHl_c3moWttBZRra-QIESSeRnrsgtjpbb7EDORTeSa7_fp15aLaKbl3pugUIZU7uINgsCetG-mim3v4KiBRcZbAkG_m-dwqY099vTTFMA7Vt3xc3HOMk7urrvxAsQP2GnFA"}, + {"PUB_BLS_tbqdEUxBSTTpN60gIz8CGQL19G9mlOK9hcFuRQc9HQ9aZnF84BJQh3BP2mDG-kYDom_pohAEWry2w1e6AdgDcIcxpP2IbiZm000rDXZu7Bfv4Ebh6X7fVtDUt4piD9gCHXVw1A", "SIG_BLS_GmwLJWgq905FbJaJm0oTi8wiXlGIAm865thKx5MVVpGetMTh_9LtEEi0-iB0mmwC4OrVYbEoZwRSPsiMpA_VEcmrubWMN1noXEdjFG69LJVn9GLS4guCJQe_0W3_i9IDwIv7fixBaJyj8-iWvDR2n_vAmKdMUTDDtfdWeeXZ6yEwdYfsoyjIqUhXQq3Axk4AxiVFZ7yfiOkk3aGKOVwdCwd623WgiPldI-DEPUS0GaqXwgXtEyLtlDtdC13NovwC-9Jmsw"}, + {"PUB_BLS_mtAiKKCgt5QKDDn14QuQhs2AugC8XFQFQr7qUqHLodf264yUawOtzMr__juNTFQUWOr-JfKfUW1GfxLi0xXOYmEpw4wZaDm6VQCgTsOtTp5gaFcp1IJiVHDG1UuDB_oFKmMA1Q", "SIG_BLS_RMIvMoGMmd3tBHrDZSR_lQiR-mx0BJE7ZU_3HrdYfmhO8O9TE8iphSs3rETKFfIRIEU9N46DQBWU0t9wQLD468Pi92Gt6zEYREctw4_tNDtcqBGrYfr7g69qX97uqzsUulqyT_lRLH4-rwhPlRJgI6hg-G4C4bXTjUs_2LGoEhpvD6Y6LDTR9ek_Buuwra0OojtZ7anuFotVOD4uuBf34IQPyWrO9-X5RJ9bv19C09vCLbO8Djf8JCfr9cI0sh8TrOj4Gg"}, + {"PUB_BLS_j5fD6oG8C76CX7HzWxWf3XSU3gvROUybbTD9W1B_w2ilH98zBzXZ5VHmtIZCQ7YHUyQISAbjDUKwR2h1SL_jyHSw7G18Fj8Q8WK_I-UWdATbvH0xjjnmM-FQurPIxRsWsu7VvQ", "SIG_BLS_kzxMg5-VsVPgSKLdLJwRpJE7Zh8GtX8KaC-5zGU0RTm0mHx4wU_IbhqXBgEYrLkPhTtD7GIOzIMQgHTjsFxfDXOw2_s9dFiHwtjzPvOnQ5f4zFgmXipWjFBOSKzFP-sUwk4mMuvFO0dbva1RghLvk1G5T8H_aNGnWyb8ywQwC06axbBw5_poiU6DtonashoZ-ei2YRttxKdUbcg87BghKZNuBUfRXiNe1p4knuKM5o9W96pbI6uz6Dryn3IVuaMKUhtlnw"}, + {"PUB_BLS_M8ZZq5MspUdQmeclKbv1vZnSNy-2Qn_Yc9euP3zzG_bNfRwLPzA0UNQNmW66OZELZM_4lQ2scuQbb2gSKK462_p9we3ea_aTf18GLTinFm6Pp8Xr-ESveFEc48rx4kcQjY_Ddw", "SIG_BLS_ZRps69hLvs23lYlr68NEt6iIDvuUBhbDjIaUX3prARqYGJZB2FnB24tOLV83EE4IBrmGw-frILt1v5NRHUDJHgaoMndsmR2C2itoUDY7af7nOmxB5xaI5SNSiO_I2mMYQBDGaThDcnhCdalhzkDVmhOUeXR3wGSmNbPccTUf0J_DS5FmBzwnroaYJe8C6o0WRn4K0Wdsy5r_QNBsYtmSXxZf6vSdQJyaWQMIyowRHE3ve1L0F9PMVlNzZndemVwWExKQag"}, + {"PUB_BLS_aYnBaZVLoANPkIe3uyD453xc2NNYnIXupXTlAWbjaZ32CiGqfJYjtUJuoDf4i2wCMi_cQrv2tlLGpcYKql8g_B3NbFQrmHHwc80JaJi_YTVn4LDkIi1-jtHpsQ9pU28Zqfqx2Q", "SIG_BLS_kfYCci5ZsW0AJGWSxVxyx3Q3Lud_xB_VO1u0-9cJi1yfGC-rNbo_erFzbeOgLCIHYIE-kE4BWNJuvbO5sZ05walDhp33cCCMMeiEZUlk-sFUQdyhVJ4HtnsTea45jSMCjn650lXufOXlAbo3D_LrL_GH8y24OZVcI--iFuesi97SzEHifWBhLPy_yEBHcY4Gj0Ll37-y6moBx8L2NO4ZzSEiYViIyMQHHBTcb_qwPHzHR1TJeuKWp8hnnf3dirUA4n1XdQ"}, + {"PUB_BLS_xY48yStp-XsqjKikK50yzyGmK_6NacUmsJXUJNbjT-FKbeQ1bvbb4kEhtBP9K8QXfjRNvogpO2LSnK7G7P2xe7PP9NAZY-VmmeWBCUxCU_ZBPB7OiYeMr9JT9gXCLusQl-Amfg", "SIG_BLS_wYQJ7gnJCWhhsIjK1zbJzUXNVde_h0FH_6l6WtkiG0jdVTp-zkQtGzJR-P3aSPoFveLLpf8pTBU8vosk0eP3Ur3oRMl7Xnh-Xy9dWq0JglRSZQm-n1999TFYkWNH8T0HiNYFaXXBt5NA3LnMkoulZ16DsHfDxfw3Ggsq7BTJg68dsDrWscGXoa6C5ixU8lMOa2nf7sY_U6Qm0jnvNqLBCe1sNlgVDPhYXguIanAx92rEvW0KAFBykS96wg9sV2sRXsuJTQ"}, + {"PUB_BLS_v-d2afMcdbQp1EyukkQ_CUw8Q2a1mNC5ir4aJUUGTz96ER57K8TEwZGnYdoTmh0I5hzT3YaXkAuhvdkxuRKGi0saJgpkSP6UA8QKWqF0oJ3dAh7pG6mhZUGWybi51R8EZttgQg", "SIG_BLS_qgw6olECCtBviiEwjk3ve4Unomlkk37jSoG5IPfExsLXh-MfPGfkxZZfLDXzBWsY_wb7LZh2oxPKKYl_wXzIVGLFfSk8623WNegg8Hy7C32Uo2mlm0Eg-3fdjs_OFKIXdVZwheDXOOBycMAUEV1FR-jOC7TfOASqcO6eOAyo8Vjy0VoyIQx2mI73ocQFQeQLUUigmylx4mB2jjnbbZ7JY4y4X1gWIYiSoe8PoxRYmZJdSz8W9Ku0dRN9f8ir4SoQJ8lfKw"}, + {"PUB_BLS_TGdjRLnSlH5lN75APoANTjnuZ3mh8Uqy4GEqzoc6su9t7dOmrsoAtKn2TqHaZFYYt1MuoDF8eYBwS1YHN8w_vbaEzUupBtWdU-QMzOxw4Qei6CLt5xlju1WfRXaPCu8IQXbOTw", "SIG_BLS_v6xg1vlIB4QZzZCx1CUQSTSOnhRJQpx7Qf3VB2NdAXRs09vrmB2fxVfvxdkwngYUQgcwjs_XBvSGX0ECvqYz2wNHmTS-8O0SIeI2Ne6BRcLO_s47ssG7ookuMOWD14sYeM1embZy4BLD68hapxPeyEzY6c9U8knwHXOs_PmgTfxPKbj_Gd53n6YogEHyltIQV_xo83mdu-eG2ny4pQ0PgTBJakhbKfL5z_TtAHCkUbVO84Gnx4rPYW8JjaeNbkUHAa9IRA"}, + {"PUB_BLS_Dow8yQTh_mVETS4ky1y8ae9zcDuQZtHXlYEMnTTx10nczdrwZExP-6bWQcYpfu4Cj5UGJdxjHjHhdk1BQItK22FaZ_bZb1yURrSuqmr7CeuU9HyRPOZ3id03xCbcaFoFqvif5g", "SIG_BLS_C5uvcsKu09x5sBzWjmz7V3amYKnKPOJrw8s0FyaohXvF71b2_WZogus1K692VdgTTckPItM__Xe38TgXb5rJTCpD7nKiKjXTpuKQ2IMM0PEQFXhY_1sVrUXYdIghX9cJm0_wILLcJc39--lVCrPKC0lGdV5d1RUy3cnb-Z4au4BFUSh5vY9oE7R0jf9jqO8FOiB0G7VFurRPeWVKfQbtgohriP1_TmmDH9iTjtgzvKO3YvZAxrnxiYCTocXy_poMekgNnQ"}, + {"PUB_BLS_1ZV6MNrDyg1_VOqkIQ6xaYoYi6diO_obKjSnj9-wspP2PQGZ1mIPqJ-2zMuHuv4F-D0mFVkh4TBZd_ildGCr7foEzxUG25f1DjSuhcAfC-X-q0eYh1NxnZzeiHCKjU0OXnAfXQ", "SIG_BLS_Ht4ZYXmuDXUw3jDgi7dwvUhm9nj8cs3kMgqJYmUvH5Kb75BmjKOgOE8EOi4NsWQNoA6JmvjZ5WZyFFm0Fv8uNmvgrlWu4xU_uEkmThkD5C47dk88tRi-Ve74GjjjOIMEDkUjmMka18dUDu-UTPqy56ju-XGDIwvPrED8ZqK7L_3ZOSPcb21QXb2iVEP-UbQXJHnDaU4zSbKt60EFaWEWgPt501A98Gwti0aBJFPJjW8jaziErlCHUKmJaEISjjUCQBbc4Q"}, + {"PUB_BLS_xCZ8dBxW7GCPvCh2v5AEAMLpPlqb5MY6KQ4AjgZiH63WCrsPF-tNOSb1tj3Tml0WQHnXtuQtAXdysAX6wGX92zvCtl779vtEnXcSkZrcoXQ036IeDg91B7s4HZVDdTIRhkWdIg", "SIG_BLS_P7bbvvAPtz1hX86X2NSEZKn6AljBpq00pL8wwpIrEjlVkWh-tSwPephv9SNyoTkE8_4HB5e97-MPILmEpYp_5lphbcimrCIZsO53dWxxHmp7TgxofGmzk6_fSDCuZI4M3fsnI3-NnjzpRKg8YK7FmAv0clHA9wj6nLa7HPsDsV8hHqAyAJwxxttMpSOpBMkESUuLXJL0AuaRsTU0KUCGeNQQxCkR_tYhOUPLZwh_Lc__35PxpZQk5Ivm1UmDZRcNRQUXEA"}, + {"PUB_BLS_lG6RfU8c0kJVvFNA8ikdU1dOtt_FrsHd8L7OMRHO9D-ct18IztEKqkHBAb6cXJEL2VL7cr2rI_LL20Fgu_9e4PIG4U54o5lp_ydwAweGtay1190QB5l8RDGT-s_sshMBkV6N8A", "SIG_BLS_--zVqQC10legB0F_UiBsQlgdNDi-VfFPo4KJPa8-Npf_bKqqaTjvHrKl56398ecBpo2GQbPeYvEM0aE2Pg-lfQLbRlFCKuOBvHsz01nBmlJU3Ai1wkwiIaLrhURIrhELcnFnA4EF60DSwMTND5FGRYHqpX3nZULiu5z-a6hrvrFUMDuCiI6fMblhX1-3sbcTwQAm7X8m-V70X_1zNHI1uuZEC4AdSouXdyG3vgeg10osfnBQn7XMhJr4SA45EW8QLBwQ4w"}, + {"PUB_BLS_3yY58HBFvJwwIcc-nADx4WqAAfLOhVa3ORc_bqN7bH5zsFImQHv98GRInYU8PWQUBbE-mNM_nsjBYcjPGMXRkePZTlgNfWtFkm5X6JkWLshvwMSzABl86UF1i7eXPbkWaHLzHQ", "SIG_BLS_pWQzUEOXHvgrf7UL7rSvwFgd6tZ7BrYtUFZG2AQgvC76cj5bUf9Cg0h-yTwOMkEDX48ZuPu4BsbifACr1cnXQ8vSYYFMcthVCL04FF6nGzh3Rungs4MyUDO0OwmXEtMW9U39CnquCoGhjFtgq--En4PuGmPhBnpDaDZzUau3Y0pqnji3gWpEM_wYJQUDvtIYUkXmOFXQvizWwYKMT2F7bXr6TLRIcIoMv7qkKReiNSBwnId8qY6rsqEd1MFpb1cJV6meeQ" }, + {"PUB_BLS_DwHoibpeQ6i1VnoF8cjYFI-Z6etehxApERYpKpjP8IvVEXeDUaUO54siI6oSFAYB4ZqKrBykU081FDqpf7ao41McS_N92cnNNjB56_gB1uGmjYlQMJgrj26fX2tveZYT2BXsTQ", "SIG_BLS_zfP89oJUxuryHX0Ok45UbzM3It-pqoBxgcqnF3fZ9Z48e6AYHkPWiwvktfBlsYYVYUtSYvERBbu2YVf9S-DA5i7F-feHoHKEf0MNEam-w-qy09lZn0jaT8OX4JIK078ItlLfMULIkLyQ_RxzjX9G-khbsXN0ody6GD3L4JV69Ol_fRPt9OH20CFkgKfUF18FESPSxIPXgyawxPJY3ND-GAfsftZmggTrcJsLJMab7wkJ4j_8L1I9hBfZ9tO3H3AZ1hQ5Hg"} +}; BOOST_AUTO_TEST_SUITE(eosio_system_finalizer_key_tests) @@ -62,7 +107,7 @@ const name bob = "bob111111111"_n; BOOST_FIXTURE_TEST_CASE(register_finalizer_key_invalid_key_tests, finalizer_key_tester) try { { // attempt to register finalizer_key for an unregistered producer BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer is not a registered producer" ), - register_finalizer_key(alice, finalizer_key_1, pop1)); + register_finalizer_key(alice, finalizer_key_1, pop_1)); } // Now alice1111111 registers as a producer @@ -73,7 +118,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_invalid_key_tests, finalizer_key_ push_action(alice, "regfinkey"_n, mvo() ("finalizer_name", "alice1111111") ("finalizer_key", "UB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) - ("proof_of_possession", pop1 ) + ("proof_of_possession", pop_1 ) ) ); } @@ -92,7 +137,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_invalid_key_tests, finalizer_key_ ("finalizer_name", "alice1111111") // use a valid formatted finalizer_key for another signature ("finalizer_key", finalizer_key_1) - ("proof_of_possession", pop2) + ("proof_of_possession", pop_2) ) ); } } // register_finalizer_key_invalid_key_tests @@ -102,7 +147,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_same_finalizer_tests, finalize BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); // First finalizer key - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop_1) ); auto fin_info = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); @@ -115,7 +160,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_same_finalizer_tests, finalize BOOST_REQUIRE_EQUAL( finalizer_key_1, fin_key_info["finalizer_key"].as_string() ); // Second finalizer key - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_2, pop2 )); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_2, pop_2 )); auto fin_info2 = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( 2, fin_info2["num_registered_keys"].as_uint64() ); // count incremented by 1 @@ -127,7 +172,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_duplicate_key_tests, finalizer_ke BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); // The first finalizer key - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop_1) ); auto fin_info = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); @@ -135,7 +180,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_duplicate_key_tests, finalizer_ke // Same finalizer key as the first one BOOST_REQUIRE_EQUAL( wasm_assert_msg( "duplicate finalizer key" ), - register_finalizer_key(alice, finalizer_key_1, pop1) ); + register_finalizer_key(alice, finalizer_key_1, pop_1) ); } FC_LOG_AND_RETHROW() // register_finalizer_key_duplicate_key_tests @@ -145,14 +190,14 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_different_finalizers_tests, fi BOOST_REQUIRE_EQUAL( success(), regproducer(bob) ); // alice1111111 registers a finalizer key - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop_1) ); auto fin_info = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( 1, fin_info["num_registered_keys"].as_uint64() ); // bob111111111 registers another finalizer key - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop2) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop_2) ); auto fin_info2 = get_finalizer_info(bob); BOOST_REQUIRE_EQUAL( 1, fin_info2["num_registered_keys"].as_uint64() ); @@ -165,7 +210,7 @@ BOOST_FIXTURE_TEST_CASE(register_duplicate_key_from_different_finalizers_tests, BOOST_REQUIRE_EQUAL( success(), regproducer(bob) ); // The first finalizer key - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop_1) ); auto fin_info = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); @@ -173,7 +218,7 @@ BOOST_FIXTURE_TEST_CASE(register_duplicate_key_from_different_finalizers_tests, // bob111111111 tries to register the same finalizer key as the first one BOOST_REQUIRE_EQUAL( wasm_assert_msg( "duplicate finalizer key" ), - register_finalizer_key(bob, finalizer_key_1, pop1) ); + register_finalizer_key(bob, finalizer_key_1, pop_1) ); } FC_LOG_AND_RETHROW() // register_duplicate_key_from_different_finalizers_tests @@ -191,8 +236,8 @@ BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_failure_tests, finalizer_key_test activate_finalizer_key(alice, finalizer_key_1) ); // Alice registers a finalizer key - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop2) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop_1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop_2) ); // Activate a finalizer key not registered by anyone BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered" ), @@ -214,8 +259,8 @@ BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_success_tests, finalizer_key_test BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); // Alice registers two finalizer keys. The first key is active - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_2, pop2) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop_1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_2, pop_2) ); // Check finalizer_key_1 is the active key auto alice_info = get_finalizer_info(alice); @@ -250,9 +295,9 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_failure_tests, finalizer_key_tester delete_finalizer_key(alice, finalizer_key_1) ); // Alice and Bob register finalizer keys - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop2) ); - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_3, pop3) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop_1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop_2) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_3, pop_3) ); // Delete a finalizer key not registered by anyone BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered" ), @@ -274,8 +319,8 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_success_test, finalizer_key_tester) BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); // Alice registers two keys and the first key is active - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_2, pop2) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop_1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_2, pop_2) ); // Check finalizer_key_1 is the active key auto alice_info = get_finalizer_info(alice); @@ -296,7 +341,7 @@ BOOST_FIXTURE_TEST_CASE(delete_last_finalizer_key_test, finalizer_key_tester) tr BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); // Alice registers one key and it is active - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop_1) ); // Check finalizer_key_1 is the active key auto alice_info = get_finalizer_info(alice); @@ -314,4 +359,20 @@ BOOST_FIXTURE_TEST_CASE(delete_last_finalizer_key_test, finalizer_key_tester) tr } FC_LOG_AND_RETHROW() // delete_last_finalizer_key_test +BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { + auto producer_names = active_and_vote_producers(); + + register_finalizer_keys(producer_names); + + BOOST_REQUIRE_EQUAL(success(), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); + + // Verify last finalizer key id table contains all finalzer keys + for( auto& p : producer_names ) { + auto finalizer_info = get_finalizer_info(p); + uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); + } +} +FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() From 0f5d3f75bcc3b37b625f0a369daf68fca8bfb99d Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 4 Apr 2024 16:16:01 -0400 Subject: [PATCH 54/94] Verify nodeos indeed switches to Savanna after switchtosvnn action is pushed --- tests/eosio.finalizer_key_tests.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 3eaf3934..9717fc0f 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -372,6 +372,17 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); } + + // Produce enough blocks so transition to Savanna finishes + produce_blocks(400); + + // If head_finality_data has value, it means we are at least after or on + // Savanna Genesis Block + BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); + + // Cannot switch to Savanna multiple times + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "switchtosvnn can be run only once" ), + push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); } FC_LOG_AND_RETHROW() From b734453f6c5347676171bad85f3fba494b81242a Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 4 Apr 2024 16:22:58 -0400 Subject: [PATCH 55/94] use std::move when setting finalizer_authorities --- contracts/eosio.system/src/finalizer_key.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 960499a1..443b138e 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -85,7 +85,7 @@ namespace eosiosystem { // Establish finalizer policy and call set_finalizers() host function eosio::finalizer_policy fin_policy { .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, // or hardcoded to 15? - .finalizers = finalizer_authorities + .finalizers = std::move(finalizer_authorities) }; eosio::set_finalizers(std::move(fin_policy)); // call host function @@ -224,7 +224,7 @@ namespace eosiosystem { // last_finkey_ids table has already been updated. Call set_finalizers host function directly eosio::finalizer_policy fin_policy { .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, - .finalizers = finalizer_authorities + .finalizers = std::move(finalizer_authorities) }; eosio::set_finalizers(std::move(fin_policy)); // call host function } From 6bccc06820a1e94e959ad2d111ec7ba5b4fb9222 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 4 Apr 2024 16:24:01 -0400 Subject: [PATCH 56/94] add missing finalizer_name in action descriptions --- .../eosio.system/include/eosio.system/eosio.system.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 0fd0b09e..2493e3e4 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1253,7 +1253,7 @@ namespace eosiosystem { * * @pre `finalizer_name` must be a registered producer * @pre `finalizer_key` must be a registered finalizer key - * @pre Authority of `finalizer` + * @pre Authority of `finalizer_name` */ [[eosio::action]] void actfinkey( const name& finalizer_name, const std::string& finalizer_key ); @@ -1268,8 +1268,8 @@ namespace eosiosystem { * * @pre `finalizer_name` must be a registered producer * @pre `finalizer_key` must be a registered finalizer key - * @pre `finalizer_key` must be not be active, unless it is the last registered finalizer key - * @pre Authority of `finalizer` + * @pre `finalizer_key` must not be active, unless it is the last registered finalizer key + * @pre Authority of `finalizer_name` */ [[eosio::action]] void delfinkey( const name& finalizer_name, const std::string& finalizer_key ); From 00f526542f7788f7a56e3787db5ac6ac00f02db9 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 4 Apr 2024 16:53:58 -0400 Subject: [PATCH 57/94] Add a test for not enough finalizer keys registered for switching to Savanna --- tests/eosio.finalizer_key_tests.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 9717fc0f..7ae516c2 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -55,11 +55,15 @@ struct finalizer_key_tester : eosio_system_tester { ("finalizer_key", finalizer_key) ); } - void register_finalizer_keys(const std::vector& producer_names) { + void register_finalizer_keys(const std::vector& producer_names, uint32_t num_keys_to_register) { uint32_t i = 0; for (const auto& p: producer_names) { BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(p, key_pair[i].pub_key, key_pair[i].pop)); ++i; + + if ( i == num_keys_to_register ) { + break; + } } } }; @@ -362,7 +366,7 @@ FC_LOG_AND_RETHROW() // delete_last_finalizer_key_test BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { auto producer_names = active_and_vote_producers(); - register_finalizer_keys(producer_names); + register_finalizer_keys(producer_names, 21); BOOST_REQUIRE_EQUAL(success(), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); @@ -386,4 +390,15 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(switchtosvnn_not_enough_finalizer_keys_tests, finalizer_key_tester) try { + auto producer_names = active_and_vote_producers(); + + register_finalizer_keys(producer_names, 20); + + // Have only 20 finalizer keys, short by 1 + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "not enough top producers have registered finalizer keys" ), + push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); +} +FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() From 59184ccf508eb17ab95c64afcb0eaf3219e2a84f Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 4 Apr 2024 21:10:22 -0400 Subject: [PATCH 58/94] Add tests for update_elected_producers in both finalizer key changes and no finalizer key changes --- tests/eosio.finalizer_key_tests.cpp | 96 ++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 3 deletions(-) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 7ae516c2..3764d5a3 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -364,10 +364,10 @@ BOOST_FIXTURE_TEST_CASE(delete_last_finalizer_key_test, finalizer_key_tester) tr FC_LOG_AND_RETHROW() // delete_last_finalizer_key_test BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { + // Register and vote 21 producers auto producer_names = active_and_vote_producers(); - + // Register 21 finalizer keys register_finalizer_keys(producer_names, 21); - BOOST_REQUIRE_EQUAL(success(), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); // Verify last finalizer key id table contains all finalzer keys @@ -378,7 +378,7 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { } // Produce enough blocks so transition to Savanna finishes - produce_blocks(400); + produce_blocks(504); // 21 Producers * 12 Blocks per producer * 2 rounds to reach Legacy finality // If head_finality_data has value, it means we are at least after or on // Savanna Genesis Block @@ -393,6 +393,7 @@ FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(switchtosvnn_not_enough_finalizer_keys_tests, finalizer_key_tester) try { auto producer_names = active_and_vote_producers(); + // Register 20 finalizer keys register_finalizer_keys(producer_names, 20); // Have only 20 finalizer keys, short by 1 @@ -401,4 +402,93 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_not_enough_finalizer_keys_tests, finalizer_ } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(update_elected_producers_no_finalizers_changed_test, finalizer_key_tester) try { + auto producer_names = active_and_vote_producers(); + register_finalizer_keys(producer_names, 21); + BOOST_REQUIRE_EQUAL(success(), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); + + // Produce enough blocks so transition to Savanna finishes + produce_blocks(504); // 21 Producers * 12 Blocks per producer * 2 rounds to reach Legacy finality + + // head_finality_data is available when nodoes is in Savanna + BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); + + // Verify last finalizer key id table contains all finalzer keys + std::set last_finkey_ids; + for( auto& p : producer_names ) { + auto finalizer_info = get_finalizer_info(p); + uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); + last_finkey_ids.insert(active_key_id); + } + + // Produce for one round + produce_block( fc::minutes(2) ); + + // Since finalizer keys have not changed, last_finkey_ids should be the same + std::set last_finkey_ids_2; + for( auto& p : producer_names ) { + auto finalizer_info = get_finalizer_info(p); + uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); + last_finkey_ids_2.insert(active_key_id); + } + + BOOST_REQUIRE_EQUAL( true, last_finkey_ids == last_finkey_ids_2 ); +} +FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finalizer_key_tester) try { + auto producer_names = active_and_vote_producers(); + register_finalizer_keys(producer_names, 21); + BOOST_REQUIRE_EQUAL(success(), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); + + // Produce enough blocks so transition to Savanna finishes + produce_blocks(504); // 21 Producers * 12 Blocks per producer * 2 rounds to reach Legacy finality + + // head_finality_data is available when nodoes is in Savanna + BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); + + // Verify last finalizer key id table contains all finalzer keys + std::set last_finkey_ids; + for( auto& p : producer_names ) { + auto finalizer_info = get_finalizer_info(p); + uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); + last_finkey_ids.insert(active_key_id); + } + + // Pick a producer + name test_producer = producer_names.back(); + + // Take a note of old active_key_id + auto p_info = get_finalizer_info(test_producer); + uint64_t old_id = p_info["active_key_id"].as_uint64(); + + // Register and activate a new finalizer key + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(test_producer, finalizer_key_1, pop_1) ); + BOOST_REQUIRE_EQUAL( success(), activate_finalizer_key(test_producer, finalizer_key_1)); + + // Since producer is an active producer, the finalizer key change takes effective + // immediately. + std::set last_finkey_ids_2; + for( auto& p : producer_names ) { + auto finalizer_info = get_finalizer_info(p); + uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); + last_finkey_ids_2.insert(active_key_id); + } + + // Take a note of new active_key_id + auto p_info_2 = get_finalizer_info(test_producer); + uint64_t new_id = p_info_2["active_key_id"].as_uint64(); + + // After replace the old_id with new_id in last_finkey_ids, + // last_finkey_ids should be the same as last_finkey_ids_2 + last_finkey_ids.erase(old_id); + last_finkey_ids.insert(new_id); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids == last_finkey_ids_2 ); +} +FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() From 33e54f12bf6acd41d0cc60a457da2dd0495d3ff5 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 4 Apr 2024 21:11:11 -0400 Subject: [PATCH 59/94] Fix primary key modified in replace_key_in_finalizer_policy() --- .../include/eosio.system/eosio.system.hpp | 2 +- contracts/eosio.system/src/finalizer_key.cpp | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 2493e3e4..14202da1 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1613,7 +1613,7 @@ namespace eosiosystem { // defined in finalizer_key.cpp bool is_savanna_consensus() const; void set_finalizers( std::vector&& finalizer_authorities, const std::vector& finalizer_key_ids, const std::unordered_set& kept_key_ids ); - void replace_key_in_finalizer_policy(const name& finalizer, uint64_t old_id, uint64_t new_id); + void replace_key_in_finalizer_policy(const name& finalizer, const last_finkey_ids_table::const_iterator& old_id_itr, uint64_t new_id); template class registration { diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 443b138e..baafa305 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -193,21 +193,26 @@ namespace eosiosystem { // Replace the finalizer policy immediately if the finalizer is // participating in current voting - if( _last_finkey_ids.find(old_active_key_id) != _last_finkey_ids.end() ) { - replace_key_in_finalizer_policy(finalizer_name, old_active_key_id, fin_key->id); + const auto old_id_itr = _last_finkey_ids.find(old_active_key_id); + if( old_id_itr != _last_finkey_ids.end() ) { + replace_key_in_finalizer_policy(finalizer_name, old_id_itr, fin_key->id); } } // replace the key in last finalizer policy and call set_finalizers host function immediately - void system_contract::replace_key_in_finalizer_policy(const name& finalizer, uint64_t old_id, uint64_t new_id) { - // replace key ID in last_finkey_ids_table - auto id_itr = _last_finkey_ids.find(old_id); - _last_finkey_ids.modify( id_itr, get_self(), [&]( auto& f ) { - f.key_id = new_id; + void system_contract::replace_key_in_finalizer_policy(const name& finalizer, const last_finkey_ids_table::const_iterator& old_id_itr, uint64_t new_id) { + // Delete old id + assert(old_id_itr); + _last_finkey_ids.erase(old_id_itr); + + // Insert new ID + _last_finkey_ids.emplace( get_self(), [&]( auto& f ) { + f.key_id = new_id; }); std::vector finalizer_authorities; + // Build a new finalizer_authority by going over all last_finkey_ids for (auto itr = _last_finkey_ids.begin(); itr != _last_finkey_ids.end(); ++itr) { auto key = _finalizer_keys.find(itr->key_id); assert( key != _finalizer_keys.end() ); From 6a21d55fbb1e644c7c509111d20f61936f6d9486 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 5 Apr 2024 11:51:39 -0400 Subject: [PATCH 60/94] Add a test of deleting an active producer's finalizer key and another producing taking over --- tests/eosio.finalizer_key_tests.cpp | 108 ++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 3764d5a3..f27730e7 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -491,4 +491,112 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finali } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, finalizer_key_tester) try { + // creat voters + const asset net = core_sym::from_string("80.0000"); + const asset cpu = core_sym::from_string("80.0000"); + const std::vector voters = { "producvotera"_n, "producvoterb"_n, "producvoterc"_n, "producvoterd"_n }; + for (const auto& v: voters) { + create_account_with_resources( v, config::system_account_name, core_sym::from_string("1.0000"), false, net, cpu ); + transfer( config::system_account_name, v, core_sym::from_string("100000000.0000"), config::system_account_name ); + BOOST_REQUIRE_EQUAL(success(), stake(v, core_sym::from_string("30000000.0000"), core_sym::from_string("30000000.0000")) ); + } + + // create accounts {defproducera, defproducerb, ..., defproducerz, abcproducera, ..., defproducern} and register as producers + std::vector producer_names; + { + producer_names.reserve('z' - 'a' + 1); + { + const std::string root("defproducer"); + for ( char c = 'a'; c <= 'z'; ++c ) { + producer_names.emplace_back(root + std::string(1, c)); + } + } + { + const std::string root("abcproducer"); + for ( char c = 'a'; c <= 'n'; ++c ) { + producer_names.emplace_back(root + std::string(1, c)); + } + } + setup_producer_accounts(producer_names); + for (const auto& p: producer_names) { + BOOST_REQUIRE_EQUAL( success(), regproducer(p) ); + produce_blocks(1); + BOOST_TEST(0 == get_producer_info(p)["total_votes"].as()); + } + } + + produce_blocks( 2 * 21 * 1 ); + + // producvotera votes for defproducera ... defproducerj + // producvoterb votes for defproducera ... defproduceru + // producvoterc votes for defproducera ... defproducerz + // producvoterd votes for abcproducera ... abcproducern + { + BOOST_REQUIRE_EQUAL(success(), vote("producvotera"_n, vector(producer_names.begin(), producer_names.begin()+10))); + BOOST_REQUIRE_EQUAL(success(), vote("producvoterb"_n, vector(producer_names.begin(), producer_names.begin()+21))); + BOOST_REQUIRE_EQUAL(success(), vote("producvoterc"_n, vector(producer_names.begin(), producer_names.begin()+26))); + BOOST_REQUIRE_EQUAL(success(), vote("producvoterd"_n, vector(producer_names.begin()+26, producer_names.end()))); + } + + // Register 21 finalizer keys + register_finalizer_keys(producer_names, 21); + // Transition to Savanna + BOOST_REQUIRE_EQUAL(success(), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); + + // Produce enough blocks so transition to Savanna finishes + produce_blocks(2 * 21 * 12); + // head_finality_data is available when nodoes is in Savanna + BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); + + // Verify last finalizer key id table contains all finalzer keys + std::set last_finkey_ids; + for( auto i = 0; i < 21; ++i ) { + auto finalizer_info = get_finalizer_info(producer_names[i]); + uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); + last_finkey_ids.insert(active_key_id); + } + + const auto new_prod_name = producer_names[21]; + BOOST_REQUIRE_EQUAL( success(), regproducer(new_prod_name) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(new_prod_name, finalizer_key_1, pop_1) ); + auto prod_info = get_finalizer_info(new_prod_name); + uint64_t new_id = prod_info["active_key_id"].as_uint64(); + + // Wait for two rounds of producer schedule so new finalizer policy takes effect + produce_block( fc::minutes(2) ); + + // Delete an active finalizer key + name deleted_prod_name = producer_names[0]; + auto p_info = get_finalizer_info(deleted_prod_name); + uint64_t deleted_id = p_info["active_key_id"].as_uint64(); + auto k_info = get_finalizer_key_info(deleted_id); + auto deleted_key = k_info["finalizer_key"].as_string(); + BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(deleted_prod_name, deleted_key) ); + + // Wait for two rounds of producer schedule so new finalizer policy takes effect + produce_blocks(504); + + // find new last_finkey_ids + std::set last_finkey_ids_2; + for( auto i = 1; i < 21; ++i ) { + auto finalizer_info = get_finalizer_info(producer_names[i]); + uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); + last_finkey_ids_2.insert(active_key_id); + } + + // Make sure new_id is in the new last_finkey_ids + BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(new_id).is_null() ); + last_finkey_ids_2.insert(new_id); + + // After replace the deleted_id with new_id in last_finkey_ids, + // last_finkey_ids should be the same as last_finkey_ids_2 + last_finkey_ids.erase(deleted_id); + last_finkey_ids.insert(new_id); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids == last_finkey_ids_2 ); +} +FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() From 8153e6ef4ff2b2c38ccf39ac8a981a4537c03a74 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 5 Apr 2024 17:01:42 -0400 Subject: [PATCH 61/94] Simplify tests using a new get_last_finkey_ids() --- tests/eosio.finalizer_key_tests.cpp | 69 ++++++++++++++--------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index f27730e7..108bf545 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -66,6 +66,25 @@ struct finalizer_key_tester : eosio_system_tester { } } } + + std::unordered_set get_last_finkey_ids() { + const auto* table_id_itr = control->db().find( + boost::make_tuple(config::system_account_name, config::system_account_name, "lastfkeyids"_n)); + + if (!table_id_itr) { + return {}; + } + + std::unordered_set last_finkey_ids; + auto t_id = table_id_itr->id; + const auto& idx = control->db().get_index(); + for (auto itr = idx.lower_bound(boost::make_tuple(t_id, 0)); itr != idx.end() && itr->t_id == t_id; ++itr) + { + last_finkey_ids.insert(itr->primary_key); + } + + return last_finkey_ids; + } }; const std::string finalizer_key_tester::finalizer_key_1 = "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA"; @@ -329,6 +348,8 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_success_test, finalizer_key_tester) // Check finalizer_key_1 is the active key auto alice_info = get_finalizer_info(alice); uint64_t active_key_id = alice_info["active_key_id"].as_uint64(); + auto num_registered_keys_before = alice_info["num_registered_keys"].as_uint64(); + auto finalizer_key_info = get_finalizer_key_info(active_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_1, finalizer_key_info["finalizer_key"].as_string() ); @@ -336,7 +357,9 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_success_test, finalizer_key_tester) // Delete the non-active key BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(alice, finalizer_key_2) ); - // ToDo: Need to check finalizer_key_2 is removed from the finalizer_key table using finalizer_key + alice_info = get_finalizer_info(alice); + auto num_registered_keys_after = alice_info["num_registered_keys"].as_uint64(); + BOOST_REQUIRE_EQUAL( num_registered_keys_before - 1, num_registered_keys_after ); } FC_LOG_AND_RETHROW() // delete_finalizer_key_success_test @@ -414,26 +437,18 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_no_finalizers_changed_test, fin BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); // Verify last finalizer key id table contains all finalzer keys - std::set last_finkey_ids; + auto last_finkey_ids = get_last_finkey_ids(); for( auto& p : producer_names ) { auto finalizer_info = get_finalizer_info(p); uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); - last_finkey_ids.insert(active_key_id); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_key_id) ); } // Produce for one round produce_block( fc::minutes(2) ); // Since finalizer keys have not changed, last_finkey_ids should be the same - std::set last_finkey_ids_2; - for( auto& p : producer_names ) { - auto finalizer_info = get_finalizer_info(p); - uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); - last_finkey_ids_2.insert(active_key_id); - } - + auto last_finkey_ids_2 = get_last_finkey_ids(); BOOST_REQUIRE_EQUAL( true, last_finkey_ids == last_finkey_ids_2 ); } FC_LOG_AND_RETHROW() @@ -450,12 +465,11 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finali BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); // Verify last finalizer key id table contains all finalzer keys - std::set last_finkey_ids; + auto last_finkey_ids = get_last_finkey_ids(); for( auto& p : producer_names ) { auto finalizer_info = get_finalizer_info(p); uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); - last_finkey_ids.insert(active_key_id); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_key_id) ); } // Pick a producer @@ -471,13 +485,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finali // Since producer is an active producer, the finalizer key change takes effective // immediately. - std::set last_finkey_ids_2; - for( auto& p : producer_names ) { - auto finalizer_info = get_finalizer_info(p); - uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); - last_finkey_ids_2.insert(active_key_id); - } + auto last_finkey_ids_2 = get_last_finkey_ids(); // Take a note of new active_key_id auto p_info_2 = get_finalizer_info(test_producer); @@ -550,12 +558,11 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); // Verify last finalizer key id table contains all finalzer keys - std::set last_finkey_ids; + auto last_finkey_ids = get_last_finkey_ids(); for( auto i = 0; i < 21; ++i ) { auto finalizer_info = get_finalizer_info(producer_names[i]); uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); - last_finkey_ids.insert(active_key_id); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_key_id) ); } const auto new_prod_name = producer_names[21]; @@ -579,17 +586,9 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final produce_blocks(504); // find new last_finkey_ids - std::set last_finkey_ids_2; - for( auto i = 1; i < 21; ++i ) { - auto finalizer_info = get_finalizer_info(producer_names[i]); - uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); - last_finkey_ids_2.insert(active_key_id); - } - + auto last_finkey_ids_2 = get_last_finkey_ids(); // Make sure new_id is in the new last_finkey_ids - BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(new_id).is_null() ); - last_finkey_ids_2.insert(new_id); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids_2.contains(new_id) ); // After replace the deleted_id with new_id in last_finkey_ids, // last_finkey_ids should be the same as last_finkey_ids_2 From f2d650c3f2719911b1485f6ef0b2421583a0637f Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 5 Apr 2024 17:02:29 -0400 Subject: [PATCH 62/94] minor editorial improvements --- contracts/eosio.system/src/finalizer_key.cpp | 48 ++++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index baafa305..e7d16a69 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -1,7 +1,6 @@ #include #include -#include namespace eosiosystem { @@ -21,17 +20,12 @@ namespace eosiosystem { // From up to 30 top producers, find 21 producers that meet all the normal requirements // for being a proposer and also have an active finalizer key - uint32_t n = 0; + uint32_t i = 0; auto idx = _producers.get_index<"prototalvote"_n>(); - for( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active(); ++it ) { - if( n > 30 ) { - break; - } - ++n; - + for( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active() && i < 30; ++it, ++i ) { auto finalizer = _finalizers.find( it->owner.value ); // If a producer is found in finalizers_table, it means it has at least one finalizer - // key registered, and one of them must be active + // key registered, and has an active key if( finalizer != _finalizers.end() ) { assert( !finalizer->active_key.empty() ); @@ -89,12 +83,12 @@ namespace eosiosystem { }; eosio::set_finalizers(std::move(fin_policy)); // call host function - // Purge any ids not in kept_key_ids from _last_finkey_ids + // Purge any ids not in kept_key_ids from last_finkey_ids table for (auto itr = _last_finkey_ids.begin(); itr != _last_finkey_ids.end(); /* intentionally empty */ ) { - if( kept_key_ids.contains(itr->key_id) ) { - ++itr; - } else { + if( !kept_key_ids.contains(itr->key_id) ) { itr = _last_finkey_ids.erase(itr); + } else { + ++itr; } } @@ -106,11 +100,15 @@ namespace eosiosystem { } } + static eosio::checksum256 get_finalizer_key_hash(const std::string& finalizer_key) { + return eosio::sha256(finalizer_key.data(), finalizer_key.size()); + } + // Action to register a finalizer key - void system_contract::regfinkey( const name& finalizer, const std::string& finalizer_key, const std::string& proof_of_possession) { - require_auth( finalizer ); + void system_contract::regfinkey( const name& finalizer_name, const std::string& finalizer_key, const std::string& proof_of_possession) { + require_auth( finalizer_name ); - auto producer = _producers.find( finalizer.value ); + auto producer = _producers.find( finalizer_name.value ); check( producer != _producers.end(), "finalizer is not a registered producer"); // Basic key and signature format check @@ -123,27 +121,27 @@ namespace eosiosystem { // Duplication check across all registered keys auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); - auto hash = eosio::sha256(finalizer_key.data(), finalizer_key.size()); + auto hash = get_finalizer_key_hash(finalizer_key); check(idx.find(hash) == idx.end(), "duplicate finalizer key"); // Proof of possession check is expensive, do it at last check(eosio::bls_pop_verify(fin_key_g1, signature), "proof of possession check failed"); // Insert into finalyzer_keys table - auto key_itr = _finalizer_keys.emplace( finalizer, [&]( auto& k ) { + auto key_itr = _finalizer_keys.emplace( finalizer_name, [&]( auto& k ) { k.id = _finalizer_keys.available_primary_key(); - k.finalizer_name = finalizer; + k.finalizer_name = finalizer_name; k.finalizer_key = finalizer_key; - k.finalizer_key_hash = eosio::sha256(finalizer_key.data(), finalizer_key.size()); + k.finalizer_key_hash = get_finalizer_key_hash(finalizer_key); }); // Update finalizers table - auto f_itr = _finalizers.find(finalizer.value); + auto f_itr = _finalizers.find(finalizer_name.value); if( f_itr == _finalizers.end() ) { // First time the finalizer to register a finalier key, // make the key active - _finalizers.emplace( finalizer, [&]( auto& f ) { - f.finalizer_name = finalizer; + _finalizers.emplace( finalizer_name, [&]( auto& f ) { + f.finalizer_name = finalizer_name; f.active_key_id = key_itr->id; f.active_key = { fin_key_g1.begin(), fin_key_g1.end() }; f.num_registered_keys = 1; @@ -174,7 +172,7 @@ namespace eosiosystem { // Check the key is registered const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); - auto hash = eosio::sha256(finalizer_key.data(), finalizer_key.size()); + auto hash = get_finalizer_key_hash(finalizer_key); auto fin_key = idx.find(hash); check(fin_key != idx.end(), "finalizer key was not registered"); @@ -248,7 +246,7 @@ namespace eosiosystem { // Check the key is registered auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); - auto hash = eosio::sha256(finalizer_key.data(), finalizer_key.size()); + auto hash = get_finalizer_key_hash(finalizer_key); auto fin_key = idx.find(hash); check(fin_key != idx.end(), "finalizer key was not registered"); From c39bf628830fe98c52255be62bc43429933ed407 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 5 Apr 2024 17:26:59 -0400 Subject: [PATCH 63/94] Improve action descriptions --- .../include/eosio.system/eosio.system.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 14202da1..893d94fb 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1232,12 +1232,13 @@ namespace eosiosystem { * by other block producers, the registration will fail. * A registered producer can have multiple registered finalizer keys. * - * @param finalizer - account registering `finalizer_key`, + * @param finalizer_name - account registering `finalizer_key`, * @param finalizer_key - key to be registered. The key is in base64url format. * @param proof_of_possession - a valid Proof of Possession signature to show the producer owns the private key of the finalizer_key. The signature is in base64url format. * - * @pre `finalizer` must be a registered producer - * @pre Authority of `finalizer` to register + * @pre `finalizer_name` must be a registered producer + * @pre `finalizer_key` must be in base64url format + * @pre Authority of `finalizer_name` to register. `linkauth` may be used to allow a lower authrity to exectute this action. */ [[eosio::action]] void regfinkey( const name& finalizer_name, const std::string& finalizer_key, const std::string& proof_of_possession); @@ -1249,10 +1250,10 @@ namespace eosiosystem { * the previously active finalizer key of that block producer. * * @param finalizer_name - account activating `finalizer_key`, - * @param finalizer_key - key to be activated, in base64url format. + * @param finalizer_key - key to be activated. * * @pre `finalizer_name` must be a registered producer - * @pre `finalizer_key` must be a registered finalizer key + * @pre `finalizer_key` must be a registered finalizer key in base64url format * @pre Authority of `finalizer_name` */ [[eosio::action]] @@ -1267,7 +1268,7 @@ namespace eosiosystem { * @param finalizer_key - key to be deleted. * * @pre `finalizer_name` must be a registered producer - * @pre `finalizer_key` must be a registered finalizer key + * @pre `finalizer_key` must be a registered finalizer key in base64url format * @pre `finalizer_key` must not be active, unless it is the last registered finalizer key * @pre Authority of `finalizer_name` */ From d5510f1e5589c111e1c9b2757225340cf0e83c0a Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 5 Apr 2024 18:06:46 -0400 Subject: [PATCH 64/94] Rename active_key_id to active_finalizer_key_id, active_key to active_finalizer_key_binary, and num_registered_keys to finalizer_key_count in finalizers table --- .../include/eosio.system/eosio.system.hpp | 6 +- contracts/eosio.system/src/finalizer_key.cpp | 46 ++++++------ contracts/eosio.system/src/voting.cpp | 8 +- tests/eosio.finalizer_key_tests.cpp | 73 ++++++++++--------- 4 files changed, 69 insertions(+), 64 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 893d94fb..2b94abd5 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -304,9 +304,9 @@ namespace eosiosystem { struct [[eosio::table("finalizers"), eosio::contract("eosio.system")]] finalizer_info { name finalizer_name; - uint64_t active_key_id; - std::vector active_key; // Affine little endian non-montgomery g1 - uint32_t num_registered_keys; + uint64_t active_finalizer_key_id; // finalizer's active finalizer_key_id + std::vector active_finalizer_key_binary; // Affine little endian non-montgomery g1 + uint32_t finalizer_key_count; // number of finalizer keys registered by this finalizer uint64_t primary_key() const { return finalizer_name.value; } }; diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index e7d16a69..7928b4e0 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -27,7 +27,7 @@ namespace eosiosystem { // If a producer is found in finalizers_table, it means it has at least one finalizer // key registered, and has an active key if( finalizer != _finalizers.end() ) { - assert( !finalizer->active_key.empty() ); + assert( !finalizer->active_finalizer_key_binary.empty() ); // builds up producer_authority top_producers.emplace_back( @@ -39,12 +39,12 @@ namespace eosiosystem { ); // builds up finalizer_authorities - new_finalizer_key_ids.emplace_back(finalizer->active_key_id); + new_finalizer_key_ids.emplace_back(finalizer->active_finalizer_key_id); finalizer_authorities.emplace_back( eosio::finalizer_authority{ .description = it->owner.to_string(), .weight = 1, - .public_key = finalizer->active_key + .public_key = finalizer->active_finalizer_key_binary } ); } @@ -141,15 +141,15 @@ namespace eosiosystem { // First time the finalizer to register a finalier key, // make the key active _finalizers.emplace( finalizer_name, [&]( auto& f ) { - f.finalizer_name = finalizer_name; - f.active_key_id = key_itr->id; - f.active_key = { fin_key_g1.begin(), fin_key_g1.end() }; - f.num_registered_keys = 1; + f.finalizer_name = finalizer_name; + f.active_finalizer_key_id = key_itr->id; + f.active_finalizer_key_binary = { fin_key_g1.begin(), fin_key_g1.end() }; + f.finalizer_key_count = 1; }); } else { - // Update num_registered_keys + // Update finalizer_key_count _finalizers.modify( f_itr, same_payer, [&]( auto& f ) { - ++f.num_registered_keys; + ++f.finalizer_key_count; }); } } @@ -164,7 +164,7 @@ namespace eosiosystem { // Check finalizer has registered keys auto finalizer = _finalizers.find(finalizer_name.value); check( finalizer != _finalizers.end(), "finalizer has not registered any finalizer keys" ); - check( finalizer->num_registered_keys > 0, "num_registered_keys of the finalizer must be greater than one" ); + check( finalizer->finalizer_key_count > 0, "finalizer_key_count of the finalizer must be greater than one" ); // Basic format check check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key must start with PUB_BLS"); @@ -180,18 +180,18 @@ namespace eosiosystem { check(fin_key->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer"); // Check if the finalizer key is not already active - check( fin_key->id != finalizer->active_key_id, "the finalizer key was already active" ); + check( fin_key->id != finalizer->active_finalizer_key_id, "the finalizer key was already active" ); - auto old_active_key_id = finalizer->active_key_id; + auto old_active_finalizer_key_id = finalizer->active_finalizer_key_id; _finalizers.modify( finalizer, same_payer, [&]( auto& f ) { - f.active_key_id = fin_key->id; - f.active_key = { fin_key_g1.begin(), fin_key_g1.end() }; + f.active_finalizer_key_id = fin_key->id; + f.active_finalizer_key_binary = { fin_key_g1.begin(), fin_key_g1.end() }; }); // Replace the finalizer policy immediately if the finalizer is // participating in current voting - const auto old_id_itr = _last_finkey_ids.find(old_active_key_id); + const auto old_id_itr = _last_finkey_ids.find(old_active_finalizer_key_id); if( old_id_itr != _last_finkey_ids.end() ) { replace_key_in_finalizer_policy(finalizer_name, old_id_itr, fin_key->id); } @@ -242,7 +242,7 @@ namespace eosiosystem { // Check finalizer has registered keys auto finalizer = _finalizers.find(finalizer_name.value); check( finalizer != _finalizers.end(), "finalizer has not registered any finalizer keys" ); - assert( finalizer->num_registered_keys > 0 ); + assert( finalizer->finalizer_key_count > 0 ); // Check the key is registered auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); @@ -250,24 +250,26 @@ namespace eosiosystem { auto fin_key = idx.find(hash); check(fin_key != idx.end(), "finalizer key was not registered"); - // Check the key belongs to finalizer + // Check the key belongs to the finalizer check(fin_key->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer"); - if( fin_key->id == finalizer->active_key_id ) { - check( finalizer->num_registered_keys == 1, "cannot delete an active key unless it is the last registered finalizer key"); + // If the key is currently active, it cannot be deleted unless it is the + // only key of the finalizer. + if( fin_key->id == finalizer->active_finalizer_key_id ) { + check( finalizer->finalizer_key_count == 1, "cannot delete an active key unless it is the last registered finalizer key"); } // Remove the key from finalizer_keys table idx.erase( fin_key ); // Update finalizers table - if( finalizer->num_registered_keys == 1 ) { + if( finalizer->finalizer_key_count == 1 ) { // The finalizer does not have any registered keys. Remove it from finalizers table. _finalizers.erase( finalizer ); } else { - // Decrement num_registered_keys finalizers table + // Decrement finalizer_key_count finalizers table _finalizers.modify( finalizer, same_payer, [&]( auto& f ) { - --f.num_registered_keys; + --f.finalizer_key_count; }); } } diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index 9536ec19..fadae4f0 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -127,13 +127,13 @@ namespace eosiosystem { continue; } - if( _last_finkey_ids.find(finalizer->active_key_id) == _last_finkey_ids.end() ) { + if( _last_finkey_ids.find(finalizer->active_finalizer_key_id) == _last_finkey_ids.end() ) { // If any producer's active finalizer_key_id is not in // last_finalizer_key_ids, it means a new finalizer policy is needed. - new_finalizer_key_ids.emplace_back(finalizer->active_key_id); + new_finalizer_key_ids.emplace_back(finalizer->active_finalizer_key_id); } else { // the active_key is the same as last round for the producer - kept_finalizer_key_ids.insert(finalizer->active_key_id); + kept_finalizer_key_ids.insert(finalizer->active_finalizer_key_id); } // Pre-build next_finalizer_authorities in case it is needed. @@ -141,7 +141,7 @@ namespace eosiosystem { eosio::finalizer_authority{ .description = it->owner.to_string(), .weight = 1, - .public_key = finalizer->active_key + .public_key = finalizer->active_finalizer_key_binary } ); } diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 108bf545..2a1424a9 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -174,11 +174,11 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_same_finalizer_tests, finalize auto fin_info = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); - BOOST_REQUIRE_EQUAL( 1, fin_info["num_registered_keys"].as_uint64() ); - uint64_t active_key_id = fin_info["active_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( 1, fin_info["finalizer_key_count"].as_uint64() ); + uint64_t active_finalizer_key_id = fin_info["active_finalizer_key_id"].as_uint64(); // Cross check finalizer keys table - auto fin_key_info = get_finalizer_key_info(active_key_id); + auto fin_key_info = get_finalizer_key_info(active_finalizer_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", fin_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_1, fin_key_info["finalizer_key"].as_string() ); @@ -186,8 +186,8 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_same_finalizer_tests, finalize BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_2, pop_2 )); auto fin_info2 = get_finalizer_info(alice); - BOOST_REQUIRE_EQUAL( 2, fin_info2["num_registered_keys"].as_uint64() ); // count incremented by 1 - BOOST_REQUIRE_EQUAL( active_key_id, fin_info2["active_key_id"].as_uint64() ); // active key should not change + BOOST_REQUIRE_EQUAL( 2, fin_info2["finalizer_key_count"].as_uint64() ); // count incremented by 1 + BOOST_REQUIRE_EQUAL( active_finalizer_key_id, fin_info2["active_finalizer_key_id"].as_uint64() ); // active key should not change } FC_LOG_AND_RETHROW() // register_finalizer_key_by_same_finalizer_tests @@ -199,7 +199,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_duplicate_key_tests, finalizer_ke auto fin_info = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); - BOOST_REQUIRE_EQUAL( 1, fin_info["num_registered_keys"].as_uint64() ); + BOOST_REQUIRE_EQUAL( 1, fin_info["finalizer_key_count"].as_uint64() ); // Same finalizer key as the first one BOOST_REQUIRE_EQUAL( wasm_assert_msg( "duplicate finalizer key" ), @@ -217,13 +217,13 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_different_finalizers_tests, fi auto fin_info = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); - BOOST_REQUIRE_EQUAL( 1, fin_info["num_registered_keys"].as_uint64() ); + BOOST_REQUIRE_EQUAL( 1, fin_info["finalizer_key_count"].as_uint64() ); // bob111111111 registers another finalizer key BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop_2) ); auto fin_info2 = get_finalizer_info(bob); - BOOST_REQUIRE_EQUAL( 1, fin_info2["num_registered_keys"].as_uint64() ); + BOOST_REQUIRE_EQUAL( 1, fin_info2["finalizer_key_count"].as_uint64() ); } FC_LOG_AND_RETHROW() // register_finalizer_key_by_different_finalizers_tests @@ -237,7 +237,7 @@ BOOST_FIXTURE_TEST_CASE(register_duplicate_key_from_different_finalizers_tests, auto fin_info = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); - BOOST_REQUIRE_EQUAL( 1, fin_info["num_registered_keys"].as_uint64() ); + BOOST_REQUIRE_EQUAL( 1, fin_info["finalizer_key_count"].as_uint64() ); // bob111111111 tries to register the same finalizer key as the first one BOOST_REQUIRE_EQUAL( wasm_assert_msg( "duplicate finalizer key" ), @@ -287,8 +287,8 @@ BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_success_tests, finalizer_key_test // Check finalizer_key_1 is the active key auto alice_info = get_finalizer_info(alice); - uint64_t active_key_id = alice_info["active_key_id"].as_uint64(); - auto finalizer_key_info = get_finalizer_key_info(active_key_id); + uint64_t active_finalizer_key_id = alice_info["active_finalizer_key_id"].as_uint64(); + auto finalizer_key_info = get_finalizer_key_info(active_finalizer_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_1, finalizer_key_info["finalizer_key"].as_string() ); @@ -297,8 +297,8 @@ BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_success_tests, finalizer_key_test // Check finalizer_key_2 is the active key alice_info = get_finalizer_info(alice); - active_key_id = alice_info["active_key_id"].as_uint64(); - finalizer_key_info = get_finalizer_key_info(active_key_id); + active_finalizer_key_id = alice_info["active_finalizer_key_id"].as_uint64(); + finalizer_key_info = get_finalizer_key_info(active_finalizer_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_2, finalizer_key_info["finalizer_key"].as_string() ); } @@ -347,10 +347,10 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_success_test, finalizer_key_tester) // Check finalizer_key_1 is the active key auto alice_info = get_finalizer_info(alice); - uint64_t active_key_id = alice_info["active_key_id"].as_uint64(); - auto num_registered_keys_before = alice_info["num_registered_keys"].as_uint64(); + uint64_t active_finalizer_key_id = alice_info["active_finalizer_key_id"].as_uint64(); + auto finalizer_key_count_before = alice_info["finalizer_key_count"].as_uint64(); - auto finalizer_key_info = get_finalizer_key_info(active_key_id); + auto finalizer_key_info = get_finalizer_key_info(active_finalizer_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_1, finalizer_key_info["finalizer_key"].as_string() ); @@ -358,8 +358,8 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_success_test, finalizer_key_tester) BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(alice, finalizer_key_2) ); alice_info = get_finalizer_info(alice); - auto num_registered_keys_after = alice_info["num_registered_keys"].as_uint64(); - BOOST_REQUIRE_EQUAL( num_registered_keys_before - 1, num_registered_keys_after ); + auto finalizer_key_count_after = alice_info["finalizer_key_count"].as_uint64(); + BOOST_REQUIRE_EQUAL( finalizer_key_count_before - 1, finalizer_key_count_after ); } FC_LOG_AND_RETHROW() // delete_finalizer_key_success_test @@ -372,8 +372,8 @@ BOOST_FIXTURE_TEST_CASE(delete_last_finalizer_key_test, finalizer_key_tester) tr // Check finalizer_key_1 is the active key auto alice_info = get_finalizer_info(alice); - uint64_t active_key_id = alice_info["active_key_id"].as_uint64(); - auto finalizer_key_info = get_finalizer_key_info(active_key_id); + uint64_t active_finalizer_key_id = alice_info["active_finalizer_key_id"].as_uint64(); + auto finalizer_key_info = get_finalizer_key_info(active_finalizer_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_1, finalizer_key_info["finalizer_key"].as_string() ); @@ -381,7 +381,7 @@ BOOST_FIXTURE_TEST_CASE(delete_last_finalizer_key_test, finalizer_key_tester) tr BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(alice, finalizer_key_1) ); // Both finalizer_key_1 and alice should be removed from finalizers and finalizer_keys tables - BOOST_REQUIRE_EQUAL( true, get_finalizer_key_info(active_key_id).is_null() ); + BOOST_REQUIRE_EQUAL( true, get_finalizer_key_info(active_finalizer_key_id).is_null() ); BOOST_REQUIRE_EQUAL( true, get_finalizer_info(alice).is_null() ); } FC_LOG_AND_RETHROW() // delete_last_finalizer_key_test @@ -396,8 +396,8 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { // Verify last finalizer key id table contains all finalzer keys for( auto& p : producer_names ) { auto finalizer_info = get_finalizer_info(p); - uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_key_id).is_null() ); + uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_finalizer_key_id).is_null() ); } // Produce enough blocks so transition to Savanna finishes @@ -425,6 +425,7 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_not_enough_finalizer_keys_tests, finalizer_ } FC_LOG_AND_RETHROW() +// Finalizers are not changed in current schedule rounds BOOST_FIXTURE_TEST_CASE(update_elected_producers_no_finalizers_changed_test, finalizer_key_tester) try { auto producer_names = active_and_vote_producers(); register_finalizer_keys(producer_names, 21); @@ -440,8 +441,8 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_no_finalizers_changed_test, fin auto last_finkey_ids = get_last_finkey_ids(); for( auto& p : producer_names ) { auto finalizer_info = get_finalizer_info(p); - uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_key_id) ); + uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_finalizer_key_id) ); } // Produce for one round @@ -453,6 +454,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_no_finalizers_changed_test, fin } FC_LOG_AND_RETHROW() +// An active finalizer activates another key. The change takes effect immediately. BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finalizer_key_tester) try { auto producer_names = active_and_vote_producers(); register_finalizer_keys(producer_names, 21); @@ -468,16 +470,16 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finali auto last_finkey_ids = get_last_finkey_ids(); for( auto& p : producer_names ) { auto finalizer_info = get_finalizer_info(p); - uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_key_id) ); + uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_finalizer_key_id) ); } // Pick a producer name test_producer = producer_names.back(); - // Take a note of old active_key_id + // Take a note of old active_finalizer_key_id auto p_info = get_finalizer_info(test_producer); - uint64_t old_id = p_info["active_key_id"].as_uint64(); + uint64_t old_id = p_info["active_finalizer_key_id"].as_uint64(); // Register and activate a new finalizer key BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(test_producer, finalizer_key_1, pop_1) ); @@ -487,9 +489,9 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finali // immediately. auto last_finkey_ids_2 = get_last_finkey_ids(); - // Take a note of new active_key_id + // Take a note of new active_finalizer_key_id auto p_info_2 = get_finalizer_info(test_producer); - uint64_t new_id = p_info_2["active_key_id"].as_uint64(); + uint64_t new_id = p_info_2["active_finalizer_key_id"].as_uint64(); // After replace the old_id with new_id in last_finkey_ids, // last_finkey_ids should be the same as last_finkey_ids_2 @@ -499,6 +501,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finali } FC_LOG_AND_RETHROW() +// An active finalizer deletes its only key. It is replaced by another finalizer in next round. BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, finalizer_key_tester) try { // creat voters const asset net = core_sym::from_string("80.0000"); @@ -561,15 +564,15 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final auto last_finkey_ids = get_last_finkey_ids(); for( auto i = 0; i < 21; ++i ) { auto finalizer_info = get_finalizer_info(producer_names[i]); - uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_key_id) ); + uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_finalizer_key_id) ); } const auto new_prod_name = producer_names[21]; BOOST_REQUIRE_EQUAL( success(), regproducer(new_prod_name) ); BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(new_prod_name, finalizer_key_1, pop_1) ); auto prod_info = get_finalizer_info(new_prod_name); - uint64_t new_id = prod_info["active_key_id"].as_uint64(); + uint64_t new_id = prod_info["active_finalizer_key_id"].as_uint64(); // Wait for two rounds of producer schedule so new finalizer policy takes effect produce_block( fc::minutes(2) ); @@ -577,7 +580,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // Delete an active finalizer key name deleted_prod_name = producer_names[0]; auto p_info = get_finalizer_info(deleted_prod_name); - uint64_t deleted_id = p_info["active_key_id"].as_uint64(); + uint64_t deleted_id = p_info["active_finalizer_key_id"].as_uint64(); auto k_info = get_finalizer_key_info(deleted_id); auto deleted_key = k_info["finalizer_key"].as_string(); BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(deleted_prod_name, deleted_key) ); From 5584a60f44ee95703627a7eb802007b9f1cccaaa Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 5 Apr 2024 18:13:22 -0400 Subject: [PATCH 65/94] Move static keys and signatures out of finalizer_key_tester --- tests/eosio.finalizer_key_tests.cpp | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 2a1424a9..c47c1403 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -10,15 +10,6 @@ struct key_pair_t { }; struct finalizer_key_tester : eosio_system_tester { - static const std::string finalizer_key_1; - static const std::string finalizer_key_2; - static const std::string finalizer_key_3; - static const std::string finalizer_key_4; - static const std::string pop_1; - static const std::string pop_2; - static const std::string pop_3; - static const std::string pop_4; - static const std::vector key_pair; fc::variant get_finalizer_key_info( uint64_t id ) { @@ -87,15 +78,6 @@ struct finalizer_key_tester : eosio_system_tester { } }; -const std::string finalizer_key_tester::finalizer_key_1 = "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA"; -const std::string finalizer_key_tester::finalizer_key_2 = "PUB_BLS_gtaOjOTa0NzDt8etBDqLoZKlfKTpTalcdfmbTJknLUJB2Fu4Cv-uoa8unF3bJ5kFewaCzf3tjYUyNE6CDSrwvYP5Nw47Y9oE9x4nqJWfJykMOoaI0kJz-GDrGN2nZdUAp5tWEg"; -const std::string finalizer_key_tester::finalizer_key_3 = "PUB_BLS_CT8khvZYYZdObeIV9aTnd8fZ8bdaCL1UpSRyqNLZZM5sdrOSpOjDTAY2drTYGvQPVS21BhtD8acLJhqGyTfjqrWjyY5FTfqLdcligofSpa2lrG3FqKVNeUULR5QgcIMYga4vkQ"; -const std::string finalizer_key_tester::finalizer_key_4 = "PUB_BLS_hJYC9REVk4Pzgt3NMycIaCRpRqTX8IIEAB8xhWg6pOYsV7n9gJnTTUOzPGH8VE4FPhxvzJuvrb5TNeR5MHwIjPMMKVPYHI-dDFwl5Oqj0yH9uoKRcMqjEaFZ5VYX3zMJuA1jQQ"; - -const std::string finalizer_key_tester::pop_1 = "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA"; -const std::string finalizer_key_tester::pop_2 = "SIG_BLS_9e1SzM60bWLdxwz4lYNQMNzMGeFuzFgJDYy7WykmynRVRQeIx2O2xnyzwv1WXvgYHLyMYZ4wK0Y_kU6jl330WazkBsw-_GzvIOGy8fnBnt5AyMaj9X5bhDbvB5MZc0QQz4-P2Z4SltTY17ZItGeekkjX_fgQ9kegM4qnuGU-2iqFj5i3Qf322L77b2SHjFoLmxdFOsfGpz7LyImSP8GcZH39W30cj5bmxfsp_90tGdAkz-7DG9nhSHYxFq6qTqMGijVPGg"; -const std::string finalizer_key_tester::pop_3 = "SIG_BLS_cJTQMGv1isqpcHEfhogLhlU56bKpGgo-Svi3Z4NXvWcly5TJo8hDChodIV-aEHgMqr06LuZftR7WFvgGkbOSdmwdO4t58R3RYOMSK-jjif2z-fEwCl7jsxUutASIRwIYtTI7h6NLCjARiKNi5BkES33xY8wYMWf-JkgbpsD2cGsZW4hkMW7T2j_1w89HmNwCn4V_hjlPM_kgz45RoYpKq4w2QEaLdCYTJ6xYOfc9Occc15c76dd1jjty_yT2RMAKO0mfUA"; -const std::string finalizer_key_tester::pop_4 = "SIG_BLS_GNlwGxjL-LCVDApTHernv8Hj6EqlsxWlZBUzOu6DcJmNNuHsfetXK14RPJ-L63wVnhPRL9aNrQAURy2wYJ1__rNiGk-nUMZ5RDTO7tO2EPTiyySq9cbzgn43vKG8FgsA4gbNlqVFeTCbo5CgGj8m9vXNV4-Cv68WW-ivcwJzDtnNA3O9PPIpRY6_HhbmwTUVrHL2v7X_arNCyAf29nucAYNOsCM-br6F6HwpSjqSxi4-KqcFfQCWbAbn_SgJNVAA4yx5fQ"; const std::vector finalizer_key_tester::key_pair { {"PUB_BLS_9Pbv53DbC9EDGGPEZUrlKuMGeXYWHzIPfmn-Ncrxj7sOTiTEOYIkcCgBrvfKYiIG0BsiafG1dRK9MV40aGWKREE4rWHpiDLIkHR91huq9CEdeZHUb2bRXvcxs0RAa7oADXSTmw", "SIG_BLS_IyjIzDWKzlekYSiRbJmBqYmWoiMsmHX_1aB0Hkqk1woeSJLbtd9D83lMDi6LiMEEpP79rP-AKiJAg1rKHODkt2habnn-y4jFMl76egQOv2KHLjobVzWWj_nz667VxeoF2FwF-NMnX7FQfpPgVRINSDKc5maRADRYQGrnlE-boh_23GBuCaxELnAFD-4L_ZEZRr8B9UIA62Vj9JBS_dExquL3wtlhx7vNq0MAGf9J3_Q69BsTuH_OMH6bs5m2AF4ZqiKpdQ" }, @@ -127,6 +109,16 @@ BOOST_AUTO_TEST_SUITE(eosio_system_finalizer_key_tests) const name alice = "alice1111111"_n; const name bob = "bob111111111"_n; +const std::string finalizer_key_1 = "PUB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA"; +const std::string finalizer_key_2 = "PUB_BLS_gtaOjOTa0NzDt8etBDqLoZKlfKTpTalcdfmbTJknLUJB2Fu4Cv-uoa8unF3bJ5kFewaCzf3tjYUyNE6CDSrwvYP5Nw47Y9oE9x4nqJWfJykMOoaI0kJz-GDrGN2nZdUAp5tWEg"; +const std::string finalizer_key_3 = "PUB_BLS_CT8khvZYYZdObeIV9aTnd8fZ8bdaCL1UpSRyqNLZZM5sdrOSpOjDTAY2drTYGvQPVS21BhtD8acLJhqGyTfjqrWjyY5FTfqLdcligofSpa2lrG3FqKVNeUULR5QgcIMYga4vkQ"; +const std::string finalizer_key_4 = "PUB_BLS_hJYC9REVk4Pzgt3NMycIaCRpRqTX8IIEAB8xhWg6pOYsV7n9gJnTTUOzPGH8VE4FPhxvzJuvrb5TNeR5MHwIjPMMKVPYHI-dDFwl5Oqj0yH9uoKRcMqjEaFZ5VYX3zMJuA1jQQ"; + +const std::string pop_1 = "SIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA"; +const std::string pop_2 = "SIG_BLS_9e1SzM60bWLdxwz4lYNQMNzMGeFuzFgJDYy7WykmynRVRQeIx2O2xnyzwv1WXvgYHLyMYZ4wK0Y_kU6jl330WazkBsw-_GzvIOGy8fnBnt5AyMaj9X5bhDbvB5MZc0QQz4-P2Z4SltTY17ZItGeekkjX_fgQ9kegM4qnuGU-2iqFj5i3Qf322L77b2SHjFoLmxdFOsfGpz7LyImSP8GcZH39W30cj5bmxfsp_90tGdAkz-7DG9nhSHYxFq6qTqMGijVPGg"; +const std::string pop_3 = "SIG_BLS_cJTQMGv1isqpcHEfhogLhlU56bKpGgo-Svi3Z4NXvWcly5TJo8hDChodIV-aEHgMqr06LuZftR7WFvgGkbOSdmwdO4t58R3RYOMSK-jjif2z-fEwCl7jsxUutASIRwIYtTI7h6NLCjARiKNi5BkES33xY8wYMWf-JkgbpsD2cGsZW4hkMW7T2j_1w89HmNwCn4V_hjlPM_kgz45RoYpKq4w2QEaLdCYTJ6xYOfc9Occc15c76dd1jjty_yT2RMAKO0mfUA"; +const std::string pop_4 = "SIG_BLS_GNlwGxjL-LCVDApTHernv8Hj6EqlsxWlZBUzOu6DcJmNNuHsfetXK14RPJ-L63wVnhPRL9aNrQAURy2wYJ1__rNiGk-nUMZ5RDTO7tO2EPTiyySq9cbzgn43vKG8FgsA4gbNlqVFeTCbo5CgGj8m9vXNV4-Cv68WW-ivcwJzDtnNA3O9PPIpRY6_HhbmwTUVrHL2v7X_arNCyAf29nucAYNOsCM-br6F6HwpSjqSxi4-KqcFfQCWbAbn_SgJNVAA4yx5fQ"; + BOOST_FIXTURE_TEST_CASE(register_finalizer_key_invalid_key_tests, finalizer_key_tester) try { { // attempt to register finalizer_key for an unregistered producer BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer is not a registered producer" ), From c0d4a8d339b515dd1ddb169d57d0fc88a9aaeae7 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Sat, 6 Apr 2024 13:29:42 -0400 Subject: [PATCH 66/94] Rename last_finkey_ids with last_fin_keys; add comments to fields of new tables --- .../include/eosio.system/eosio.system.hpp | 35 ++++++++-------- contracts/eosio.system/src/eosio.system.cpp | 2 +- contracts/eosio.system/src/finalizer_key.cpp | 40 +++++++++---------- contracts/eosio.system/src/voting.cpp | 2 +- tests/eosio.finalizer_key_tests.cpp | 6 +-- 5 files changed, 42 insertions(+), 43 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 2b94abd5..51984f2c 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -284,42 +284,41 @@ namespace eosiosystem { EOSLIB_SERIALIZE( producer_info2, (owner)(votepay_share)(last_votepay_share_update) ) }; - // Defines finalizer_key info structure to be stored in finalizer_keys info table, added after version 6.0 + // finalizer_key_info stores information about a finalizer key. struct [[eosio::table("finkeys"), eosio::contract("eosio.system")]] finalizer_key_info { - uint64_t id; - name finalizer_name; - std::string finalizer_key; // base64url - checksum256 finalizer_key_hash; + uint64_t id; // automatically generated ID for the key in the table + name finalizer_name; // name of the finalizer owning the key + std::string finalizer_key; // finalizer key in base64url format + checksum256 finalizer_key_hash; // hash of finalizer key, cached to avoid re-computing uint64_t primary_key() const { return id; } uint64_t by_fin_name() const { return finalizer_name.value; } checksum256 by_fin_key() const { return finalizer_key_hash; } }; - typedef eosio::multi_index< "finkeys"_n, finalizer_key_info, indexed_by<"byfinname"_n, const_mem_fun>, indexed_by<"byfinkey"_n, const_mem_fun> > finalizer_keys_table; + // finalizer_info stores information about a finalizer. struct [[eosio::table("finalizers"), eosio::contract("eosio.system")]] finalizer_info { - name finalizer_name; - uint64_t active_finalizer_key_id; // finalizer's active finalizer_key_id - std::vector active_finalizer_key_binary; // Affine little endian non-montgomery g1 - uint32_t finalizer_key_count; // number of finalizer keys registered by this finalizer + name finalizer_name; // finalizer's name + uint64_t active_finalizer_key_id; // finalizer's active finalizer key's id in finalizer_keys_table, for fast finding key information + std::vector active_finalizer_key_binary; // finalizer's active finalizer key's binary format in Affine little endian non-montgomery g1 + uint32_t finalizer_key_count = 0; // number of finalizer keys registered by this finalizer uint64_t primary_key() const { return finalizer_name.value; } }; - typedef eosio::multi_index< "finalizers"_n, finalizer_info > finalizers_table; - struct [[eosio::table("lastfkeyids"), eosio::contract("eosio.system")]] last_finkey_id_info { - uint64_t key_id; + // last_fin_key_info stores information about a finalizer key used in last finalizer policy. + struct [[eosio::table("lastfinkeys"), eosio::contract("eosio.system")]] last_fin_key_info { + uint64_t id; // finalizer key's id in finalizer_keys_table - uint64_t primary_key() const { return key_id; } + uint64_t primary_key() const { return id; } }; - - typedef eosio::multi_index< "lastfkeyids"_n, last_finkey_id_info > last_finkey_ids_table; + typedef eosio::multi_index< "lastfinkeys"_n, last_fin_key_info > last_fin_keys_table; // Voter info. Voter info stores information about the voter: // - `owner` the voter @@ -722,7 +721,7 @@ namespace eosiosystem { producers_table2 _producers2; finalizer_keys_table _finalizer_keys; finalizers_table _finalizers; - last_finkey_ids_table _last_finkey_ids; + last_fin_keys_table _last_fin_keys; global_state_singleton _global; global_state2_singleton _global2; global_state3_singleton _global3; @@ -1614,7 +1613,7 @@ namespace eosiosystem { // defined in finalizer_key.cpp bool is_savanna_consensus() const; void set_finalizers( std::vector&& finalizer_authorities, const std::vector& finalizer_key_ids, const std::unordered_set& kept_key_ids ); - void replace_key_in_finalizer_policy(const name& finalizer, const last_finkey_ids_table::const_iterator& old_id_itr, uint64_t new_id); + void replace_key_in_finalizer_policy(const name& finalizer, const last_fin_keys_table::const_iterator& old_id_itr, uint64_t new_id); template class registration { diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index 13215983..b4bfad6a 100644 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -22,7 +22,7 @@ namespace eosiosystem { _producers2(get_self(), get_self().value), _finalizer_keys(get_self(), get_self().value), _finalizers(get_self(), get_self().value), - _last_finkey_ids(get_self(), get_self().value), + _last_fin_keys(get_self(), get_self().value), _global(get_self(), get_self().value), _global2(get_self(), get_self().value), _global3(get_self(), get_self().value), diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 7928b4e0..d76f4942 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -72,10 +72,10 @@ namespace eosiosystem { } bool system_contract::is_savanna_consensus() const { - return _last_finkey_ids.begin() != _last_finkey_ids.end(); + return _last_fin_keys.begin() != _last_fin_keys.end(); } - void system_contract::set_finalizers( std::vector&& finalizer_authorities, const std::vector& new_key_ids, const std::unordered_set& kept_key_ids ) { + void system_contract::set_finalizers( std::vector&& finalizer_authorities, const std::vector& new_ids, const std::unordered_set& kept_ids ) { // Establish finalizer policy and call set_finalizers() host function eosio::finalizer_policy fin_policy { .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, // or hardcoded to 15? @@ -83,19 +83,19 @@ namespace eosiosystem { }; eosio::set_finalizers(std::move(fin_policy)); // call host function - // Purge any ids not in kept_key_ids from last_finkey_ids table - for (auto itr = _last_finkey_ids.begin(); itr != _last_finkey_ids.end(); /* intentionally empty */ ) { - if( !kept_key_ids.contains(itr->key_id) ) { - itr = _last_finkey_ids.erase(itr); + // Purge any ids not in kept_ids from _last_fin_keys table + for (auto itr = _last_fin_keys.begin(); itr != _last_fin_keys.end(); /* intentionally empty */ ) { + if( !kept_ids.contains(itr->id) ) { + itr = _last_fin_keys.erase(itr); } else { ++itr; } } - // Add new_key_ids to _last_finkey_ids - for (auto id: new_key_ids ) { - _last_finkey_ids.emplace( get_self(), [&]( auto& f ) { - f.key_id = id; + // Add new_ids to _last_fin_keys + for (auto id: new_ids ) { + _last_fin_keys.emplace( get_self(), [&]( auto& f ) { + f.id = id; }); } } @@ -191,28 +191,28 @@ namespace eosiosystem { // Replace the finalizer policy immediately if the finalizer is // participating in current voting - const auto old_id_itr = _last_finkey_ids.find(old_active_finalizer_key_id); - if( old_id_itr != _last_finkey_ids.end() ) { + const auto old_id_itr = _last_fin_keys.find(old_active_finalizer_key_id); + if( old_id_itr != _last_fin_keys.end() ) { replace_key_in_finalizer_policy(finalizer_name, old_id_itr, fin_key->id); } } // replace the key in last finalizer policy and call set_finalizers host function immediately - void system_contract::replace_key_in_finalizer_policy(const name& finalizer, const last_finkey_ids_table::const_iterator& old_id_itr, uint64_t new_id) { + void system_contract::replace_key_in_finalizer_policy(const name& finalizer, const last_fin_keys_table::const_iterator& old_id_itr, uint64_t new_id) { // Delete old id assert(old_id_itr); - _last_finkey_ids.erase(old_id_itr); + _last_fin_keys.erase(old_id_itr); // Insert new ID - _last_finkey_ids.emplace( get_self(), [&]( auto& f ) { - f.key_id = new_id; + _last_fin_keys.emplace( get_self(), [&]( auto& f ) { + f.id = new_id; }); std::vector finalizer_authorities; - // Build a new finalizer_authority by going over all last_finkey_ids - for (auto itr = _last_finkey_ids.begin(); itr != _last_finkey_ids.end(); ++itr) { - auto key = _finalizer_keys.find(itr->key_id); + // Build a new finalizer_authority by going over all keys in _last_fin_keys table + for (auto itr = _last_fin_keys.begin(); itr != _last_fin_keys.end(); ++itr) { + auto key = _finalizer_keys.find(itr->id); assert( key != _finalizer_keys.end() ); const auto pk = eosio::decode_bls_public_key_to_g1(key->finalizer_key); finalizer_authorities.emplace_back( @@ -224,7 +224,7 @@ namespace eosiosystem { ); } - // last_finkey_ids table has already been updated. Call set_finalizers host function directly + // _last_fin_keys table has already been updated. Call set_finalizers host function directly eosio::finalizer_policy fin_policy { .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, .finalizers = std::move(finalizer_authorities) diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index fadae4f0..35728c36 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -127,7 +127,7 @@ namespace eosiosystem { continue; } - if( _last_finkey_ids.find(finalizer->active_finalizer_key_id) == _last_finkey_ids.end() ) { + if( _last_fin_keys.find(finalizer->active_finalizer_key_id) == _last_fin_keys.end() ) { // If any producer's active finalizer_key_id is not in // last_finalizer_key_ids, it means a new finalizer policy is needed. new_finalizer_key_ids.emplace_back(finalizer->active_finalizer_key_id); diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index c47c1403..89470837 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -23,8 +23,8 @@ struct finalizer_key_tester : eosio_system_tester { } fc::variant get_last_finkey_id_info( uint64_t id ) { - vector data = get_row_by_id( config::system_account_name, config::system_account_name, "lastfkeyids"_n, id ); - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "last_finkey_id_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); + vector data = get_row_by_id( config::system_account_name, config::system_account_name, "lastfinkeys"_n, id ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "last_fin_key_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } action_result register_finalizer_key( const account_name& act, const std::string& finalizer_key, const std::string& pop ) { @@ -60,7 +60,7 @@ struct finalizer_key_tester : eosio_system_tester { std::unordered_set get_last_finkey_ids() { const auto* table_id_itr = control->db().find( - boost::make_tuple(config::system_account_name, config::system_account_name, "lastfkeyids"_n)); + boost::make_tuple(config::system_account_name, config::system_account_name, "lastfinkeys"_n)); if (!table_id_itr) { return {}; From 3ea54b183eaa9ed6b1e8772778966a49f2fdc413 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Sat, 6 Apr 2024 14:00:50 -0400 Subject: [PATCH 67/94] refactor replace_key_in_finalizer_policy() into generate_finalizer_policy_and_set_finalizers() --- .../include/eosio.system/eosio.system.hpp | 2 +- contracts/eosio.system/src/finalizer_key.cpp | 36 ++++++++++--------- contracts/eosio.system/src/voting.cpp | 5 +++ 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 51984f2c..22012526 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1613,7 +1613,7 @@ namespace eosiosystem { // defined in finalizer_key.cpp bool is_savanna_consensus() const; void set_finalizers( std::vector&& finalizer_authorities, const std::vector& finalizer_key_ids, const std::unordered_set& kept_key_ids ); - void replace_key_in_finalizer_policy(const name& finalizer, const last_fin_keys_table::const_iterator& old_id_itr, uint64_t new_id); + void generate_finalizer_policy_and_set_finalizers(); template class registration { diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index d76f4942..5e986551 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -75,10 +75,12 @@ namespace eosiosystem { return _last_fin_keys.begin() != _last_fin_keys.end(); } + // This method can never fail, as it may be called by update_elected_producers, + // and in turn by onblock void system_contract::set_finalizers( std::vector&& finalizer_authorities, const std::vector& new_ids, const std::unordered_set& kept_ids ) { // Establish finalizer policy and call set_finalizers() host function eosio::finalizer_policy fin_policy { - .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, // or hardcoded to 15? + .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, .finalizers = std::move(finalizer_authorities) }; eosio::set_finalizers(std::move(fin_policy)); // call host function @@ -191,23 +193,23 @@ namespace eosiosystem { // Replace the finalizer policy immediately if the finalizer is // participating in current voting - const auto old_id_itr = _last_fin_keys.find(old_active_finalizer_key_id); - if( old_id_itr != _last_fin_keys.end() ) { - replace_key_in_finalizer_policy(finalizer_name, old_id_itr, fin_key->id); - } - } + const auto old_key_itr = _last_fin_keys.find(old_active_finalizer_key_id); + if( old_key_itr != _last_fin_keys.end() ) { + // Delete old key + _last_fin_keys.erase(old_key_itr); - // replace the key in last finalizer policy and call set_finalizers host function immediately - void system_contract::replace_key_in_finalizer_policy(const name& finalizer, const last_fin_keys_table::const_iterator& old_id_itr, uint64_t new_id) { - // Delete old id - assert(old_id_itr); - _last_fin_keys.erase(old_id_itr); + // Insert new key + _last_fin_keys.emplace( get_self(), [&]( auto& f ) { + f.id = fin_key->id; // new active finalizer key id + }); - // Insert new ID - _last_fin_keys.emplace( get_self(), [&]( auto& f ) { - f.id = new_id; - }); + generate_finalizer_policy_and_set_finalizers(); + } + } + // Generate a new finalizer policy from keys in _last_fin_keys table and + // call set_finalizers host function immediately + void system_contract::generate_finalizer_policy_and_set_finalizers() { std::vector finalizer_authorities; // Build a new finalizer_authority by going over all keys in _last_fin_keys table @@ -224,7 +226,7 @@ namespace eosiosystem { ); } - // _last_fin_keys table has already been updated. Call set_finalizers host function directly + // _last_fin_keys table up to date. Call set_finalizers host function directly eosio::finalizer_policy fin_policy { .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, .finalizers = std::move(finalizer_authorities) @@ -244,6 +246,8 @@ namespace eosiosystem { check( finalizer != _finalizers.end(), "finalizer has not registered any finalizer keys" ); assert( finalizer->finalizer_key_count > 0 ); + check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key must start with PUB_BLS"); + // Check the key is registered auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); auto hash = get_finalizer_key_hash(finalizer_key); diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index 35728c36..f92d7b61 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -127,6 +127,11 @@ namespace eosiosystem { continue; } + // This should never happen. Double check just in case + if( finalizer->active_finalizer_key_binary.empty() ) { + continue; + } + if( _last_fin_keys.find(finalizer->active_finalizer_key_id) == _last_fin_keys.end() ) { // If any producer's active finalizer_key_id is not in // last_finalizer_key_ids, it means a new finalizer policy is needed. From 6bf5dc58e5bfe92817ab8a13e18439b26de1a978 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Sat, 6 Apr 2024 14:33:59 -0400 Subject: [PATCH 68/94] Add authority check tests --- tests/eosio.finalizer_key_tests.cpp | 36 ++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 89470837..ac5d48f1 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -119,7 +119,16 @@ const std::string pop_2 = "SIG_BLS_9e1SzM60bWLdxwz4lYNQMNzMGeFuzFgJDYy7WykmynRVR const std::string pop_3 = "SIG_BLS_cJTQMGv1isqpcHEfhogLhlU56bKpGgo-Svi3Z4NXvWcly5TJo8hDChodIV-aEHgMqr06LuZftR7WFvgGkbOSdmwdO4t58R3RYOMSK-jjif2z-fEwCl7jsxUutASIRwIYtTI7h6NLCjARiKNi5BkES33xY8wYMWf-JkgbpsD2cGsZW4hkMW7T2j_1w89HmNwCn4V_hjlPM_kgz45RoYpKq4w2QEaLdCYTJ6xYOfc9Occc15c76dd1jjty_yT2RMAKO0mfUA"; const std::string pop_4 = "SIG_BLS_GNlwGxjL-LCVDApTHernv8Hj6EqlsxWlZBUzOu6DcJmNNuHsfetXK14RPJ-L63wVnhPRL9aNrQAURy2wYJ1__rNiGk-nUMZ5RDTO7tO2EPTiyySq9cbzgn43vKG8FgsA4gbNlqVFeTCbo5CgGj8m9vXNV4-Cv68WW-ivcwJzDtnNA3O9PPIpRY6_HhbmwTUVrHL2v7X_arNCyAf29nucAYNOsCM-br6F6HwpSjqSxi4-KqcFfQCWbAbn_SgJNVAA4yx5fQ"; -BOOST_FIXTURE_TEST_CASE(register_finalizer_key_invalid_key_tests, finalizer_key_tester) try { +BOOST_FIXTURE_TEST_CASE(register_finalizer_key_failure_tests, finalizer_key_tester) try { + { // bob111111111 does not have Alice's authority + BOOST_REQUIRE_EQUAL( error( "missing authority of bob111111111" ), + push_action(alice, "regfinkey"_n, mvo() + ("finalizer_name", "bob111111111") + ("finalizer_key", finalizer_key_1 ) + ("proof_of_possession", pop_1 ) + ) ); + } + { // attempt to register finalizer_key for an unregistered producer BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer is not a registered producer" ), register_finalizer_key(alice, finalizer_key_1, pop_1)); @@ -128,6 +137,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_invalid_key_tests, finalizer_key_ // Now alice1111111 registers as a producer BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); + { // finalizer key does not start with PUB_BLS BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key must start with PUB_BLS" ), push_action(alice, "regfinkey"_n, mvo() @@ -238,6 +248,13 @@ BOOST_FIXTURE_TEST_CASE(register_duplicate_key_from_different_finalizers_tests, FC_LOG_AND_RETHROW() // register_duplicate_key_from_different_finalizers_tests BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_failure_tests, finalizer_key_tester) try { + // bob111111111 does not have Alice's authority + BOOST_REQUIRE_EQUAL( error( "missing authority of bob111111111" ), + push_action(alice, "actfinkey"_n, mvo() + ("finalizer_name", "bob111111111") + ("finalizer_key", finalizer_key_1 ) + ) ); + // attempt to activate finalizer_key for an unregistered producer BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer is not a registered producer" ), activate_finalizer_key(alice, finalizer_key_1) ); @@ -297,6 +314,13 @@ BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_success_tests, finalizer_key_test FC_LOG_AND_RETHROW() // activate_finalizer_key_success_tests BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_failure_tests, finalizer_key_tester) try { + // bob111111111 does not have Alice's authority + BOOST_REQUIRE_EQUAL( error( "missing authority of bob111111111" ), + push_action(alice, "delfinkey"_n, mvo() + ("finalizer_name", "bob111111111") + ("finalizer_key", finalizer_key_1 ) + ) ); + // attempt to delete finalizer_key for an unregistered producer BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer is not a registered producer" ), delete_finalizer_key(alice, finalizer_key_1) ); @@ -379,9 +403,9 @@ BOOST_FIXTURE_TEST_CASE(delete_last_finalizer_key_test, finalizer_key_tester) tr FC_LOG_AND_RETHROW() // delete_last_finalizer_key_test BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { - // Register and vote 21 producers + // Register and vote 26 producers auto producer_names = active_and_vote_producers(); - // Register 21 finalizer keys + // Register 21 finalizer keys for the first 21 producers register_finalizer_keys(producer_names, 21); BOOST_REQUIRE_EQUAL(success(), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); @@ -405,6 +429,12 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(switchtosvnn_missing_authority_tests, finalizer_key_tester) try { + BOOST_REQUIRE_EQUAL( error( "missing authority of eosio" ), + push_action( alice, "switchtosvnn"_n, mvo()) ); +} +FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE(switchtosvnn_not_enough_finalizer_keys_tests, finalizer_key_tester) try { auto producer_names = active_and_vote_producers(); From c9b156d3f8a5871d7dcc7f4398d51952b76b1f92 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Sat, 6 Apr 2024 21:07:21 -0400 Subject: [PATCH 69/94] Cache finalizer key binary form in finalizers table; improve description of actions; various minor cleanups. --- .../include/eosio.system/eosio.system.hpp | 29 +-- contracts/eosio.system/src/finalizer_key.cpp | 168 ++++++++++-------- tests/eosio.finalizer_key_tests.cpp | 64 ++++--- 3 files changed, 144 insertions(+), 117 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 22012526..db05c29d 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -286,10 +286,11 @@ namespace eosiosystem { // finalizer_key_info stores information about a finalizer key. struct [[eosio::table("finkeys"), eosio::contract("eosio.system")]] finalizer_key_info { - uint64_t id; // automatically generated ID for the key in the table - name finalizer_name; // name of the finalizer owning the key - std::string finalizer_key; // finalizer key in base64url format - checksum256 finalizer_key_hash; // hash of finalizer key, cached to avoid re-computing + uint64_t id; // automatically generated ID for the key in the table + name finalizer_name; // name of the finalizer owning the key + std::string finalizer_key; // finalizer key in base64url format + std::vector finalizer_key_binary; // finalizer key in binary format in Affine little endian non-montgomery g1 + checksum256 finalizer_key_hash; // hash of finalizer key, cached to avoid re-computing uint64_t primary_key() const { return id; } uint64_t by_fin_name() const { return finalizer_name.value; } @@ -1218,17 +1219,17 @@ namespace eosiosystem { * the policy by using `set_finalizers` host function * * @pre Require the authority of the contract itself - * @pre A sufficient number (15) of the top 21 block producers have registered a finalizer key + * @pre A sufficient numner of the top 21 block producers have registered a finalizer key */ [[eosio::action]] void switchtosvnn(); /** * Action to register a finalizer key by a registered producer. + * If this was registered before (and still exists) even + * by other block producers, the registration will fail. * If this is the first registered finalizer key of the producer, * it will also implicitly be marked active. - * If this finalizer key was registered before (and still exists) even - * by other block producers, the registration will fail. * A registered producer can have multiple registered finalizer keys. * * @param finalizer_name - account registering `finalizer_key`, @@ -1237,16 +1238,18 @@ namespace eosiosystem { * * @pre `finalizer_name` must be a registered producer * @pre `finalizer_key` must be in base64url format + * @pre `proof_of_possession` must be a valid of proof of possession signature * @pre Authority of `finalizer_name` to register. `linkauth` may be used to allow a lower authrity to exectute this action. */ [[eosio::action]] void regfinkey( const name& finalizer_name, const std::string& finalizer_key, const std::string& proof_of_possession); /** - * Action to activate a finalizer key. If the block producer is currently - * active (in top 21), then immediately change Finalizer Policy. - * Activating a finalizer key of a block producer implicitly deactivates - * the previously active finalizer key of that block producer. + * Action to activate a finalizer key. If the finalizer is currently an + * active block producer (in top 21), then immediately change Finalizer Policy. + * A finalizer may only have one active finalizer key. Activating a + * finalizer key implicitly deactivates the previously active finalizer + * key of that finalizer. * * @param finalizer_name - account activating `finalizer_key`, * @param finalizer_key - key to be activated. @@ -1259,8 +1262,8 @@ namespace eosiosystem { void actfinkey( const name& finalizer_name, const std::string& finalizer_key ); /** - * Action to delete a finalizer key. The key cannot be active unless - * it is the last registered finalizer key. If it is the last one, + * Action to delete a finalizer key. An active finalizer key may not be deleted + * unless it is the last registered finalizer key. If it is the last one, * it will be deleted. * * @param finalizer_name - account deleting `finalizer_key`, diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 5e986551..e573d2cd 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -4,6 +4,15 @@ namespace eosiosystem { + // Common routines + bool system_contract::is_savanna_consensus() const { + return _last_fin_keys.begin() != _last_fin_keys.end(); + } + + static eosio::checksum256 get_finalizer_key_hash(const std::string& finalizer_key) { + return eosio::sha256(finalizer_key.data(), finalizer_key.size()); + } + // Action to switch to Savanna void system_contract::switchtosvnn() { require_auth(get_self()); @@ -24,30 +33,36 @@ namespace eosiosystem { auto idx = _producers.get_index<"prototalvote"_n>(); for( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active() && i < 30; ++it, ++i ) { auto finalizer = _finalizers.find( it->owner.value ); - // If a producer is found in finalizers_table, it means it has at least one finalizer - // key registered, and has an active key - if( finalizer != _finalizers.end() ) { - assert( !finalizer->active_finalizer_key_binary.empty() ); - - // builds up producer_authority - top_producers.emplace_back( - eosio::producer_authority{ - .producer_name = it->owner, - .authority = it->get_producer_authority() - }, - it->location - ); - - // builds up finalizer_authorities - new_finalizer_key_ids.emplace_back(finalizer->active_finalizer_key_id); - finalizer_authorities.emplace_back( - eosio::finalizer_authority{ - .description = it->owner.to_string(), - .weight = 1, - .public_key = finalizer->active_finalizer_key_binary - } - ); + if( finalizer == _finalizers.end() ) { + // The producer is not in finalizers table, indicating it does not have an + // active registered finalizer key. Try next one. + continue; + } + + // This should never happen. Double check the finalizer has an active key just in case + if( finalizer->active_finalizer_key_binary.empty() ) { + continue; } + + // builds up producer_authority + top_producers.emplace_back( + eosio::producer_authority{ + .producer_name = it->owner, + .authority = it->get_producer_authority() + }, + it->location + ); + + // stores finalizer_key_id + new_finalizer_key_ids.emplace_back(finalizer->active_finalizer_key_id); + // builds up finalizer_authorities + finalizer_authorities.emplace_back( + eosio::finalizer_authority{ + .description = it->owner.to_string(), + .weight = 1, + .public_key = finalizer->active_finalizer_key_binary + } + ); } check( top_producers.size() > 0 && top_producers.size() >= _gstate.last_producer_schedule_size, "not enough top producers have registered finalizer keys" ); @@ -63,29 +78,28 @@ namespace eosiosystem { for( auto& item : top_producers ) producers.push_back( std::move(item.first) ); + // Should set_finalizers be called the first before set_proposed_producers + // during transition? + set_finalizers(std::move(finalizer_authorities), new_finalizer_key_ids, {}); + if( set_proposed_producers( producers ) >= 0 ) { _gstate.last_producer_schedule_update = eosio::current_time_point(); _gstate.last_producer_schedule_size = static_cast( producers.size() ); } - - set_finalizers(std::move(finalizer_authorities), new_finalizer_key_ids, {}); } - bool system_contract::is_savanna_consensus() const { - return _last_fin_keys.begin() != _last_fin_keys.end(); - } - - // This method can never fail, as it may be called by update_elected_producers, + // This function may never fail, as it can be called by update_elected_producers, // and in turn by onblock void system_contract::set_finalizers( std::vector&& finalizer_authorities, const std::vector& new_ids, const std::unordered_set& kept_ids ) { - // Establish finalizer policy and call set_finalizers() host function + // Establish finalizer policy eosio::finalizer_policy fin_policy { .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, .finalizers = std::move(finalizer_authorities) }; + // call host function eosio::set_finalizers(std::move(fin_policy)); // call host function - // Purge any ids not in kept_ids from _last_fin_keys table + // Purge any IDs not in kept_ids from _last_fin_keys table for (auto itr = _last_fin_keys.begin(); itr != _last_fin_keys.end(); /* intentionally empty */ ) { if( !kept_ids.contains(itr->id) ) { itr = _last_fin_keys.erase(itr); @@ -94,7 +108,7 @@ namespace eosiosystem { } } - // Add new_ids to _last_fin_keys + // Add IDs in new_ids to _last_fin_keys table for (auto id: new_ids ) { _last_fin_keys.emplace( get_self(), [&]( auto& f ) { f.id = id; @@ -102,10 +116,6 @@ namespace eosiosystem { } } - static eosio::checksum256 get_finalizer_key_hash(const std::string& finalizer_key) { - return eosio::sha256(finalizer_key.data(), finalizer_key.size()); - } - // Action to register a finalizer key void system_contract::regfinkey( const name& finalizer_name, const std::string& finalizer_key, const std::string& proof_of_possession) { require_auth( finalizer_name ); @@ -115,42 +125,45 @@ namespace eosiosystem { // Basic key and signature format check check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key must start with PUB_BLS"); - check(proof_of_possession.compare(0, 7, "SIG_BLS") == 0, "proof of possession siganture must start with SIG_BLS"); - - // Convert to binary form - const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); - const auto signature = eosio::decode_bls_signature_to_g2(proof_of_possession); + check(proof_of_possession.compare(0, 7, "SIG_BLS") == 0, "proof of possession signature must start with SIG_BLS"); // Duplication check across all registered keys auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); auto hash = get_finalizer_key_hash(finalizer_key); check(idx.find(hash) == idx.end(), "duplicate finalizer key"); - // Proof of possession check is expensive, do it at last - check(eosio::bls_pop_verify(fin_key_g1, signature), "proof of possession check failed"); - - // Insert into finalyzer_keys table - auto key_itr = _finalizer_keys.emplace( finalizer_name, [&]( auto& k ) { - k.id = _finalizer_keys.available_primary_key(); - k.finalizer_name = finalizer_name; - k.finalizer_key = finalizer_key; - k.finalizer_key_hash = get_finalizer_key_hash(finalizer_key); + // Convert to binary form. The validity will be checked during conversion. + const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); + const auto pop_g2 = eosio::decode_bls_signature_to_g2(proof_of_possession); + + // Proof of possession check is expensive, do it last + check(eosio::bls_pop_verify(fin_key_g1, pop_g2), "proof of possession check failed"); + + // Insert the finalizer key into finalyzer_keys table + auto fin_key_itr = _finalizer_keys.emplace( finalizer_name, [&]( auto& k ) { + k.id = _finalizer_keys.available_primary_key(); + k.finalizer_name = finalizer_name; + k.finalizer_key = finalizer_key; + k.finalizer_key_binary = { fin_key_g1.begin(), fin_key_g1.end() }; + k.finalizer_key_hash = get_finalizer_key_hash(finalizer_key); }); // Update finalizers table - auto f_itr = _finalizers.find(finalizer_name.value); - if( f_itr == _finalizers.end() ) { + auto fin_itr = _finalizers.find(finalizer_name.value); + if( fin_itr == _finalizers.end() ) { // First time the finalizer to register a finalier key, // make the key active _finalizers.emplace( finalizer_name, [&]( auto& f ) { f.finalizer_name = finalizer_name; - f.active_finalizer_key_id = key_itr->id; + f.active_finalizer_key_id = fin_key_itr->id; f.active_finalizer_key_binary = { fin_key_g1.begin(), fin_key_g1.end() }; f.finalizer_key_count = 1; }); } else { // Update finalizer_key_count - _finalizers.modify( f_itr, same_payer, [&]( auto& f ) { + _finalizers.modify( fin_itr, same_payer, [&]( auto& f ) { + assert(f.finalizer_name == finalizer_name); + assert(f.finalizer_key_count > 0); ++f.finalizer_key_count; }); } @@ -172,35 +185,34 @@ namespace eosiosystem { check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key must start with PUB_BLS"); // Check the key is registered - const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); auto hash = get_finalizer_key_hash(finalizer_key); - auto fin_key = idx.find(hash); - check(fin_key != idx.end(), "finalizer key was not registered"); + auto fin_key_itr = idx.find(hash); + check(fin_key_itr != idx.end(), "finalizer key was not registered"); // Check the key belongs to finalizer - check(fin_key->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer"); + check(fin_key_itr->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer"); // Check if the finalizer key is not already active - check( fin_key->id != finalizer->active_finalizer_key_id, "the finalizer key was already active" ); + check( fin_key_itr->id != finalizer->active_finalizer_key_id, "the finalizer key was already active" ); auto old_active_finalizer_key_id = finalizer->active_finalizer_key_id; _finalizers.modify( finalizer, same_payer, [&]( auto& f ) { - f.active_finalizer_key_id = fin_key->id; - f.active_finalizer_key_binary = { fin_key_g1.begin(), fin_key_g1.end() }; + f.active_finalizer_key_id = fin_key_itr->id; + f.active_finalizer_key_binary = fin_key_itr->finalizer_key_binary; }); - // Replace the finalizer policy immediately if the finalizer is - // participating in current voting + // Replace the finalizer policy immediately if the finalizer key is + // used in last finalizer policy const auto old_key_itr = _last_fin_keys.find(old_active_finalizer_key_id); if( old_key_itr != _last_fin_keys.end() ) { // Delete old key _last_fin_keys.erase(old_key_itr); - // Insert new key + // Replace the old key with finalizer key just activated _last_fin_keys.emplace( get_self(), [&]( auto& f ) { - f.id = fin_key->id; // new active finalizer key id + f.id = fin_key_itr->id; // new active finalizer key id }); generate_finalizer_policy_and_set_finalizers(); @@ -214,24 +226,24 @@ namespace eosiosystem { // Build a new finalizer_authority by going over all keys in _last_fin_keys table for (auto itr = _last_fin_keys.begin(); itr != _last_fin_keys.end(); ++itr) { - auto key = _finalizer_keys.find(itr->id); - assert( key != _finalizer_keys.end() ); - const auto pk = eosio::decode_bls_public_key_to_g1(key->finalizer_key); + auto fin_key_itr = _finalizer_keys.find(itr->id); + assert( fin_key_itr != _finalizer_keys.end() ); finalizer_authorities.emplace_back( eosio::finalizer_authority{ - .description = key->finalizer_name.to_string(), + .description = fin_key_itr->finalizer_name.to_string(), .weight = 1, - .public_key = { pk.begin(), pk.end() } + .public_key = fin_key_itr->finalizer_key_binary } ); } - // _last_fin_keys table up to date. Call set_finalizers host function directly eosio::finalizer_policy fin_policy { .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, .finalizers = std::move(finalizer_authorities) }; - eosio::set_finalizers(std::move(fin_policy)); // call host function + + // _last_fin_keys table is up to date. Call set_finalizers host function directly + eosio::set_finalizers(std::move(fin_policy)); } // Action to delete a registered finalizer key @@ -251,20 +263,20 @@ namespace eosiosystem { // Check the key is registered auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); auto hash = get_finalizer_key_hash(finalizer_key); - auto fin_key = idx.find(hash); - check(fin_key != idx.end(), "finalizer key was not registered"); + auto fin_key_itr = idx.find(hash); + check(fin_key_itr != idx.end(), "finalizer key was not registered"); // Check the key belongs to the finalizer - check(fin_key->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer"); + check(fin_key_itr->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer"); // If the key is currently active, it cannot be deleted unless it is the // only key of the finalizer. - if( fin_key->id == finalizer->active_finalizer_key_id ) { + if( fin_key_itr->id == finalizer->active_finalizer_key_id ) { check( finalizer->finalizer_key_count == 1, "cannot delete an active key unless it is the last registered finalizer key"); } // Remove the key from finalizer_keys table - idx.erase( fin_key ); + idx.erase( fin_key_itr ); // Update finalizers table if( finalizer->finalizer_key_count == 1 ) { diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index ac5d48f1..b15b2dbe 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -22,7 +22,7 @@ struct finalizer_key_tester : eosio_system_tester { return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "finalizer_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } - fc::variant get_last_finkey_id_info( uint64_t id ) { + fc::variant get_last_fin_key_info( uint64_t id ) { vector data = get_row_by_id( config::system_account_name, config::system_account_name, "lastfinkeys"_n, id ); return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "last_fin_key_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } @@ -148,7 +148,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_failure_tests, finalizer_key_test } { // proof_of_possession does not start with SIG_BLS - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "proof of possession siganture must start with SIG_BLS" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "proof of possession signature must start with SIG_BLS" ), push_action(alice, "regfinkey"_n, mvo() ("finalizer_name", "alice1111111") ("finalizer_key", finalizer_key_1) @@ -171,25 +171,25 @@ FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_same_finalizer_tests, finalizer_key_tester) try { BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); - // First finalizer key + // Register first finalizer key BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop_1) ); - auto fin_info = get_finalizer_info(alice); - BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); - BOOST_REQUIRE_EQUAL( 1, fin_info["finalizer_key_count"].as_uint64() ); - uint64_t active_finalizer_key_id = fin_info["active_finalizer_key_id"].as_uint64(); + auto alice_info = get_finalizer_info(alice); + BOOST_REQUIRE_EQUAL( "alice1111111", alice_info["finalizer_name"].as_string() ); + BOOST_REQUIRE_EQUAL( 1, alice_info["finalizer_key_count"].as_uint64() ); + uint64_t active_finalizer_key_id = alice_info["active_finalizer_key_id"].as_uint64(); // Cross check finalizer keys table auto fin_key_info = get_finalizer_key_info(active_finalizer_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", fin_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_1, fin_key_info["finalizer_key"].as_string() ); - // Second finalizer key + // Register second finalizer key BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_2, pop_2 )); - auto fin_info2 = get_finalizer_info(alice); - BOOST_REQUIRE_EQUAL( 2, fin_info2["finalizer_key_count"].as_uint64() ); // count incremented by 1 - BOOST_REQUIRE_EQUAL( active_finalizer_key_id, fin_info2["active_finalizer_key_id"].as_uint64() ); // active key should not change + alice_info = get_finalizer_info(alice); + BOOST_REQUIRE_EQUAL( 2, alice_info["finalizer_key_count"].as_uint64() ); // count incremented by 1 + BOOST_REQUIRE_EQUAL( active_finalizer_key_id, alice_info["active_finalizer_key_id"].as_uint64() ); // active key should not change } FC_LOG_AND_RETHROW() // register_finalizer_key_by_same_finalizer_tests @@ -199,13 +199,17 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_duplicate_key_tests, finalizer_ke // The first finalizer key BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop_1) ); - auto fin_info = get_finalizer_info(alice); - BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); - BOOST_REQUIRE_EQUAL( 1, fin_info["finalizer_key_count"].as_uint64() ); + auto alice_info = get_finalizer_info(alice); + BOOST_REQUIRE_EQUAL( "alice1111111", alice_info["finalizer_name"].as_string() ); + BOOST_REQUIRE_EQUAL( 1, alice_info["finalizer_key_count"].as_uint64() ); - // Same finalizer key as the first one + // Tries to register the same finalizer key BOOST_REQUIRE_EQUAL( wasm_assert_msg( "duplicate finalizer key" ), register_finalizer_key(alice, finalizer_key_1, pop_1) ); + + // finalizer key count still 1 + alice_info = get_finalizer_info(alice); + BOOST_REQUIRE_EQUAL( 1, alice_info["finalizer_key_count"].as_uint64() ); } FC_LOG_AND_RETHROW() // register_finalizer_key_duplicate_key_tests @@ -216,16 +220,18 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_different_finalizers_tests, fi // alice1111111 registers a finalizer key BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop_1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_2, pop_2) ); - auto fin_info = get_finalizer_info(alice); - BOOST_REQUIRE_EQUAL( "alice1111111", fin_info["finalizer_name"].as_string() ); - BOOST_REQUIRE_EQUAL( 1, fin_info["finalizer_key_count"].as_uint64() ); + auto alice_info = get_finalizer_info(alice); + BOOST_REQUIRE_EQUAL( "alice1111111", alice_info["finalizer_name"].as_string() ); + BOOST_REQUIRE_EQUAL( 2, alice_info["finalizer_key_count"].as_uint64() ); // bob111111111 registers another finalizer key - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop_2) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_3, pop_3) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_4, pop_4) ); - auto fin_info2 = get_finalizer_info(bob); - BOOST_REQUIRE_EQUAL( 1, fin_info2["finalizer_key_count"].as_uint64() ); + auto bob_info = get_finalizer_info(bob); + BOOST_REQUIRE_EQUAL( 2, bob_info["finalizer_key_count"].as_uint64() ); } FC_LOG_AND_RETHROW() // register_finalizer_key_by_different_finalizers_tests @@ -338,15 +344,22 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_failure_tests, finalizer_key_tester BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop_2) ); BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_3, pop_3) ); - // Delete a finalizer key not registered by anyone + // Alice tries to delete a finalizer key not registered by anyone BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered" ), delete_finalizer_key(alice, finalizer_key_4) ); - // Delete a finalizer key not registered by Alice + // Alice tries to delete a finalizer key registered by Bob BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered by the finalizer" ), delete_finalizer_key(alice, finalizer_key_2) ); - // Delete a finalizer key whose finalizer has more than one key and the key is active + // Make sure finalizer_key_2 is Bob's active finalizer key and Bob has 2 keys + auto bob_info = get_finalizer_info(bob); + uint64_t active_finalizer_key_id = bob_info["active_finalizer_key_id"].as_uint64(); + auto finalizer_key_info = get_finalizer_key_info(active_finalizer_key_id); + BOOST_REQUIRE_EQUAL( finalizer_key_2, finalizer_key_info["finalizer_key"].as_string() ); + BOOST_REQUIRE_EQUAL( 2, bob_info["finalizer_key_count"].as_uint64() ); + + // Bob tries to delete his active finalizer key but he has 2 keys BOOST_REQUIRE_EQUAL( wasm_assert_msg( "cannot delete an active key unless it is the last registered finalizer key" ), delete_finalizer_key(bob, finalizer_key_2) ); @@ -365,7 +378,6 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_success_test, finalizer_key_tester) auto alice_info = get_finalizer_info(alice); uint64_t active_finalizer_key_id = alice_info["active_finalizer_key_id"].as_uint64(); auto finalizer_key_count_before = alice_info["finalizer_key_count"].as_uint64(); - auto finalizer_key_info = get_finalizer_key_info(active_finalizer_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_1, finalizer_key_info["finalizer_key"].as_string() ); @@ -413,7 +425,7 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { for( auto& p : producer_names ) { auto finalizer_info = get_finalizer_info(p); uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( false, get_last_finkey_id_info(active_finalizer_key_id).is_null() ); + BOOST_REQUIRE_EQUAL( false, get_last_fin_key_info(active_finalizer_key_id).is_null() ); } // Produce enough blocks so transition to Savanna finishes From a2b44f4eec1dec1b30fe4f283769146c15657e20 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Sun, 7 Apr 2024 21:18:45 -0400 Subject: [PATCH 70/94] Simplilfy the update_elected_producers test and small clean ups --- contracts/eosio.system/src/finalizer_key.cpp | 102 ++++++++++++------- tests/eosio.finalizer_key_tests.cpp | 77 +++++--------- tests/eosio.system_tester.hpp | 6 +- 3 files changed, 93 insertions(+), 92 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index e573d2cd..3c940ed2 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -4,16 +4,23 @@ namespace eosiosystem { - // Common routines + // Returns true if nodeos has transitioned to Savanna (last finalizer set not empty) bool system_contract::is_savanna_consensus() const { return _last_fin_keys.begin() != _last_fin_keys.end(); } + // Rteurns hash of finalizer_key static eosio::checksum256 get_finalizer_key_hash(const std::string& finalizer_key) { return eosio::sha256(finalizer_key.data(), finalizer_key.size()); } - // Action to switch to Savanna + /** + * Action to switch to Savanna + * + * @pre Require the authority of the contract itself + * @pre A sufficient numner of the top 21 block producers have registered a finalizer key + * @post is_savanna_consensus returns true + */ void system_contract::switchtosvnn() { require_auth(get_self()); @@ -22,10 +29,10 @@ namespace eosiosystem { using value_type = std::pair; std::vector top_producers; std::vector finalizer_authorities; - std::vector new_finalizer_key_ids; + std::vector first_finalizer_key_set; top_producers.reserve(21); finalizer_authorities.reserve(21); - new_finalizer_key_ids.reserve(21); + first_finalizer_key_set.reserve(21); // From up to 30 top producers, find 21 producers that meet all the normal requirements // for being a proposer and also have an active finalizer key @@ -54,11 +61,12 @@ namespace eosiosystem { ); // stores finalizer_key_id - new_finalizer_key_ids.emplace_back(finalizer->active_finalizer_key_id); + first_finalizer_key_set.emplace_back(finalizer->active_finalizer_key_id); + // builds up finalizer_authorities finalizer_authorities.emplace_back( eosio::finalizer_authority{ - .description = it->owner.to_string(), + .description = finalizer->finalizer_name.to_string(), .weight = 1, .public_key = finalizer->active_finalizer_key_binary } @@ -78,9 +86,10 @@ namespace eosiosystem { for( auto& item : top_producers ) producers.push_back( std::move(item.first) ); - // Should set_finalizers be called the first before set_proposed_producers + // Should set_finalizers() be called before set_proposed_producers() // during transition? - set_finalizers(std::move(finalizer_authorities), new_finalizer_key_ids, {}); + set_finalizers(std::move(finalizer_authorities), first_finalizer_key_set, {}); + check( is_savanna_consensus(), "switching to Savanna failed" ); if( set_proposed_producers( producers ) >= 0 ) { _gstate.last_producer_schedule_update = eosio::current_time_point(); @@ -116,7 +125,14 @@ namespace eosiosystem { } } - // Action to register a finalizer key + /* + * Action to register a finalizer key + * + * @pre `finalizer_name` must be a registered producer + * @pre `finalizer_key` must be in base64url format + * @pre `proof_of_possession` must be a valid of proof of possession signature + * @pre Authority of `finalizer_name` to register. `linkauth` may be used to allow a lower authrity to exectute this action. + */ void system_contract::regfinkey( const name& finalizer_name, const std::string& finalizer_key, const std::string& proof_of_possession) { require_auth( finalizer_name ); @@ -140,7 +156,7 @@ namespace eosiosystem { check(eosio::bls_pop_verify(fin_key_g1, pop_g2), "proof of possession check failed"); // Insert the finalizer key into finalyzer_keys table - auto fin_key_itr = _finalizer_keys.emplace( finalizer_name, [&]( auto& k ) { + auto finalizer_key_itr = _finalizer_keys.emplace( finalizer_name, [&]( auto& k ) { k.id = _finalizer_keys.available_primary_key(); k.finalizer_name = finalizer_name; k.finalizer_key = finalizer_key; @@ -149,27 +165,31 @@ namespace eosiosystem { }); // Update finalizers table - auto fin_itr = _finalizers.find(finalizer_name.value); - if( fin_itr == _finalizers.end() ) { - // First time the finalizer to register a finalier key, - // make the key active + auto finalizer = _finalizers.find(finalizer_name.value); + if( finalizer == _finalizers.end() ) { + // This is the first time the finalizer registering a finalizer key, + // mark the key active _finalizers.emplace( finalizer_name, [&]( auto& f ) { f.finalizer_name = finalizer_name; - f.active_finalizer_key_id = fin_key_itr->id; - f.active_finalizer_key_binary = { fin_key_g1.begin(), fin_key_g1.end() }; + f.active_finalizer_key_id = finalizer_key_itr->id; + f.active_finalizer_key_binary = finalizer_key_itr->finalizer_key_binary; f.finalizer_key_count = 1; }); } else { // Update finalizer_key_count - _finalizers.modify( fin_itr, same_payer, [&]( auto& f ) { - assert(f.finalizer_name == finalizer_name); - assert(f.finalizer_key_count > 0); + _finalizers.modify( finalizer, same_payer, [&]( auto& f ) { ++f.finalizer_key_count; }); } } - // Action to activate a finalizer key + /* + * Action to activate a finalizer key + * + * @pre `finalizer_name` must be a registered producer + * @pre `finalizer_key` must be a registered finalizer key in base64url format + * @pre Authority of `finalizer_name` + */ void system_contract::actfinkey( const name& finalizer_name, const std::string& finalizer_key ) { require_auth( finalizer_name ); @@ -179,7 +199,6 @@ namespace eosiosystem { // Check finalizer has registered keys auto finalizer = _finalizers.find(finalizer_name.value); check( finalizer != _finalizers.end(), "finalizer has not registered any finalizer keys" ); - check( finalizer->finalizer_key_count > 0, "finalizer_key_count of the finalizer must be greater than one" ); // Basic format check check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key must start with PUB_BLS"); @@ -187,20 +206,20 @@ namespace eosiosystem { // Check the key is registered auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); auto hash = get_finalizer_key_hash(finalizer_key); - auto fin_key_itr = idx.find(hash); - check(fin_key_itr != idx.end(), "finalizer key was not registered"); + auto finalizer_key_itr = idx.find(hash); + check(finalizer_key_itr != idx.end(), "finalizer key was not registered"); // Check the key belongs to finalizer - check(fin_key_itr->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer"); + check(finalizer_key_itr->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer"); // Check if the finalizer key is not already active - check( fin_key_itr->id != finalizer->active_finalizer_key_id, "the finalizer key was already active" ); + check( finalizer_key_itr->id != finalizer->active_finalizer_key_id, "the finalizer key was already active" ); auto old_active_finalizer_key_id = finalizer->active_finalizer_key_id; _finalizers.modify( finalizer, same_payer, [&]( auto& f ) { - f.active_finalizer_key_id = fin_key_itr->id; - f.active_finalizer_key_binary = fin_key_itr->finalizer_key_binary; + f.active_finalizer_key_id = finalizer_key_itr->id; + f.active_finalizer_key_binary = finalizer_key_itr->finalizer_key_binary; }); // Replace the finalizer policy immediately if the finalizer key is @@ -212,7 +231,7 @@ namespace eosiosystem { // Replace the old key with finalizer key just activated _last_fin_keys.emplace( get_self(), [&]( auto& f ) { - f.id = fin_key_itr->id; // new active finalizer key id + f.id = finalizer_key_itr->id; // new active finalizer key id }); generate_finalizer_policy_and_set_finalizers(); @@ -227,7 +246,7 @@ namespace eosiosystem { // Build a new finalizer_authority by going over all keys in _last_fin_keys table for (auto itr = _last_fin_keys.begin(); itr != _last_fin_keys.end(); ++itr) { auto fin_key_itr = _finalizer_keys.find(itr->id); - assert( fin_key_itr != _finalizer_keys.end() ); + check( fin_key_itr != _finalizer_keys.end(), "last finalizer key not found in finalizer keys table" ); finalizer_authorities.emplace_back( eosio::finalizer_authority{ .description = fin_key_itr->finalizer_name.to_string(), @@ -246,7 +265,14 @@ namespace eosiosystem { eosio::set_finalizers(std::move(fin_policy)); } - // Action to delete a registered finalizer key + /* + * Action to delete a registered finalizer key + * + * @pre `finalizer_name` must be a registered producer + * @pre `finalizer_key` must be a registered finalizer key in base64url format + * @pre `finalizer_key` must not be active, unless it is the last registered finalizer key + * @pre Authority of `finalizer_name` + * */ void system_contract::delfinkey( const name& finalizer_name, const std::string& finalizer_key ) { require_auth( finalizer_name ); @@ -256,7 +282,7 @@ namespace eosiosystem { // Check finalizer has registered keys auto finalizer = _finalizers.find(finalizer_name.value); check( finalizer != _finalizers.end(), "finalizer has not registered any finalizer keys" ); - assert( finalizer->finalizer_key_count > 0 ); + check( finalizer->finalizer_key_count > 0, "finalizer_key_count of the finalizer must be greater than one" ); check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key must start with PUB_BLS"); @@ -269,24 +295,28 @@ namespace eosiosystem { // Check the key belongs to the finalizer check(fin_key_itr->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer"); - // If the key is currently active, it cannot be deleted unless it is the - // only key of the finalizer. if( fin_key_itr->id == finalizer->active_finalizer_key_id ) { check( finalizer->finalizer_key_count == 1, "cannot delete an active key unless it is the last registered finalizer key"); } - // Remove the key from finalizer_keys table - idx.erase( fin_key_itr ); - // Update finalizers table if( finalizer->finalizer_key_count == 1 ) { // The finalizer does not have any registered keys. Remove it from finalizers table. _finalizers.erase( finalizer ); + + // Remove it from _last_fin_keys in case ID is reused + const auto itr = _last_fin_keys.find(fin_key_itr->id); + if( itr != _last_fin_keys.end() ) { + _last_fin_keys.erase(itr); + } } else { // Decrement finalizer_key_count finalizers table _finalizers.modify( finalizer, same_payer, [&]( auto& f ) { --f.finalizer_key_count; }); } + + // Remove the key from finalizer_keys table + idx.erase( fin_key_itr ); } } /// namespace eosiosystem diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index b15b2dbe..b59732df 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -119,6 +119,11 @@ const std::string pop_2 = "SIG_BLS_9e1SzM60bWLdxwz4lYNQMNzMGeFuzFgJDYy7WykmynRVR const std::string pop_3 = "SIG_BLS_cJTQMGv1isqpcHEfhogLhlU56bKpGgo-Svi3Z4NXvWcly5TJo8hDChodIV-aEHgMqr06LuZftR7WFvgGkbOSdmwdO4t58R3RYOMSK-jjif2z-fEwCl7jsxUutASIRwIYtTI7h6NLCjARiKNi5BkES33xY8wYMWf-JkgbpsD2cGsZW4hkMW7T2j_1w89HmNwCn4V_hjlPM_kgz45RoYpKq4w2QEaLdCYTJ6xYOfc9Occc15c76dd1jjty_yT2RMAKO0mfUA"; const std::string pop_4 = "SIG_BLS_GNlwGxjL-LCVDApTHernv8Hj6EqlsxWlZBUzOu6DcJmNNuHsfetXK14RPJ-L63wVnhPRL9aNrQAURy2wYJ1__rNiGk-nUMZ5RDTO7tO2EPTiyySq9cbzgn43vKG8FgsA4gbNlqVFeTCbo5CgGj8m9vXNV4-Cv68WW-ivcwJzDtnNA3O9PPIpRY6_HhbmwTUVrHL2v7X_arNCyAf29nucAYNOsCM-br6F6HwpSjqSxi4-KqcFfQCWbAbn_SgJNVAA4yx5fQ"; +const std::string finalizer_key_binary_1 = "ea3e18dcb7ec46207163e0e0beaad934c0adb477ed0503c85b00e237608c8475942e33759c6c0cd4efe710425e7eac001b85f4f67e0a76de1ad667d9d444b570b1a3428eae2cb4a5a22556e22f415213075369d5ba33f5fd4ffd8a1748dde819"; +const std::string finalizer_key_binary_2 = "82d68e8ce4dad0dcc3b7c7ad043a8ba192a57ca4e94da95c75f99b4c99272d4241d85bb80affaea1af2e9c5ddb2799057b0682cdfded8d8532344e820d2af0bd83f9370e3b63da04f71e27a8959f27290c3a8688d24273f860eb18dda765d500"; +const std::string finalizer_key_binary_3 = "093f2486f65861974e6de215f5a4e777c7d9f1b75a08bd54a52472a8d2d964ce6c76b392a4e8c34c063676b4d81af40f552db5061b43f1a70b261a86c937e3aab5a3c98e454dfa8b75c9628287d2a5ada5ac6dc5a8a54d79450b479420708318"; +const std::string finalizer_key_binary_4 = "849602f511159383f382ddcd33270868246946a4d7f08204001f3185683aa4e62c57b9fd8099d34d43b33c61fc544e053e1c6fcc9bafadbe5335e479307c088cf30c2953d81c8f9d0c5c25e4eaa3d321fdba829170caa311a159e55617df3309"; + BOOST_FIXTURE_TEST_CASE(register_finalizer_key_failure_tests, finalizer_key_tester) try { { // bob111111111 does not have Alice's authority BOOST_REQUIRE_EQUAL( error( "missing authority of bob111111111" ), @@ -174,12 +179,14 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_same_finalizer_tests, finalize // Register first finalizer key BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(alice, finalizer_key_1, pop_1) ); + // Make sure binary format is correct, which is important auto alice_info = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( "alice1111111", alice_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( 1, alice_info["finalizer_key_count"].as_uint64() ); - uint64_t active_finalizer_key_id = alice_info["active_finalizer_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( finalizer_key_binary_1, alice_info["active_finalizer_key_binary"].as_string() ); // Cross check finalizer keys table + uint64_t active_finalizer_key_id = alice_info["active_finalizer_key_id"].as_uint64(); auto fin_key_info = get_finalizer_key_info(active_finalizer_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", fin_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_1, fin_key_info["finalizer_key"].as_string() ); @@ -224,6 +231,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_different_finalizers_tests, fi auto alice_info = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( "alice1111111", alice_info["finalizer_name"].as_string() ); + BOOST_REQUIRE_EQUAL( finalizer_key_binary_1, alice_info["active_finalizer_key_binary"].as_string() ); BOOST_REQUIRE_EQUAL( 2, alice_info["finalizer_key_count"].as_uint64() ); // bob111111111 registers another finalizer key @@ -232,6 +240,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_different_finalizers_tests, fi auto bob_info = get_finalizer_info(bob); BOOST_REQUIRE_EQUAL( 2, bob_info["finalizer_key_count"].as_uint64() ); + BOOST_REQUIRE_EQUAL( finalizer_key_binary_3, bob_info["active_finalizer_key_binary"].as_string() ); } FC_LOG_AND_RETHROW() // register_finalizer_key_by_different_finalizers_tests @@ -316,6 +325,9 @@ BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_success_tests, finalizer_key_test finalizer_key_info = get_finalizer_key_info(active_finalizer_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_2, finalizer_key_info["finalizer_key"].as_string() ); + + // Make sure active_finalizer_key_binary is correct. This test is important. + BOOST_REQUIRE_EQUAL( finalizer_key_binary_2, alice_info["active_finalizer_key_binary"].as_string() ); } FC_LOG_AND_RETHROW() // activate_finalizer_key_success_tests @@ -537,55 +549,13 @@ FC_LOG_AND_RETHROW() // An active finalizer deletes its only key. It is replaced by another finalizer in next round. BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, finalizer_key_tester) try { - // creat voters - const asset net = core_sym::from_string("80.0000"); - const asset cpu = core_sym::from_string("80.0000"); - const std::vector voters = { "producvotera"_n, "producvoterb"_n, "producvoterc"_n, "producvoterd"_n }; - for (const auto& v: voters) { - create_account_with_resources( v, config::system_account_name, core_sym::from_string("1.0000"), false, net, cpu ); - transfer( config::system_account_name, v, core_sym::from_string("100000000.0000"), config::system_account_name ); - BOOST_REQUIRE_EQUAL(success(), stake(v, core_sym::from_string("30000000.0000"), core_sym::from_string("30000000.0000")) ); - } + // Create and vote 26 producers + auto producer_names = active_and_vote_producers(26); - // create accounts {defproducera, defproducerb, ..., defproducerz, abcproducera, ..., defproducern} and register as producers - std::vector producer_names; - { - producer_names.reserve('z' - 'a' + 1); - { - const std::string root("defproducer"); - for ( char c = 'a'; c <= 'z'; ++c ) { - producer_names.emplace_back(root + std::string(1, c)); - } - } - { - const std::string root("abcproducer"); - for ( char c = 'a'; c <= 'n'; ++c ) { - producer_names.emplace_back(root + std::string(1, c)); - } - } - setup_producer_accounts(producer_names); - for (const auto& p: producer_names) { - BOOST_REQUIRE_EQUAL( success(), regproducer(p) ); - produce_blocks(1); - BOOST_TEST(0 == get_producer_info(p)["total_votes"].as()); - } - } - - produce_blocks( 2 * 21 * 1 ); - - // producvotera votes for defproducera ... defproducerj - // producvoterb votes for defproducera ... defproduceru - // producvoterc votes for defproducera ... defproducerz - // producvoterd votes for abcproducera ... abcproducern - { - BOOST_REQUIRE_EQUAL(success(), vote("producvotera"_n, vector(producer_names.begin(), producer_names.begin()+10))); - BOOST_REQUIRE_EQUAL(success(), vote("producvoterb"_n, vector(producer_names.begin(), producer_names.begin()+21))); - BOOST_REQUIRE_EQUAL(success(), vote("producvoterc"_n, vector(producer_names.begin(), producer_names.begin()+26))); - BOOST_REQUIRE_EQUAL(success(), vote("producvoterd"_n, vector(producer_names.begin()+26, producer_names.end()))); - } - - // Register 21 finalizer keys + // But only the first 21 producers (defproducera .. defproduceru) register finalizer + // keys at the beginning register_finalizer_keys(producer_names, 21); + // Transition to Savanna BOOST_REQUIRE_EQUAL(success(), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); @@ -602,8 +572,8 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_finalizer_key_id) ); } - const auto new_prod_name = producer_names[21]; - BOOST_REQUIRE_EQUAL( success(), regproducer(new_prod_name) ); + // defproducerv registers its first finalizer key and is marked active + account_name new_prod_name = "defproducerv"_n; BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(new_prod_name, finalizer_key_1, pop_1) ); auto prod_info = get_finalizer_info(new_prod_name); uint64_t new_id = prod_info["active_finalizer_key_id"].as_uint64(); @@ -611,7 +581,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // Wait for two rounds of producer schedule so new finalizer policy takes effect produce_block( fc::minutes(2) ); - // Delete an active finalizer key + // Delete defproducera's finalizer key name deleted_prod_name = producer_names[0]; auto p_info = get_finalizer_info(deleted_prod_name); uint64_t deleted_id = p_info["active_finalizer_key_id"].as_uint64(); @@ -619,7 +589,8 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final auto deleted_key = k_info["finalizer_key"].as_string(); BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(deleted_prod_name, deleted_key) ); - // Wait for two rounds of producer schedule so new finalizer policy takes effect + // Wait for two rounds of producer schedule so defproducera is replaced by defproducerv + // because defproducera does not have an active finalizer key produce_blocks(504); // find new last_finkey_ids @@ -627,7 +598,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // Make sure new_id is in the new last_finkey_ids BOOST_REQUIRE_EQUAL( true, last_finkey_ids_2.contains(new_id) ); - // After replace the deleted_id with new_id in last_finkey_ids, + // After replace the deleted_id with new_id in the old last_finkey_ids, // last_finkey_ids should be the same as last_finkey_ids_2 last_finkey_ids.erase(deleted_id); last_finkey_ids.insert(new_id); diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index f2a6a823..18c0b751 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -977,7 +977,7 @@ class eosio_system_tester : public TESTER { return msig_abi_ser; } - vector active_and_vote_producers() { + vector active_and_vote_producers(uint32_t num_producers = 21) { //stake more than 15% of total EOS supply to activate chain transfer( "eosio"_n, "alice1111111"_n, core_sym::from_string("650000000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111"_n, "alice1111111"_n, core_sym::from_string("300000000.0000"), core_sym::from_string("300000000.0000") ) ); @@ -987,7 +987,7 @@ class eosio_system_tester : public TESTER { { producer_names.reserve('z' - 'a' + 1); const std::string root("defproducer"); - for ( char c = 'a'; c < 'a'+21; ++c ) { + for ( char c = 'a'; c < 'a'+num_producers; ++c ) { producer_names.emplace_back(root + std::string(1, c)); } setup_producer_accounts(producer_names); @@ -1018,7 +1018,7 @@ class eosio_system_tester : public TESTER { BOOST_REQUIRE_EQUAL(success(), push_action("alice1111111"_n, "voteproducer"_n, mvo() ("voter", "alice1111111") ("proxy", name(0).to_string()) - ("producers", vector(producer_names.begin(), producer_names.begin()+21)) + ("producers", vector(producer_names.begin(), producer_names.begin()+num_producers)) ) ); } From d5f68ad4fc063c5d48cbce36be19491c972715f2 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 8 Apr 2024 10:05:23 -0400 Subject: [PATCH 71/94] Remove unnecessary set_proposed_producers related code in switosvnn() action --- contracts/eosio.system/src/finalizer_key.cpp | 36 ++------------------ 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 3c940ed2..b1a6aa4c 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -26,11 +26,8 @@ namespace eosiosystem { check(!is_savanna_consensus(), "switchtosvnn can be run only once"); - using value_type = std::pair; - std::vector top_producers; std::vector finalizer_authorities; std::vector first_finalizer_key_set; - top_producers.reserve(21); finalizer_authorities.reserve(21); first_finalizer_key_set.reserve(21); @@ -38,7 +35,7 @@ namespace eosiosystem { // for being a proposer and also have an active finalizer key uint32_t i = 0; auto idx = _producers.get_index<"prototalvote"_n>(); - for( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active() && i < 30; ++it, ++i ) { + for( auto it = idx.cbegin(); it != idx.cend() && finalizer_authorities.size() < 21 && 0 < it->total_votes && it->active() && i < 30; ++it, ++i ) { auto finalizer = _finalizers.find( it->owner.value ); if( finalizer == _finalizers.end() ) { // The producer is not in finalizers table, indicating it does not have an @@ -51,15 +48,6 @@ namespace eosiosystem { continue; } - // builds up producer_authority - top_producers.emplace_back( - eosio::producer_authority{ - .producer_name = it->owner, - .authority = it->get_producer_authority() - }, - it->location - ); - // stores finalizer_key_id first_finalizer_key_set.emplace_back(finalizer->active_finalizer_key_id); @@ -73,28 +61,10 @@ namespace eosiosystem { ); } - check( top_producers.size() > 0 && top_producers.size() >= _gstate.last_producer_schedule_size, "not enough top producers have registered finalizer keys" ); - - std::sort( top_producers.begin(), top_producers.end(), []( const value_type& lhs, const value_type& rhs ) { - return lhs.first.producer_name < rhs.first.producer_name; // sort by producer name - // return lhs.second < rhs.second; // sort by location - } ); - - std::vector producers; + check( finalizer_authorities.size() > 0 && finalizer_authorities.size() >= _gstate.last_producer_schedule_size, "not enough top producers have registered finalizer keys" ); - producers.reserve(top_producers.size()); - for( auto& item : top_producers ) - producers.push_back( std::move(item.first) ); - - // Should set_finalizers() be called before set_proposed_producers() - // during transition? set_finalizers(std::move(finalizer_authorities), first_finalizer_key_set, {}); check( is_savanna_consensus(), "switching to Savanna failed" ); - - if( set_proposed_producers( producers ) >= 0 ) { - _gstate.last_producer_schedule_update = eosio::current_time_point(); - _gstate.last_producer_schedule_size = static_cast( producers.size() ); - } } // This function may never fail, as it can be called by update_elected_producers, @@ -152,7 +122,7 @@ namespace eosiosystem { const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); const auto pop_g2 = eosio::decode_bls_signature_to_g2(proof_of_possession); - // Proof of possession check is expensive, do it last + // Proof of possession check check(eosio::bls_pop_verify(fin_key_g1, pop_g2), "proof of possession check failed"); // Insert the finalizer key into finalyzer_keys table From bddb5eff21feb2c14ddb4086e6cff9910e5dd51c Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 8 Apr 2024 11:38:41 -0400 Subject: [PATCH 72/94] Provide detailed information for check() failures in actions --- contracts/eosio.system/src/finalizer_key.cpp | 36 ++++++++++---------- tests/eosio.finalizer_key_tests.cpp | 34 +++++++++--------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index b1a6aa4c..4aea8441 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -61,7 +61,7 @@ namespace eosiosystem { ); } - check( finalizer_authorities.size() > 0 && finalizer_authorities.size() >= _gstate.last_producer_schedule_size, "not enough top producers have registered finalizer keys" ); + check( finalizer_authorities.size() > 0 && finalizer_authorities.size() >= _gstate.last_producer_schedule_size, "not enough top producers have registered finalizer keys, has " + std::to_string(finalizer_authorities.size()) ); set_finalizers(std::move(finalizer_authorities), first_finalizer_key_set, {}); check( is_savanna_consensus(), "switching to Savanna failed" ); @@ -107,16 +107,16 @@ namespace eosiosystem { require_auth( finalizer_name ); auto producer = _producers.find( finalizer_name.value ); - check( producer != _producers.end(), "finalizer is not a registered producer"); + check( producer != _producers.end(), "finalizer " + finalizer_name.to_string() + " is not a registered producer"); // Basic key and signature format check - check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key must start with PUB_BLS"); - check(proof_of_possession.compare(0, 7, "SIG_BLS") == 0, "proof of possession signature must start with SIG_BLS"); + check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key does not start with PUB_BLS: " + finalizer_key); + check(proof_of_possession.compare(0, 7, "SIG_BLS") == 0, "proof of possession signature does not start with SIG_BLS: " + proof_of_possession); // Duplication check across all registered keys auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); auto hash = get_finalizer_key_hash(finalizer_key); - check(idx.find(hash) == idx.end(), "duplicate finalizer key"); + check(idx.find(hash) == idx.end(), "duplicate finalizer key: " + finalizer_key); // Convert to binary form. The validity will be checked during conversion. const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); @@ -164,26 +164,26 @@ namespace eosiosystem { require_auth( finalizer_name ); auto producer = _producers.find( finalizer_name.value ); - check( producer != _producers.end(), "finalizer is not a registered producer"); + check( producer != _producers.end(), "finalizer " + finalizer_name.to_string() + " is not a registered producer"); // Check finalizer has registered keys auto finalizer = _finalizers.find(finalizer_name.value); check( finalizer != _finalizers.end(), "finalizer has not registered any finalizer keys" ); // Basic format check - check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key must start with PUB_BLS"); + check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key does not start with PUB_BLS: " + finalizer_key); // Check the key is registered auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); auto hash = get_finalizer_key_hash(finalizer_key); auto finalizer_key_itr = idx.find(hash); - check(finalizer_key_itr != idx.end(), "finalizer key was not registered"); + check(finalizer_key_itr != idx.end(), "finalizer key was not registered: " + finalizer_key); // Check the key belongs to finalizer - check(finalizer_key_itr->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer"); + check(finalizer_key_itr->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer: " + finalizer_key); // Check if the finalizer key is not already active - check( finalizer_key_itr->id != finalizer->active_finalizer_key_id, "the finalizer key was already active" ); + check( finalizer_key_itr->id != finalizer->active_finalizer_key_id, "finalizer key was already active: " + finalizer_key ); auto old_active_finalizer_key_id = finalizer->active_finalizer_key_id; @@ -216,7 +216,7 @@ namespace eosiosystem { // Build a new finalizer_authority by going over all keys in _last_fin_keys table for (auto itr = _last_fin_keys.begin(); itr != _last_fin_keys.end(); ++itr) { auto fin_key_itr = _finalizer_keys.find(itr->id); - check( fin_key_itr != _finalizer_keys.end(), "last finalizer key not found in finalizer keys table" ); + check( fin_key_itr != _finalizer_keys.end(), "last finalizer key not found in finalizer keys table, key id: " + std::to_string(itr->id) ); finalizer_authorities.emplace_back( eosio::finalizer_authority{ .description = fin_key_itr->finalizer_name.to_string(), @@ -247,26 +247,26 @@ namespace eosiosystem { require_auth( finalizer_name ); auto producer = _producers.find( finalizer_name.value ); - check( producer != _producers.end(), "finalizer is not a registered producer"); + check( producer != _producers.end(), "finalizer " + finalizer_name.to_string() + " is not a registered producer"); // Check finalizer has registered keys auto finalizer = _finalizers.find(finalizer_name.value); - check( finalizer != _finalizers.end(), "finalizer has not registered any finalizer keys" ); - check( finalizer->finalizer_key_count > 0, "finalizer_key_count of the finalizer must be greater than one" ); + check( finalizer != _finalizers.end(), "finalizer " + finalizer_name.to_string() + " has not registered any finalizer keys" ); + check( finalizer->finalizer_key_count > 0, "finalizer " + finalizer_name.to_string() + " must have at least one registered finalizer keys, has " + std::to_string(finalizer->finalizer_key_count) ); - check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key must start with PUB_BLS"); + check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key does not start with PUB_BLS: " + finalizer_key); // Check the key is registered auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); auto hash = get_finalizer_key_hash(finalizer_key); auto fin_key_itr = idx.find(hash); - check(fin_key_itr != idx.end(), "finalizer key was not registered"); + check(fin_key_itr != idx.end(), "finalizer key was not registered: " + finalizer_key); // Check the key belongs to the finalizer - check(fin_key_itr->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer"); + check(fin_key_itr->finalizer_name == name(finalizer_name), "finalizer key " + finalizer_key + " was not registered by the finalizer " + finalizer_name.to_string() ); if( fin_key_itr->id == finalizer->active_finalizer_key_id ) { - check( finalizer->finalizer_key_count == 1, "cannot delete an active key unless it is the last registered finalizer key"); + check( finalizer->finalizer_key_count == 1, "cannot delete an active key unless it is the last registered finalizer key, has " + std::to_string(finalizer->finalizer_key_count) + " keys"); } // Update finalizers table diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index b59732df..7097c3af 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -135,7 +135,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_failure_tests, finalizer_key_test } { // attempt to register finalizer_key for an unregistered producer - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer is not a registered producer" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer alice1111111 is not a registered producer" ), register_finalizer_key(alice, finalizer_key_1, pop_1)); } @@ -144,7 +144,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_failure_tests, finalizer_key_test { // finalizer key does not start with PUB_BLS - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key must start with PUB_BLS" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key does not start with PUB_BLS: UB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA"), push_action(alice, "regfinkey"_n, mvo() ("finalizer_name", "alice1111111") ("finalizer_key", "UB_BLS_6j4Y3LfsRiBxY-DgvqrZNMCttHftBQPIWwDiN2CMhHWULjN1nGwM1O_nEEJefqwAG4X09n4Kdt4a1mfZ1ES1cLGjQo6uLLSloiVW4i9BUhMHU2nVujP1_U_9ihdI3egZ17N-iA" ) @@ -153,7 +153,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_failure_tests, finalizer_key_test } { // proof_of_possession does not start with SIG_BLS - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "proof of possession signature must start with SIG_BLS" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "proof of possession signature does not start with SIG_BLS: XIG_BLS_N5r73_i50OVkydasCVVBOqqAqM4XQo_-DHgNawK77bcf06Bx0_rh5TNn9iZewNMZ6ecyEjs_sEkwjAXplhqyqf7S9FqSt8mfRxO7pE3bUZS0Z-Fxitsh9X0l_-kj3Z8VD8IwsaUwBLacudzShIXA-5E47cEqYoV3bGhANerKuDhZ4Pesm2xotAScK0pcNp0LbTNj0MZpVr0u6kJh169IoeG4ngCvD6uE2EicNrzyvDhu0u925Q1cm5z_bVha-DsANq3zcA" ), push_action(alice, "regfinkey"_n, mvo() ("finalizer_name", "alice1111111") ("finalizer_key", finalizer_key_1) @@ -211,7 +211,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_duplicate_key_tests, finalizer_ke BOOST_REQUIRE_EQUAL( 1, alice_info["finalizer_key_count"].as_uint64() ); // Tries to register the same finalizer key - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "duplicate finalizer key" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "duplicate finalizer key: " + finalizer_key_1 ), register_finalizer_key(alice, finalizer_key_1, pop_1) ); // finalizer key count still 1 @@ -257,7 +257,7 @@ BOOST_FIXTURE_TEST_CASE(register_duplicate_key_from_different_finalizers_tests, BOOST_REQUIRE_EQUAL( 1, fin_info["finalizer_key_count"].as_uint64() ); // bob111111111 tries to register the same finalizer key as the first one - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "duplicate finalizer key" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "duplicate finalizer key: " + finalizer_key_1 ), register_finalizer_key(bob, finalizer_key_1, pop_1) ); } FC_LOG_AND_RETHROW() // register_duplicate_key_from_different_finalizers_tests @@ -271,8 +271,8 @@ BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_failure_tests, finalizer_key_test ) ); // attempt to activate finalizer_key for an unregistered producer - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer is not a registered producer" ), - activate_finalizer_key(alice, finalizer_key_1) ); + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer alice1111111 is not a registered producer" ), + activate_finalizer_key(alice, finalizer_key_1) ); // Register producers BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); @@ -287,16 +287,16 @@ BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_failure_tests, finalizer_key_test BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_2, pop_2) ); // Activate a finalizer key not registered by anyone - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered: " + finalizer_key_3 ), activate_finalizer_key(alice, finalizer_key_3) ); // Activate a finalizer key not registered by Alice - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered by the finalizer" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered by the finalizer: " + finalizer_key_2 ), activate_finalizer_key(alice, finalizer_key_2) ); // Activate a finalizer key that is already active (the first key registered is // automatically set to active - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "the finalizer key was already active" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was already active: " + finalizer_key_1 ), activate_finalizer_key(alice, finalizer_key_1) ); } FC_LOG_AND_RETHROW() // activate_finalizer_key_failure_tests @@ -340,15 +340,15 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_failure_tests, finalizer_key_tester ) ); // attempt to delete finalizer_key for an unregistered producer - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer is not a registered producer" ), - delete_finalizer_key(alice, finalizer_key_1) ); + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer alice1111111 is not a registered producer" ), + delete_finalizer_key(alice, finalizer_key_1) ); // Register producers BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); BOOST_REQUIRE_EQUAL( success(), regproducer(bob) ); // finalizer has not registered any finalizer keys yet. - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer has not registered any finalizer keys" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer alice1111111 has not registered any finalizer keys" ), delete_finalizer_key(alice, finalizer_key_1) ); // Alice and Bob register finalizer keys @@ -357,11 +357,11 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_failure_tests, finalizer_key_tester BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(bob, finalizer_key_3, pop_3) ); // Alice tries to delete a finalizer key not registered by anyone - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered: " + finalizer_key_4 ), delete_finalizer_key(alice, finalizer_key_4) ); // Alice tries to delete a finalizer key registered by Bob - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key was not registered by the finalizer" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer key " + finalizer_key_2 + " was not registered by the finalizer alice1111111" ), delete_finalizer_key(alice, finalizer_key_2) ); // Make sure finalizer_key_2 is Bob's active finalizer key and Bob has 2 keys @@ -372,7 +372,7 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_failure_tests, finalizer_key_tester BOOST_REQUIRE_EQUAL( 2, bob_info["finalizer_key_count"].as_uint64() ); // Bob tries to delete his active finalizer key but he has 2 keys - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "cannot delete an active key unless it is the last registered finalizer key" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "cannot delete an active key unless it is the last registered finalizer key, has 2 keys" ), delete_finalizer_key(bob, finalizer_key_2) ); } @@ -466,7 +466,7 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_not_enough_finalizer_keys_tests, finalizer_ register_finalizer_keys(producer_names, 20); // Have only 20 finalizer keys, short by 1 - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "not enough top producers have registered finalizer keys" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "not enough top producers have registered finalizer keys, has 20" ), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); } FC_LOG_AND_RETHROW() From 96239057e93aa53a05d820e281c58f6f0764019a Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 8 Apr 2024 13:09:56 -0400 Subject: [PATCH 73/94] Add deleting last finalizer key to update_elected_producers_finalizers_replaced_test --- tests/eosio.finalizer_key_tests.cpp | 51 +++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 7097c3af..6d9eb5c4 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -572,22 +572,24 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_finalizer_key_id) ); } + // Test delete the first finalizer key + // defproducerv registers its first finalizer key and is marked active - account_name new_prod_name = "defproducerv"_n; - BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(new_prod_name, finalizer_key_1, pop_1) ); - auto prod_info = get_finalizer_info(new_prod_name); - uint64_t new_id = prod_info["active_finalizer_key_id"].as_uint64(); + account_name producerv_name = "defproducerv"_n; + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(producerv_name, finalizer_key_1, pop_1) ); + auto producerv_info = get_finalizer_info(producerv_name); + uint64_t producerv_id = producerv_info["active_finalizer_key_id"].as_uint64(); // Wait for two rounds of producer schedule so new finalizer policy takes effect produce_block( fc::minutes(2) ); // Delete defproducera's finalizer key - name deleted_prod_name = producer_names[0]; - auto p_info = get_finalizer_info(deleted_prod_name); + name producera_name = "defproducera"_n; + auto p_info = get_finalizer_info(producera_name); uint64_t deleted_id = p_info["active_finalizer_key_id"].as_uint64(); auto k_info = get_finalizer_key_info(deleted_id); - auto deleted_key = k_info["finalizer_key"].as_string(); - BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(deleted_prod_name, deleted_key) ); + auto producera_id = k_info["finalizer_key"].as_string(); + BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(producera_name, producera_id) ); // Wait for two rounds of producer schedule so defproducera is replaced by defproducerv // because defproducera does not have an active finalizer key @@ -596,13 +598,42 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // find new last_finkey_ids auto last_finkey_ids_2 = get_last_finkey_ids(); // Make sure new_id is in the new last_finkey_ids - BOOST_REQUIRE_EQUAL( true, last_finkey_ids_2.contains(new_id) ); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids_2.contains(producerv_id) ); // After replace the deleted_id with new_id in the old last_finkey_ids, // last_finkey_ids should be the same as last_finkey_ids_2 last_finkey_ids.erase(deleted_id); - last_finkey_ids.insert(new_id); + last_finkey_ids.insert(producerv_id); BOOST_REQUIRE_EQUAL( true, last_finkey_ids == last_finkey_ids_2 ); + + // Test delete last finalizer key + + // defproducerw registers its first finalizer key and is marked active + account_name producerw_name = "defproducerw"_n; + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(producerw_name, finalizer_key_2, pop_2) ); + auto producerw_info = get_finalizer_info(producerw_name); + uint64_t producerw_id = producerw_info["active_finalizer_key_id"].as_uint64(); + + // Wait for two rounds of producer schedule so new finalizer policy takes effect + produce_block( fc::minutes(2) ); + + // Delete defproducerv's finalizer key + BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(producerv_name, finalizer_key_1) ); + + // Wait for two rounds of producer schedule so defproducera is replaced by defproducerv + // because defproducera does not have an active finalizer key + produce_blocks(504); + + // find new last_finkey_ids + auto last_finkey_ids_3 = get_last_finkey_ids(); + // Make sure producerw_id is in the new last_finkey_ids + BOOST_REQUIRE_EQUAL( true, last_finkey_ids_3.contains(producerw_id) ); + + // After replace producerv_id wth producerw_id in the old last_finkey_ids_2, + // last_finkey_ids should be the same as last_finkey_ids_3 + last_finkey_ids_2.erase(producerv_id); + last_finkey_ids_2.insert(producerw_id); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids_2 == last_finkey_ids_3 ); } FC_LOG_AND_RETHROW() From dba03eaa36732fcc85262c1969da83d98e4d26a2 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 9 Apr 2024 11:00:21 -0400 Subject: [PATCH 74/94] Do not limit number of producers consideered to be 30, to match with update_elected_producers() implementation; replace hardcoded number 21 with ast_producer_schedule_size --- contracts/eosio.system/src/finalizer_key.cpp | 15 ++++++++------- tests/eosio.finalizer_key_tests.cpp | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 4aea8441..c87fee85 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -28,14 +28,15 @@ namespace eosiosystem { std::vector finalizer_authorities; std::vector first_finalizer_key_set; - finalizer_authorities.reserve(21); - first_finalizer_key_set.reserve(21); + finalizer_authorities.reserve(_gstate.last_producer_schedule_size); + first_finalizer_key_set.reserve(_gstate.last_producer_schedule_size); - // From up to 30 top producers, find 21 producers that meet all the normal requirements - // for being a proposer and also have an active finalizer key - uint32_t i = 0; + // Find a set of producers that meet all the normal requirements for + // being a proposer and also have an active finalizer key. + // The number of the producers must be equal to the number of producers + // in the last_producer_schedule. auto idx = _producers.get_index<"prototalvote"_n>(); - for( auto it = idx.cbegin(); it != idx.cend() && finalizer_authorities.size() < 21 && 0 < it->total_votes && it->active() && i < 30; ++it, ++i ) { + for( auto it = idx.cbegin(); it != idx.cend() && finalizer_authorities.size() < _gstate.last_producer_schedule_size && 0 < it->total_votes && it->active(); ++it ) { auto finalizer = _finalizers.find( it->owner.value ); if( finalizer == _finalizers.end() ) { // The producer is not in finalizers table, indicating it does not have an @@ -61,7 +62,7 @@ namespace eosiosystem { ); } - check( finalizer_authorities.size() > 0 && finalizer_authorities.size() >= _gstate.last_producer_schedule_size, "not enough top producers have registered finalizer keys, has " + std::to_string(finalizer_authorities.size()) ); + check( finalizer_authorities.size() == _gstate.last_producer_schedule_size, "not enough top producers have registered finalizer keys, has " + std::to_string(finalizer_authorities.size()) + ", require " + std::to_string(_gstate.last_producer_schedule_size) ); set_finalizers(std::move(finalizer_authorities), first_finalizer_key_set, {}); check( is_savanna_consensus(), "switching to Savanna failed" ); diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 6d9eb5c4..60ea507c 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -466,7 +466,7 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_not_enough_finalizer_keys_tests, finalizer_ register_finalizer_keys(producer_names, 20); // Have only 20 finalizer keys, short by 1 - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "not enough top producers have registered finalizer keys, has 20" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "not enough top producers have registered finalizer keys, has 20, require 21" ), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); } FC_LOG_AND_RETHROW() From c16b95ce6a50d0c8fb353f24407234153b47579d Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 9 Apr 2024 11:45:20 -0400 Subject: [PATCH 75/94] Use binary format as hashing key for finalizers table and do not store the hash key --- .../include/eosio.system/eosio.system.hpp | 8 ++++++-- contracts/eosio.system/src/finalizer_key.cpp | 14 +++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index db05c29d..6458f86c 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -290,11 +290,15 @@ namespace eosiosystem { name finalizer_name; // name of the finalizer owning the key std::string finalizer_key; // finalizer key in base64url format std::vector finalizer_key_binary; // finalizer key in binary format in Affine little endian non-montgomery g1 - checksum256 finalizer_key_hash; // hash of finalizer key, cached to avoid re-computing uint64_t primary_key() const { return id; } uint64_t by_fin_name() const { return finalizer_name.value; } - checksum256 by_fin_key() const { return finalizer_key_hash; } + // Use binary format to hash. It is more robust and less likely to change + // than the base64url text encoding of it. + // There is no need to store the hash key to avoid re-computation, + // which only happens if the table row is modified. There won't be any + // modification of the table rows of; it may only be removed. + checksum256 by_fin_key() const { return eosio::sha256(finalizer_key_binary.data(), finalizer_key_binary.size()); } }; typedef eosio::multi_index< "finkeys"_n, finalizer_key_info, diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index c87fee85..43bd41c6 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -11,7 +11,8 @@ namespace eosiosystem { // Rteurns hash of finalizer_key static eosio::checksum256 get_finalizer_key_hash(const std::string& finalizer_key) { - return eosio::sha256(finalizer_key.data(), finalizer_key.size()); + const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); + return eosio::sha256(fin_key_g1.data(), fin_key_g1.size()); } /** @@ -114,15 +115,15 @@ namespace eosiosystem { check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key does not start with PUB_BLS: " + finalizer_key); check(proof_of_possession.compare(0, 7, "SIG_BLS") == 0, "proof of possession signature does not start with SIG_BLS: " + proof_of_possession); - // Duplication check across all registered keys - auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); - auto hash = get_finalizer_key_hash(finalizer_key); - check(idx.find(hash) == idx.end(), "duplicate finalizer key: " + finalizer_key); - // Convert to binary form. The validity will be checked during conversion. const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); const auto pop_g2 = eosio::decode_bls_signature_to_g2(proof_of_possession); + // Duplication check across all registered keys + auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); + auto hash = eosio::sha256(fin_key_g1.data(), fin_key_g1.size()); + check(idx.find(hash) == idx.end(), "duplicate finalizer key: " + finalizer_key); + // Proof of possession check check(eosio::bls_pop_verify(fin_key_g1, pop_g2), "proof of possession check failed"); @@ -132,7 +133,6 @@ namespace eosiosystem { k.finalizer_name = finalizer_name; k.finalizer_key = finalizer_key; k.finalizer_key_binary = { fin_key_g1.begin(), fin_key_g1.end() }; - k.finalizer_key_hash = get_finalizer_key_hash(finalizer_key); }); // Update finalizers table From 7a12d93552a041b2bf91573f34223ba87ab805e7 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 9 Apr 2024 21:27:25 -0400 Subject: [PATCH 76/94] Use a singlton to store last proposed finalizer keys to simplify code logic and reasoning --- .../include/eosio.system/eosio.system.hpp | 49 ++++-- contracts/eosio.system/src/eosio.system.cpp | 7 +- contracts/eosio.system/src/finalizer_key.cpp | 148 +++++++++--------- contracts/eosio.system/src/voting.cpp | 34 ++-- tests/eosio.finalizer_key_tests.cpp | 109 +------------ 5 files changed, 133 insertions(+), 214 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 6458f86c..6af77842 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -199,6 +199,33 @@ namespace eosiosystem { EOSLIB_SERIALIZE( eosio_global_state4, (continuous_rate)(inflation_pay_factor)(votepay_factor) ) }; + // Defines new global state parameter to store next available + // finalizer key_id to make sure key_id in eosio_global_state_a will + // never be reused. + struct [[eosio::table("global5"), eosio::contract("eosio.system")]] eosio_global_state5 { + eosio_global_state5() { } + uint64_t get_next_finalizer_key_id() { return next_finalizer_key_id++; }; + + uint64_t next_finalizer_key_id = 0; + + EOSLIB_SERIALIZE( eosio_global_state5, (next_finalizer_key_id) ) + }; + + // Defines new global state parameter to store last proposed finalizer set. + // It is also used as an indicator Savanna consensus has been switched over. + struct proposed_finalizer_key_t { + uint64_t key_id; + eosio::finalizer_authority fin_authority; + + EOSLIB_SERIALIZE( proposed_finalizer_key_t, (key_id)(fin_authority) ) + }; + struct [[eosio::table("globala"), eosio::contract("eosio.system")]] eosio_global_state_a { // name can only contain digits '1' to '5'. + eosio_global_state_a() { } + std::vector last_proposed_keys; // sorted by ascending finalizer key id + + EOSLIB_SERIALIZE( eosio_global_state_a, (last_proposed_keys) ) + }; + inline eosio::block_signing_authority convert_to_block_signing_authority( const eosio::public_key& producer_key ) { return eosio::block_signing_authority_v0{ .threshold = 1, .keys = {{producer_key, 1}} }; } @@ -317,14 +344,6 @@ namespace eosiosystem { }; typedef eosio::multi_index< "finalizers"_n, finalizer_info > finalizers_table; - // last_fin_key_info stores information about a finalizer key used in last finalizer policy. - struct [[eosio::table("lastfinkeys"), eosio::contract("eosio.system")]] last_fin_key_info { - uint64_t id; // finalizer key's id in finalizer_keys_table - - uint64_t primary_key() const { return id; } - }; - typedef eosio::multi_index< "lastfinkeys"_n, last_fin_key_info > last_fin_keys_table; - // Voter info. Voter info stores information about the voter: // - `owner` the voter // - `proxy` the proxy set by the voter, if any @@ -380,6 +399,10 @@ namespace eosiosystem { typedef eosio::singleton< "global4"_n, eosio_global_state4 > global_state4_singleton; + typedef eosio::singleton< "global5"_n, eosio_global_state5 > global_state5_singleton; + + typedef eosio::singleton< "globala"_n, eosio_global_state_a > global_state_a_singleton; + struct [[eosio::table, eosio::contract("eosio.system")]] user_resources { name owner; asset net_weight; @@ -726,15 +749,18 @@ namespace eosiosystem { producers_table2 _producers2; finalizer_keys_table _finalizer_keys; finalizers_table _finalizers; - last_fin_keys_table _last_fin_keys; global_state_singleton _global; global_state2_singleton _global2; global_state3_singleton _global3; global_state4_singleton _global4; + global_state5_singleton _global5; + global_state_a_singleton _global_a; eosio_global_state _gstate; eosio_global_state2 _gstate2; eosio_global_state3 _gstate3; eosio_global_state4 _gstate4; + eosio_global_state5 _gstate5; + eosio_global_state_a _gstate_a; rammarket _rammarket; rex_pool_table _rexpool; rex_return_pool_table _rexretpool; @@ -1619,8 +1645,9 @@ namespace eosiosystem { // defined in finalizer_key.cpp bool is_savanna_consensus() const; - void set_finalizers( std::vector&& finalizer_authorities, const std::vector& finalizer_key_ids, const std::unordered_set& kept_key_ids ); - void generate_finalizer_policy_and_set_finalizers(); + void set_proposed_finalizers( const std::vector& proposed_fin_keys ); + void set_proposed_finalizers_if_changed( std::vector& proposed_fin_keys ); + void set_proposed_finalizers_unsorted( std::vector& proposed_fin_keys ); template class registration { diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index b4bfad6a..6a6faef4 100644 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -22,11 +22,12 @@ namespace eosiosystem { _producers2(get_self(), get_self().value), _finalizer_keys(get_self(), get_self().value), _finalizers(get_self(), get_self().value), - _last_fin_keys(get_self(), get_self().value), _global(get_self(), get_self().value), _global2(get_self(), get_self().value), _global3(get_self(), get_self().value), _global4(get_self(), get_self().value), + _global5(get_self(), get_self().value), + _global_a(get_self(), get_self().value), _rammarket(get_self(), get_self().value), _rexpool(get_self(), get_self().value), _rexretpool(get_self(), get_self().value), @@ -39,6 +40,8 @@ namespace eosiosystem { _gstate2 = _global2.exists() ? _global2.get() : eosio_global_state2{}; _gstate3 = _global3.exists() ? _global3.get() : eosio_global_state3{}; _gstate4 = _global4.exists() ? _global4.get() : get_default_inflation_parameters(); + _gstate5 = _global5.exists() ? _global5.get() : eosio_global_state5{}; + _gstate_a = _global_a.exists() ? _global_a.get() : eosio_global_state_a{}; } eosio_global_state system_contract::get_default_parameters() { @@ -65,6 +68,8 @@ namespace eosiosystem { _global2.set( _gstate2, get_self() ); _global3.set( _gstate3, get_self() ); _global4.set( _gstate4, get_self() ); + _global5.set( _gstate5, get_self() ); + _global_a.set( _gstate_a, get_self() ); } void system_contract::setram( uint64_t max_ram_size ) { diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 43bd41c6..ebedf47f 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -6,7 +6,7 @@ namespace eosiosystem { // Returns true if nodeos has transitioned to Savanna (last finalizer set not empty) bool system_contract::is_savanna_consensus() const { - return _last_fin_keys.begin() != _last_fin_keys.end(); + return !_gstate_a.last_proposed_keys.empty(); } // Rteurns hash of finalizer_key @@ -27,17 +27,15 @@ namespace eosiosystem { check(!is_savanna_consensus(), "switchtosvnn can be run only once"); - std::vector finalizer_authorities; - std::vector first_finalizer_key_set; - finalizer_authorities.reserve(_gstate.last_producer_schedule_size); - first_finalizer_key_set.reserve(_gstate.last_producer_schedule_size); + std::vector< proposed_finalizer_key_t > proposed_fin_keys; + proposed_fin_keys.reserve(_gstate.last_producer_schedule_size); // Find a set of producers that meet all the normal requirements for // being a proposer and also have an active finalizer key. // The number of the producers must be equal to the number of producers // in the last_producer_schedule. auto idx = _producers.get_index<"prototalvote"_n>(); - for( auto it = idx.cbegin(); it != idx.cend() && finalizer_authorities.size() < _gstate.last_producer_schedule_size && 0 < it->total_votes && it->active(); ++it ) { + for( auto it = idx.cbegin(); it != idx.cend() && proposed_fin_keys.size() < _gstate.last_producer_schedule_size && 0 < it->total_votes && it->active(); ++it ) { auto finalizer = _finalizers.find( it->owner.value ); if( finalizer == _finalizers.end() ) { // The producer is not in finalizers table, indicating it does not have an @@ -50,51 +48,84 @@ namespace eosiosystem { continue; } - // stores finalizer_key_id - first_finalizer_key_set.emplace_back(finalizer->active_finalizer_key_id); - - // builds up finalizer_authorities - finalizer_authorities.emplace_back( - eosio::finalizer_authority{ + proposed_fin_keys.emplace_back( proposed_finalizer_key_t { + .key_id = finalizer->active_finalizer_key_id, + .fin_authority = eosio::finalizer_authority{ .description = finalizer->finalizer_name.to_string(), .weight = 1, .public_key = finalizer->active_finalizer_key_binary - } + }} ); } - check( finalizer_authorities.size() == _gstate.last_producer_schedule_size, "not enough top producers have registered finalizer keys, has " + std::to_string(finalizer_authorities.size()) + ", require " + std::to_string(_gstate.last_producer_schedule_size) ); + check( proposed_fin_keys.size() == _gstate.last_producer_schedule_size, + "not enough top producers have registered finalizer keys, has " + std::to_string(proposed_fin_keys.size()) + ", require " + std::to_string(_gstate.last_producer_schedule_size) ); - set_finalizers(std::move(finalizer_authorities), first_finalizer_key_set, {}); + set_proposed_finalizers_unsorted(proposed_fin_keys); check( is_savanna_consensus(), "switching to Savanna failed" ); } - // This function may never fail, as it can be called by update_elected_producers, - // and in turn by onblock - void system_contract::set_finalizers( std::vector&& finalizer_authorities, const std::vector& new_ids, const std::unordered_set& kept_ids ) { + // This function may never fail, as it can be called by onblock indirectly. + // Establish finalizer policy from `proposed_fin_keys` and calls + // eosio::set_finalizers host function + void system_contract::set_proposed_finalizers( const std::vector& proposed_fin_keys ) { + // Construct finalizer authorities + std::vector finalizer_authorities; + for( const auto& k: proposed_fin_keys ) { + finalizer_authorities.emplace_back(k.fin_authority); + } + // Establish finalizer policy eosio::finalizer_policy fin_policy { .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, .finalizers = std::move(finalizer_authorities) }; + // call host function eosio::set_finalizers(std::move(fin_policy)); // call host function + } - // Purge any IDs not in kept_ids from _last_fin_keys table - for (auto itr = _last_fin_keys.begin(); itr != _last_fin_keys.end(); /* intentionally empty */ ) { - if( !kept_ids.contains(itr->id) ) { - itr = _last_fin_keys.erase(itr); - } else { - ++itr; + // Sort `proposed_fin_keys` and calls set_proposed_finalizers() + void system_contract::set_proposed_finalizers_unsorted( std::vector& proposed_fin_keys ) { + std::sort( proposed_fin_keys.begin(), proposed_fin_keys.end(), []( const proposed_finalizer_key_t& lhs, const proposed_finalizer_key_t& rhs ) { + return lhs.key_id < rhs.key_id; + } ); + + set_proposed_finalizers(proposed_fin_keys); + + // store last proposed policy + _gstate_a.last_proposed_keys = proposed_fin_keys; + } + + // This function may never fail, as it can be called by update_elected_producers, + // and in turn by onblock + // Sort `proposed_fin_keys`. If it is the same as last proposed finalizer + // policy, do not proceed. Otherwise, call set_proposed_finalizers() + void system_contract::set_proposed_finalizers_if_changed( std::vector& proposed_fin_keys ) { + std::sort( proposed_fin_keys.begin(), proposed_fin_keys.end(), []( const proposed_finalizer_key_t& lhs, const proposed_finalizer_key_t& rhs ) { + return lhs.key_id < rhs.key_id; + } ); + + if( proposed_fin_keys.size() == _gstate_a.last_proposed_keys.size() ) { + bool new_fin_policy = false; + for( auto i = 0; i < proposed_fin_keys.size(); ++i ) { + if( proposed_fin_keys[i].key_id != _gstate_a.last_proposed_keys[i].key_id || + proposed_fin_keys[i].fin_authority.public_key != _gstate_a.last_proposed_keys[i].fin_authority.public_key ) { + new_fin_policy = true; + break; + } } - } - // Add IDs in new_ids to _last_fin_keys table - for (auto id: new_ids ) { - _last_fin_keys.emplace( get_self(), [&]( auto& f ) { - f.id = id; - }); + // Finalizer policy has not changed. Do not proceed. + if( !new_fin_policy ) { + return; + } } + + set_proposed_finalizers(proposed_fin_keys); + + // store last proposed policy + _gstate_a.last_proposed_keys = proposed_fin_keys; } /* @@ -129,7 +160,7 @@ namespace eosiosystem { // Insert the finalizer key into finalyzer_keys table auto finalizer_key_itr = _finalizer_keys.emplace( finalizer_name, [&]( auto& k ) { - k.id = _finalizer_keys.available_primary_key(); + k.id = _gstate5.get_next_finalizer_key_id(); k.finalizer_name = finalizer_name; k.finalizer_key = finalizer_key; k.finalizer_key_binary = { fin_key_g1.begin(), fin_key_g1.end() }; @@ -186,54 +217,25 @@ namespace eosiosystem { // Check if the finalizer key is not already active check( finalizer_key_itr->id != finalizer->active_finalizer_key_id, "finalizer key was already active: " + finalizer_key ); - auto old_active_finalizer_key_id = finalizer->active_finalizer_key_id; + auto prev_fin_key_id = finalizer->active_finalizer_key_id; _finalizers.modify( finalizer, same_payer, [&]( auto& f ) { f.active_finalizer_key_id = finalizer_key_itr->id; f.active_finalizer_key_binary = finalizer_key_itr->finalizer_key_binary; }); - // Replace the finalizer policy immediately if the finalizer key is - // used in last finalizer policy - const auto old_key_itr = _last_fin_keys.find(old_active_finalizer_key_id); - if( old_key_itr != _last_fin_keys.end() ) { - // Delete old key - _last_fin_keys.erase(old_key_itr); - - // Replace the old key with finalizer key just activated - _last_fin_keys.emplace( get_self(), [&]( auto& f ) { - f.id = finalizer_key_itr->id; // new active finalizer key id - }); - - generate_finalizer_policy_and_set_finalizers(); - } - } + // Do a binary search to see if the finalizer is in last proposed policy + auto itr = std::lower_bound(_gstate_a.last_proposed_keys.begin(), _gstate_a.last_proposed_keys.end(), prev_fin_key_id, [](const proposed_finalizer_key_t& key, uint64_t id) { + return key.key_id < id; + }); - // Generate a new finalizer policy from keys in _last_fin_keys table and - // call set_finalizers host function immediately - void system_contract::generate_finalizer_policy_and_set_finalizers() { - std::vector finalizer_authorities; + if( itr != _gstate_a.last_proposed_keys.end() && itr->key_id == prev_fin_key_id ) { + // Replace the previous finalizer key with finalizer key just activated + itr->fin_authority.public_key = finalizer_key_itr->finalizer_key_binary; - // Build a new finalizer_authority by going over all keys in _last_fin_keys table - for (auto itr = _last_fin_keys.begin(); itr != _last_fin_keys.end(); ++itr) { - auto fin_key_itr = _finalizer_keys.find(itr->id); - check( fin_key_itr != _finalizer_keys.end(), "last finalizer key not found in finalizer keys table, key id: " + std::to_string(itr->id) ); - finalizer_authorities.emplace_back( - eosio::finalizer_authority{ - .description = fin_key_itr->finalizer_name.to_string(), - .weight = 1, - .public_key = fin_key_itr->finalizer_key_binary - } - ); + // Call set_finalizers immediately + set_proposed_finalizers(_gstate_a.last_proposed_keys); } - - eosio::finalizer_policy fin_policy { - .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, - .finalizers = std::move(finalizer_authorities) - }; - - // _last_fin_keys table is up to date. Call set_finalizers host function directly - eosio::set_finalizers(std::move(fin_policy)); } /* @@ -274,12 +276,6 @@ namespace eosiosystem { if( finalizer->finalizer_key_count == 1 ) { // The finalizer does not have any registered keys. Remove it from finalizers table. _finalizers.erase( finalizer ); - - // Remove it from _last_fin_keys in case ID is reused - const auto itr = _last_fin_keys.find(fin_key_itr->id); - if( itr != _last_fin_keys.end() ) { - _last_fin_keys.erase(itr); - } } else { // Decrement finalizer_key_count finalizers table _finalizers.modify( finalizer, same_payer, [&]( auto& f ) { diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index f92d7b61..d26c4897 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -110,13 +110,9 @@ namespace eosiosystem { using value_type = std::pair; std::vector< value_type > top_producers; - std::vector< eosio::finalizer_authority > next_finalizer_authorities; - std::vector< uint64_t > new_finalizer_key_ids; - std::unordered_set< uint64_t > kept_finalizer_key_ids; + std::vector< proposed_finalizer_key_t > proposed_fin_keys; top_producers.reserve(21); - next_finalizer_authorities.reserve(21); - new_finalizer_key_ids.reserve(21); - bool new_finalizer_keys_found = false; + proposed_fin_keys.reserve(21); for( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active(); ++it ) { if( is_savanna_consensus() ) { @@ -132,22 +128,13 @@ namespace eosiosystem { continue; } - if( _last_fin_keys.find(finalizer->active_finalizer_key_id) == _last_fin_keys.end() ) { - // If any producer's active finalizer_key_id is not in - // last_finalizer_key_ids, it means a new finalizer policy is needed. - new_finalizer_key_ids.emplace_back(finalizer->active_finalizer_key_id); - } else { - // the active_key is the same as last round for the producer - kept_finalizer_key_ids.insert(finalizer->active_finalizer_key_id); - } - - // Pre-build next_finalizer_authorities in case it is needed. - next_finalizer_authorities.emplace_back( - eosio::finalizer_authority{ - .description = it->owner.to_string(), + proposed_fin_keys.emplace_back( proposed_finalizer_key_t { + .key_id = finalizer->active_finalizer_key_id, + .fin_authority = eosio::finalizer_authority{ + .description = finalizer->finalizer_name.to_string(), .weight = 1, .public_key = finalizer->active_finalizer_key_binary - } + }} ); } @@ -179,9 +166,10 @@ namespace eosiosystem { _gstate.last_producer_schedule_size = static_cast( producers.size() ); } - // Only set a new finalizer policy if it has changed. - if( is_savanna_consensus() && !new_finalizer_key_ids.empty() ) { - set_finalizers( std::move(next_finalizer_authorities), new_finalizer_key_ids, kept_finalizer_key_ids ); + // set_proposed_finalizers() checks if last proposed finalizer policy + // has not changed, it will not call set_finalizers() host function. + if( is_savanna_consensus() ) { + set_proposed_finalizers_if_changed( proposed_fin_keys ); } } diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 60ea507c..7a6ea0a9 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -22,11 +22,6 @@ struct finalizer_key_tester : eosio_system_tester { return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "finalizer_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } - fc::variant get_last_fin_key_info( uint64_t id ) { - vector data = get_row_by_id( config::system_account_name, config::system_account_name, "lastfinkeys"_n, id ); - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "last_fin_key_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); - } - action_result register_finalizer_key( const account_name& act, const std::string& finalizer_key, const std::string& pop ) { return push_action( act, "regfinkey"_n, mvo() ("finalizer_name", act) @@ -57,25 +52,6 @@ struct finalizer_key_tester : eosio_system_tester { } } } - - std::unordered_set get_last_finkey_ids() { - const auto* table_id_itr = control->db().find( - boost::make_tuple(config::system_account_name, config::system_account_name, "lastfinkeys"_n)); - - if (!table_id_itr) { - return {}; - } - - std::unordered_set last_finkey_ids; - auto t_id = table_id_itr->id; - const auto& idx = control->db().get_index(); - for (auto itr = idx.lower_bound(boost::make_tuple(t_id, 0)); itr != idx.end() && itr->t_id == t_id; ++itr) - { - last_finkey_ids.insert(itr->primary_key); - } - - return last_finkey_ids; - } }; @@ -433,13 +409,6 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { register_finalizer_keys(producer_names, 21); BOOST_REQUIRE_EQUAL(success(), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); - // Verify last finalizer key id table contains all finalzer keys - for( auto& p : producer_names ) { - auto finalizer_info = get_finalizer_info(p); - uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( false, get_last_fin_key_info(active_finalizer_key_id).is_null() ); - } - // Produce enough blocks so transition to Savanna finishes produce_blocks(504); // 21 Producers * 12 Blocks per producer * 2 rounds to reach Legacy finality @@ -483,20 +452,8 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_no_finalizers_changed_test, fin // head_finality_data is available when nodoes is in Savanna BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); - // Verify last finalizer key id table contains all finalzer keys - auto last_finkey_ids = get_last_finkey_ids(); - for( auto& p : producer_names ) { - auto finalizer_info = get_finalizer_info(p); - uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_finalizer_key_id) ); - } - - // Produce for one round - produce_block( fc::minutes(2) ); - - // Since finalizer keys have not changed, last_finkey_ids should be the same - auto last_finkey_ids_2 = get_last_finkey_ids(); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids == last_finkey_ids_2 ); + // Let it run for awhile + produce_blocks(252); } FC_LOG_AND_RETHROW() @@ -512,38 +469,15 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finali // head_finality_data is available when nodoes is in Savanna BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); - // Verify last finalizer key id table contains all finalzer keys - auto last_finkey_ids = get_last_finkey_ids(); - for( auto& p : producer_names ) { - auto finalizer_info = get_finalizer_info(p); - uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_finalizer_key_id) ); - } - // Pick a producer name test_producer = producer_names.back(); - // Take a note of old active_finalizer_key_id - auto p_info = get_finalizer_info(test_producer); - uint64_t old_id = p_info["active_finalizer_key_id"].as_uint64(); - // Register and activate a new finalizer key BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(test_producer, finalizer_key_1, pop_1) ); BOOST_REQUIRE_EQUAL( success(), activate_finalizer_key(test_producer, finalizer_key_1)); - // Since producer is an active producer, the finalizer key change takes effective - // immediately. - auto last_finkey_ids_2 = get_last_finkey_ids(); - - // Take a note of new active_finalizer_key_id - auto p_info_2 = get_finalizer_info(test_producer); - uint64_t new_id = p_info_2["active_finalizer_key_id"].as_uint64(); - - // After replace the old_id with new_id in last_finkey_ids, - // last_finkey_ids should be the same as last_finkey_ids_2 - last_finkey_ids.erase(old_id); - last_finkey_ids.insert(new_id); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids == last_finkey_ids_2 ); + // Let it run for awhile + produce_blocks(252); } FC_LOG_AND_RETHROW() @@ -564,14 +498,6 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // head_finality_data is available when nodoes is in Savanna BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); - // Verify last finalizer key id table contains all finalzer keys - auto last_finkey_ids = get_last_finkey_ids(); - for( auto i = 0; i < 21; ++i ) { - auto finalizer_info = get_finalizer_info(producer_names[i]); - uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_finalizer_key_id) ); - } - // Test delete the first finalizer key // defproducerv registers its first finalizer key and is marked active @@ -595,17 +521,6 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // because defproducera does not have an active finalizer key produce_blocks(504); - // find new last_finkey_ids - auto last_finkey_ids_2 = get_last_finkey_ids(); - // Make sure new_id is in the new last_finkey_ids - BOOST_REQUIRE_EQUAL( true, last_finkey_ids_2.contains(producerv_id) ); - - // After replace the deleted_id with new_id in the old last_finkey_ids, - // last_finkey_ids should be the same as last_finkey_ids_2 - last_finkey_ids.erase(deleted_id); - last_finkey_ids.insert(producerv_id); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids == last_finkey_ids_2 ); - // Test delete last finalizer key // defproducerw registers its first finalizer key and is marked active @@ -620,20 +535,8 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // Delete defproducerv's finalizer key BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(producerv_name, finalizer_key_1) ); - // Wait for two rounds of producer schedule so defproducera is replaced by defproducerv - // because defproducera does not have an active finalizer key - produce_blocks(504); - - // find new last_finkey_ids - auto last_finkey_ids_3 = get_last_finkey_ids(); - // Make sure producerw_id is in the new last_finkey_ids - BOOST_REQUIRE_EQUAL( true, last_finkey_ids_3.contains(producerw_id) ); - - // After replace producerv_id wth producerw_id in the old last_finkey_ids_2, - // last_finkey_ids should be the same as last_finkey_ids_3 - last_finkey_ids_2.erase(producerv_id); - last_finkey_ids_2.insert(producerw_id); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids_2 == last_finkey_ids_3 ); + // Let it run for awhile + produce_blocks(252); } FC_LOG_AND_RETHROW() From 99ae2e3f05a485727201a91b07a62ec676f43b10 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 9 Apr 2024 21:36:57 -0400 Subject: [PATCH 77/94] Allow unregistered producers to activate and delete their finalizer keys --- .../eosio.system/include/eosio.system/eosio.system.hpp | 2 -- contracts/eosio.system/src/finalizer_key.cpp | 8 -------- tests/eosio.finalizer_key_tests.cpp | 8 -------- 3 files changed, 18 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 6af77842..43f7e040 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1284,7 +1284,6 @@ namespace eosiosystem { * @param finalizer_name - account activating `finalizer_key`, * @param finalizer_key - key to be activated. * - * @pre `finalizer_name` must be a registered producer * @pre `finalizer_key` must be a registered finalizer key in base64url format * @pre Authority of `finalizer_name` */ @@ -1299,7 +1298,6 @@ namespace eosiosystem { * @param finalizer_name - account deleting `finalizer_key`, * @param finalizer_key - key to be deleted. * - * @pre `finalizer_name` must be a registered producer * @pre `finalizer_key` must be a registered finalizer key in base64url format * @pre `finalizer_key` must not be active, unless it is the last registered finalizer key * @pre Authority of `finalizer_name` diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index ebedf47f..db0c1c6c 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -188,16 +188,12 @@ namespace eosiosystem { /* * Action to activate a finalizer key * - * @pre `finalizer_name` must be a registered producer * @pre `finalizer_key` must be a registered finalizer key in base64url format * @pre Authority of `finalizer_name` */ void system_contract::actfinkey( const name& finalizer_name, const std::string& finalizer_key ) { require_auth( finalizer_name ); - auto producer = _producers.find( finalizer_name.value ); - check( producer != _producers.end(), "finalizer " + finalizer_name.to_string() + " is not a registered producer"); - // Check finalizer has registered keys auto finalizer = _finalizers.find(finalizer_name.value); check( finalizer != _finalizers.end(), "finalizer has not registered any finalizer keys" ); @@ -241,7 +237,6 @@ namespace eosiosystem { /* * Action to delete a registered finalizer key * - * @pre `finalizer_name` must be a registered producer * @pre `finalizer_key` must be a registered finalizer key in base64url format * @pre `finalizer_key` must not be active, unless it is the last registered finalizer key * @pre Authority of `finalizer_name` @@ -249,9 +244,6 @@ namespace eosiosystem { void system_contract::delfinkey( const name& finalizer_name, const std::string& finalizer_key ) { require_auth( finalizer_name ); - auto producer = _producers.find( finalizer_name.value ); - check( producer != _producers.end(), "finalizer " + finalizer_name.to_string() + " is not a registered producer"); - // Check finalizer has registered keys auto finalizer = _finalizers.find(finalizer_name.value); check( finalizer != _finalizers.end(), "finalizer " + finalizer_name.to_string() + " has not registered any finalizer keys" ); diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 7a6ea0a9..5ff15933 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -246,10 +246,6 @@ BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_failure_tests, finalizer_key_test ("finalizer_key", finalizer_key_1 ) ) ); - // attempt to activate finalizer_key for an unregistered producer - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer alice1111111 is not a registered producer" ), - activate_finalizer_key(alice, finalizer_key_1) ); - // Register producers BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); BOOST_REQUIRE_EQUAL( success(), regproducer(bob) ); @@ -315,10 +311,6 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_failure_tests, finalizer_key_tester ("finalizer_key", finalizer_key_1 ) ) ); - // attempt to delete finalizer_key for an unregistered producer - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer alice1111111 is not a registered producer" ), - delete_finalizer_key(alice, finalizer_key_1) ); - // Register producers BOOST_REQUIRE_EQUAL( success(), regproducer(alice) ); BOOST_REQUIRE_EQUAL( success(), regproducer(bob) ); From 7f2e940ca19da8ad04e3abfb3a13ab4ba87093f3 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 10 Apr 2024 10:05:20 -0400 Subject: [PATCH 78/94] Define a customized operator == in proposed_finalizer_key_t to simplify checking finalizer policy changes --- .../include/eosio.system/eosio.system.hpp | 10 +++++++++- contracts/eosio.system/src/finalizer_key.cpp | 20 +++++-------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 43f7e040..e42da13f 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -217,8 +217,16 @@ namespace eosiosystem { uint64_t key_id; eosio::finalizer_authority fin_authority; + bool operator==(const proposed_finalizer_key_t& other) const { + // Weight and description can never be changed by a user. + // They are not considered here. + return key_id == other.key_id && + fin_authority.public_key == other.fin_authority.public_key; + }; + EOSLIB_SERIALIZE( proposed_finalizer_key_t, (key_id)(fin_authority) ) }; + struct [[eosio::table("globala"), eosio::contract("eosio.system")]] eosio_global_state_a { // name can only contain digits '1' to '5'. eosio_global_state_a() { } std::vector last_proposed_keys; // sorted by ascending finalizer key id @@ -1645,7 +1653,7 @@ namespace eosiosystem { bool is_savanna_consensus() const; void set_proposed_finalizers( const std::vector& proposed_fin_keys ); void set_proposed_finalizers_if_changed( std::vector& proposed_fin_keys ); - void set_proposed_finalizers_unsorted( std::vector& proposed_fin_keys ); + void set_proposed_finalizers_sorted( std::vector& proposed_fin_keys ); template class registration { diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index db0c1c6c..38ece17d 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -61,7 +61,7 @@ namespace eosiosystem { check( proposed_fin_keys.size() == _gstate.last_producer_schedule_size, "not enough top producers have registered finalizer keys, has " + std::to_string(proposed_fin_keys.size()) + ", require " + std::to_string(_gstate.last_producer_schedule_size) ); - set_proposed_finalizers_unsorted(proposed_fin_keys); + set_proposed_finalizers_sorted(proposed_fin_keys); check( is_savanna_consensus(), "switching to Savanna failed" ); } @@ -71,6 +71,7 @@ namespace eosiosystem { void system_contract::set_proposed_finalizers( const std::vector& proposed_fin_keys ) { // Construct finalizer authorities std::vector finalizer_authorities; + finalizer_authorities.reserve(proposed_fin_keys.size()); for( const auto& k: proposed_fin_keys ) { finalizer_authorities.emplace_back(k.fin_authority); } @@ -86,7 +87,7 @@ namespace eosiosystem { } // Sort `proposed_fin_keys` and calls set_proposed_finalizers() - void system_contract::set_proposed_finalizers_unsorted( std::vector& proposed_fin_keys ) { + void system_contract::set_proposed_finalizers_sorted( std::vector& proposed_fin_keys ) { std::sort( proposed_fin_keys.begin(), proposed_fin_keys.end(), []( const proposed_finalizer_key_t& lhs, const proposed_finalizer_key_t& rhs ) { return lhs.key_id < rhs.key_id; } ); @@ -106,20 +107,9 @@ namespace eosiosystem { return lhs.key_id < rhs.key_id; } ); - if( proposed_fin_keys.size() == _gstate_a.last_proposed_keys.size() ) { - bool new_fin_policy = false; - for( auto i = 0; i < proposed_fin_keys.size(); ++i ) { - if( proposed_fin_keys[i].key_id != _gstate_a.last_proposed_keys[i].key_id || - proposed_fin_keys[i].fin_authority.public_key != _gstate_a.last_proposed_keys[i].fin_authority.public_key ) { - new_fin_policy = true; - break; - } - } - + if( proposed_fin_keys == _gstate_a.last_proposed_keys ) { // Finalizer policy has not changed. Do not proceed. - if( !new_fin_policy ) { - return; - } + return; } set_proposed_finalizers(proposed_fin_keys); From ada26ea3b927f4f67ee50a7956ddae10a8474893 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 11 Apr 2024 13:37:50 -0400 Subject: [PATCH 79/94] Change to use a caching mechanism to store last proposed finalizers to avoid unnecessay serialization of data in system contract constructor/destructor; always check if proposed finalizers are the same as last proposed ones --- .../include/eosio.system/eosio.system.hpp | 64 ++++---- contracts/eosio.system/src/eosio.system.cpp | 4 +- contracts/eosio.system/src/finalizer_key.cpp | 140 ++++++++++-------- contracts/eosio.system/src/voting.cpp | 14 +- 4 files changed, 118 insertions(+), 104 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index e42da13f..ca8ae65e 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -211,28 +211,6 @@ namespace eosiosystem { EOSLIB_SERIALIZE( eosio_global_state5, (next_finalizer_key_id) ) }; - // Defines new global state parameter to store last proposed finalizer set. - // It is also used as an indicator Savanna consensus has been switched over. - struct proposed_finalizer_key_t { - uint64_t key_id; - eosio::finalizer_authority fin_authority; - - bool operator==(const proposed_finalizer_key_t& other) const { - // Weight and description can never be changed by a user. - // They are not considered here. - return key_id == other.key_id && - fin_authority.public_key == other.fin_authority.public_key; - }; - - EOSLIB_SERIALIZE( proposed_finalizer_key_t, (key_id)(fin_authority) ) - }; - - struct [[eosio::table("globala"), eosio::contract("eosio.system")]] eosio_global_state_a { // name can only contain digits '1' to '5'. - eosio_global_state_a() { } - std::vector last_proposed_keys; // sorted by ascending finalizer key id - - EOSLIB_SERIALIZE( eosio_global_state_a, (last_proposed_keys) ) - }; inline eosio::block_signing_authority convert_to_block_signing_authority( const eosio::public_key& producer_key ) { return eosio::block_signing_authority_v0{ .threshold = 1, .keys = {{producer_key, 1}} }; @@ -352,6 +330,35 @@ namespace eosiosystem { }; typedef eosio::multi_index< "finalizers"_n, finalizer_info > finalizers_table; + // finalizer_auth_info stores a finalizer's key id and its finalizer authority + struct finalizer_auth_info { + uint64_t key_id; // A finalizer's key ID in finalizer_keys_table + eosio::finalizer_authority fin_authority; // The finalizer's finalizer_authority + + bool operator==(const finalizer_auth_info& other) const { + // Weight and description can never be changed by a user. + // They are not considered here. + return key_id == other.key_id && + fin_authority.public_key == other.fin_authority.public_key; + }; + + EOSLIB_SERIALIZE( finalizer_auth_info, (key_id)(fin_authority) ) + }; + + // Stores information about last proposed finalizers. + // It contains only one entry. Should not continue using the global + // singleton pattern as it unnecessarily serializes data at construction + // even the data is not used. + struct [[eosio::table("lastpropfins"), eosio::contract("eosio.system")]] last_prop_finalizers_info { + std::vector last_proposed_finalizers; // sorted by ascending finalizer key id + + uint64_t primary_key()const { return 0; } + + EOSLIB_SERIALIZE( last_prop_finalizers_info, (last_proposed_finalizers) ) + }; + + typedef eosio::multi_index< "lastpropfins"_n, last_prop_finalizers_info > last_prop_finalizers_table; + // Voter info. Voter info stores information about the voter: // - `owner` the voter // - `proxy` the proxy set by the voter, if any @@ -409,8 +416,6 @@ namespace eosiosystem { typedef eosio::singleton< "global5"_n, eosio_global_state5 > global_state5_singleton; - typedef eosio::singleton< "globala"_n, eosio_global_state_a > global_state_a_singleton; - struct [[eosio::table, eosio::contract("eosio.system")]] user_resources { name owner; asset net_weight; @@ -757,18 +762,18 @@ namespace eosiosystem { producers_table2 _producers2; finalizer_keys_table _finalizer_keys; finalizers_table _finalizers; + last_prop_finalizers_table _last_prop_finalizers; + std::optional> _last_prop_finalizers_cached; global_state_singleton _global; global_state2_singleton _global2; global_state3_singleton _global3; global_state4_singleton _global4; global_state5_singleton _global5; - global_state_a_singleton _global_a; eosio_global_state _gstate; eosio_global_state2 _gstate2; eosio_global_state3 _gstate3; eosio_global_state4 _gstate4; eosio_global_state5 _gstate5; - eosio_global_state_a _gstate_a; rammarket _rammarket; rex_pool_table _rexpool; rex_return_pool_table _rexretpool; @@ -1650,10 +1655,9 @@ namespace eosiosystem { double additional_shares_delta = 0.0, double shares_rate_delta = 0.0 ); // defined in finalizer_key.cpp - bool is_savanna_consensus() const; - void set_proposed_finalizers( const std::vector& proposed_fin_keys ); - void set_proposed_finalizers_if_changed( std::vector& proposed_fin_keys ); - void set_proposed_finalizers_sorted( std::vector& proposed_fin_keys ); + bool is_savanna_consensus(); + void set_proposed_finalizers( std::vector& finalizers); + std::vector get_last_proposed_finalizers(); template class registration { diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index 6a6faef4..ed165687 100644 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -22,12 +22,12 @@ namespace eosiosystem { _producers2(get_self(), get_self().value), _finalizer_keys(get_self(), get_self().value), _finalizers(get_self(), get_self().value), + _last_prop_finalizers(get_self(), get_self().value), _global(get_self(), get_self().value), _global2(get_self(), get_self().value), _global3(get_self(), get_self().value), _global4(get_self(), get_self().value), _global5(get_self(), get_self().value), - _global_a(get_self(), get_self().value), _rammarket(get_self(), get_self().value), _rexpool(get_self(), get_self().value), _rexretpool(get_self(), get_self().value), @@ -41,7 +41,6 @@ namespace eosiosystem { _gstate3 = _global3.exists() ? _global3.get() : eosio_global_state3{}; _gstate4 = _global4.exists() ? _global4.get() : get_default_inflation_parameters(); _gstate5 = _global5.exists() ? _global5.get() : eosio_global_state5{}; - _gstate_a = _global_a.exists() ? _global_a.get() : eosio_global_state_a{}; } eosio_global_state system_contract::get_default_parameters() { @@ -69,7 +68,6 @@ namespace eosiosystem { _global3.set( _gstate3, get_self() ); _global4.set( _gstate4, get_self() ); _global5.set( _gstate5, get_self() ); - _global_a.set( _gstate_a, get_self() ); } void system_contract::setram( uint64_t max_ram_size ) { diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 38ece17d..1cec3880 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -5,16 +5,73 @@ namespace eosiosystem { // Returns true if nodeos has transitioned to Savanna (last finalizer set not empty) - bool system_contract::is_savanna_consensus() const { - return !_gstate_a.last_proposed_keys.empty(); + bool system_contract::is_savanna_consensus() { + return !get_last_proposed_finalizers().empty(); } - // Rteurns hash of finalizer_key + // Returns hash of finalizer_key static eosio::checksum256 get_finalizer_key_hash(const std::string& finalizer_key) { const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); return eosio::sha256(fin_key_g1.data(), fin_key_g1.size()); } + // This function may never fail, as it can be called by update_elected_producers, + // and in turn by onblock + // Establish finalizer policy from `proposed_fin_keys` and calls + // eosio::set_finalizers host function + void system_contract::set_proposed_finalizers( std::vector& proposed_finalizers ) { + std::sort( proposed_finalizers.begin(), proposed_finalizers.end(), []( const finalizer_auth_info& lhs, const finalizer_auth_info& rhs ) { + return lhs.key_id < rhs.key_id; + } ); + + const auto last_proposed_finalizers = get_last_proposed_finalizers(); + if( proposed_finalizers == last_proposed_finalizers ) { + // Finalizer policy has not changed. Do not proceed. + return; + } + + // Construct finalizer authorities + std::vector finalizer_authorities; + finalizer_authorities.reserve(proposed_finalizers.size()); + for( const auto& k: proposed_finalizers ) { + finalizer_authorities.emplace_back(k.fin_authority); + } + + // Establish finalizer policy + eosio::finalizer_policy fin_policy { + .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, + .finalizers = std::move(finalizer_authorities) + }; + + // call host function + eosio::set_finalizers(std::move(fin_policy)); // call host function + + // store last proposed policy in both cache and DB table + _last_prop_finalizers_cached = proposed_finalizers; + if( _last_prop_finalizers.begin() == _last_prop_finalizers.end() ) { + _last_prop_finalizers.emplace( get_self(), [&]( auto& f ) { + f.last_proposed_finalizers = proposed_finalizers; + }); + } else { + _last_prop_finalizers.modify(_last_prop_finalizers.begin(), same_payer, [&]( auto& f ) { + f.last_proposed_finalizers = proposed_finalizers; + }); + } + } + + std::vector system_contract::get_last_proposed_finalizers() { + if( !_last_prop_finalizers_cached.has_value() ) { + const auto finalizers_itr = _last_prop_finalizers.begin(); + if( finalizers_itr == _last_prop_finalizers.end() ) { + return {}; + } + + _last_prop_finalizers_cached = finalizers_itr->last_proposed_finalizers; + } + + return *_last_prop_finalizers_cached; + } + /** * Action to switch to Savanna * @@ -27,15 +84,15 @@ namespace eosiosystem { check(!is_savanna_consensus(), "switchtosvnn can be run only once"); - std::vector< proposed_finalizer_key_t > proposed_fin_keys; - proposed_fin_keys.reserve(_gstate.last_producer_schedule_size); + std::vector< finalizer_auth_info > proposed_finalizers; + proposed_finalizers.reserve(_gstate.last_producer_schedule_size); // Find a set of producers that meet all the normal requirements for // being a proposer and also have an active finalizer key. // The number of the producers must be equal to the number of producers // in the last_producer_schedule. auto idx = _producers.get_index<"prototalvote"_n>(); - for( auto it = idx.cbegin(); it != idx.cend() && proposed_fin_keys.size() < _gstate.last_producer_schedule_size && 0 < it->total_votes && it->active(); ++it ) { + for( auto it = idx.cbegin(); it != idx.cend() && proposed_finalizers.size() < _gstate.last_producer_schedule_size && 0 < it->total_votes && it->active(); ++it ) { auto finalizer = _finalizers.find( it->owner.value ); if( finalizer == _finalizers.end() ) { // The producer is not in finalizers table, indicating it does not have an @@ -48,7 +105,7 @@ namespace eosiosystem { continue; } - proposed_fin_keys.emplace_back( proposed_finalizer_key_t { + proposed_finalizers.emplace_back( finalizer_auth_info { .key_id = finalizer->active_finalizer_key_id, .fin_authority = eosio::finalizer_authority{ .description = finalizer->finalizer_name.to_string(), @@ -58,65 +115,13 @@ namespace eosiosystem { ); } - check( proposed_fin_keys.size() == _gstate.last_producer_schedule_size, - "not enough top producers have registered finalizer keys, has " + std::to_string(proposed_fin_keys.size()) + ", require " + std::to_string(_gstate.last_producer_schedule_size) ); + check( proposed_finalizers.size() == _gstate.last_producer_schedule_size, + "not enough top producers have registered finalizer keys, has " + std::to_string(proposed_finalizers.size()) + ", require " + std::to_string(_gstate.last_producer_schedule_size) ); - set_proposed_finalizers_sorted(proposed_fin_keys); + set_proposed_finalizers(proposed_finalizers); check( is_savanna_consensus(), "switching to Savanna failed" ); } - // This function may never fail, as it can be called by onblock indirectly. - // Establish finalizer policy from `proposed_fin_keys` and calls - // eosio::set_finalizers host function - void system_contract::set_proposed_finalizers( const std::vector& proposed_fin_keys ) { - // Construct finalizer authorities - std::vector finalizer_authorities; - finalizer_authorities.reserve(proposed_fin_keys.size()); - for( const auto& k: proposed_fin_keys ) { - finalizer_authorities.emplace_back(k.fin_authority); - } - - // Establish finalizer policy - eosio::finalizer_policy fin_policy { - .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, - .finalizers = std::move(finalizer_authorities) - }; - - // call host function - eosio::set_finalizers(std::move(fin_policy)); // call host function - } - - // Sort `proposed_fin_keys` and calls set_proposed_finalizers() - void system_contract::set_proposed_finalizers_sorted( std::vector& proposed_fin_keys ) { - std::sort( proposed_fin_keys.begin(), proposed_fin_keys.end(), []( const proposed_finalizer_key_t& lhs, const proposed_finalizer_key_t& rhs ) { - return lhs.key_id < rhs.key_id; - } ); - - set_proposed_finalizers(proposed_fin_keys); - - // store last proposed policy - _gstate_a.last_proposed_keys = proposed_fin_keys; - } - - // This function may never fail, as it can be called by update_elected_producers, - // and in turn by onblock - // Sort `proposed_fin_keys`. If it is the same as last proposed finalizer - // policy, do not proceed. Otherwise, call set_proposed_finalizers() - void system_contract::set_proposed_finalizers_if_changed( std::vector& proposed_fin_keys ) { - std::sort( proposed_fin_keys.begin(), proposed_fin_keys.end(), []( const proposed_finalizer_key_t& lhs, const proposed_finalizer_key_t& rhs ) { - return lhs.key_id < rhs.key_id; - } ); - - if( proposed_fin_keys == _gstate_a.last_proposed_keys ) { - // Finalizer policy has not changed. Do not proceed. - return; - } - - set_proposed_finalizers(proposed_fin_keys); - - // store last proposed policy - _gstate_a.last_proposed_keys = proposed_fin_keys; - } /* * Action to register a finalizer key @@ -210,17 +215,22 @@ namespace eosiosystem { f.active_finalizer_key_binary = finalizer_key_itr->finalizer_key_binary; }); + auto last_proposed_finalizers = get_last_proposed_finalizers(); + if( last_proposed_finalizers.empty() ) { + return; + } + // Do a binary search to see if the finalizer is in last proposed policy - auto itr = std::lower_bound(_gstate_a.last_proposed_keys.begin(), _gstate_a.last_proposed_keys.end(), prev_fin_key_id, [](const proposed_finalizer_key_t& key, uint64_t id) { + auto itr = std::lower_bound(last_proposed_finalizers.begin(), last_proposed_finalizers.end(), prev_fin_key_id, [](const finalizer_auth_info& key, uint64_t id) { return key.key_id < id; }); - if( itr != _gstate_a.last_proposed_keys.end() && itr->key_id == prev_fin_key_id ) { + if( itr != last_proposed_finalizers.end() && itr->key_id == prev_fin_key_id ) { // Replace the previous finalizer key with finalizer key just activated itr->fin_authority.public_key = finalizer_key_itr->finalizer_key_binary; // Call set_finalizers immediately - set_proposed_finalizers(_gstate_a.last_proposed_keys); + set_proposed_finalizers(last_proposed_finalizers); } } diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index d26c4897..f7401d73 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -110,12 +110,14 @@ namespace eosiosystem { using value_type = std::pair; std::vector< value_type > top_producers; - std::vector< proposed_finalizer_key_t > proposed_fin_keys; + std::vector< finalizer_auth_info > proposed_finalizers; top_producers.reserve(21); - proposed_fin_keys.reserve(21); + proposed_finalizers.reserve(21); + + bool is_savanna = is_savanna_consensus(); for( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active(); ++it ) { - if( is_savanna_consensus() ) { + if( is_savanna ) { auto finalizer = _finalizers.find( it->owner.value ); if( finalizer == _finalizers.end() ) { // The producer is not in finalizers table, indicating it does not have an @@ -128,7 +130,7 @@ namespace eosiosystem { continue; } - proposed_fin_keys.emplace_back( proposed_finalizer_key_t { + proposed_finalizers.emplace_back( finalizer_auth_info { .key_id = finalizer->active_finalizer_key_id, .fin_authority = eosio::finalizer_authority{ .description = finalizer->finalizer_name.to_string(), @@ -168,8 +170,8 @@ namespace eosiosystem { // set_proposed_finalizers() checks if last proposed finalizer policy // has not changed, it will not call set_finalizers() host function. - if( is_savanna_consensus() ) { - set_proposed_finalizers_if_changed( proposed_fin_keys ); + if( is_savanna ) { + set_proposed_finalizers( proposed_finalizers ); } } From 242de13b5c761101ed8653eefeefd961401a8fe2 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 11 Apr 2024 14:24:11 -0400 Subject: [PATCH 80/94] Use a single entry table for next finalizer key ID generator --- .../include/eosio.system/eosio.system.hpp | 38 +++++++++---------- contracts/eosio.system/src/eosio.system.cpp | 4 +- contracts/eosio.system/src/finalizer_key.cpp | 19 +++++++++- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index ca8ae65e..e8d9e151 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -199,17 +199,6 @@ namespace eosiosystem { EOSLIB_SERIALIZE( eosio_global_state4, (continuous_rate)(inflation_pay_factor)(votepay_factor) ) }; - // Defines new global state parameter to store next available - // finalizer key_id to make sure key_id in eosio_global_state_a will - // never be reused. - struct [[eosio::table("global5"), eosio::contract("eosio.system")]] eosio_global_state5 { - eosio_global_state5() { } - uint64_t get_next_finalizer_key_id() { return next_finalizer_key_id++; }; - - uint64_t next_finalizer_key_id = 0; - - EOSLIB_SERIALIZE( eosio_global_state5, (next_finalizer_key_id) ) - }; inline eosio::block_signing_authority convert_to_block_signing_authority( const eosio::public_key& producer_key ) { @@ -345,9 +334,9 @@ namespace eosiosystem { EOSLIB_SERIALIZE( finalizer_auth_info, (key_id)(fin_authority) ) }; - // Stores information about last proposed finalizers. - // It contains only one entry. Should not continue using the global - // singleton pattern as it unnecessarily serializes data at construction + // A single entry storing information about last proposed finalizers. + // Should avoid using the global singleton pattern as it unnecessarily + // serializes data at construction/desstruction of system_contract, // even the data is not used. struct [[eosio::table("lastpropfins"), eosio::contract("eosio.system")]] last_prop_finalizers_info { std::vector last_proposed_finalizers; // sorted by ascending finalizer key id @@ -357,7 +346,18 @@ namespace eosiosystem { EOSLIB_SERIALIZE( last_prop_finalizers_info, (last_proposed_finalizers) ) }; - typedef eosio::multi_index< "lastpropfins"_n, last_prop_finalizers_info > last_prop_finalizers_table; + typedef eosio::multi_index< "lastpropfins"_n, last_prop_finalizers_info > last_prop_fins_table; + + // A single entry storing next available finalizer key_id to make sure + // key_id in finalizers_table will never be reused. + struct [[eosio::table("finkeyidgen"), eosio::contract("eosio.system")]] fin_key_id_generator_info { + uint64_t next_finalizer_key_id = 0; + uint64_t primary_key()const { return 0; } + + EOSLIB_SERIALIZE( fin_key_id_generator_info, (next_finalizer_key_id) ) + }; + + typedef eosio::multi_index< "finkeyidgen"_n, fin_key_id_generator_info > fin_key_id_gen_table; // Voter info. Voter info stores information about the voter: // - `owner` the voter @@ -414,8 +414,6 @@ namespace eosiosystem { typedef eosio::singleton< "global4"_n, eosio_global_state4 > global_state4_singleton; - typedef eosio::singleton< "global5"_n, eosio_global_state5 > global_state5_singleton; - struct [[eosio::table, eosio::contract("eosio.system")]] user_resources { name owner; asset net_weight; @@ -762,18 +760,17 @@ namespace eosiosystem { producers_table2 _producers2; finalizer_keys_table _finalizer_keys; finalizers_table _finalizers; - last_prop_finalizers_table _last_prop_finalizers; + last_prop_fins_table _last_prop_finalizers; std::optional> _last_prop_finalizers_cached; + fin_key_id_gen_table _fin_key_id_generator; global_state_singleton _global; global_state2_singleton _global2; global_state3_singleton _global3; global_state4_singleton _global4; - global_state5_singleton _global5; eosio_global_state _gstate; eosio_global_state2 _gstate2; eosio_global_state3 _gstate3; eosio_global_state4 _gstate4; - eosio_global_state5 _gstate5; rammarket _rammarket; rex_pool_table _rexpool; rex_return_pool_table _rexretpool; @@ -1658,6 +1655,7 @@ namespace eosiosystem { bool is_savanna_consensus(); void set_proposed_finalizers( std::vector& finalizers); std::vector get_last_proposed_finalizers(); + uint64_t get_next_finalizer_key_id(); template class registration { diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index ed165687..feb2a1ac 100644 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -23,11 +23,11 @@ namespace eosiosystem { _finalizer_keys(get_self(), get_self().value), _finalizers(get_self(), get_self().value), _last_prop_finalizers(get_self(), get_self().value), + _fin_key_id_generator(get_self(), get_self().value), _global(get_self(), get_self().value), _global2(get_self(), get_self().value), _global3(get_self(), get_self().value), _global4(get_self(), get_self().value), - _global5(get_self(), get_self().value), _rammarket(get_self(), get_self().value), _rexpool(get_self(), get_self().value), _rexretpool(get_self(), get_self().value), @@ -40,7 +40,6 @@ namespace eosiosystem { _gstate2 = _global2.exists() ? _global2.get() : eosio_global_state2{}; _gstate3 = _global3.exists() ? _global3.get() : eosio_global_state3{}; _gstate4 = _global4.exists() ? _global4.get() : get_default_inflation_parameters(); - _gstate5 = _global5.exists() ? _global5.get() : eosio_global_state5{}; } eosio_global_state system_contract::get_default_parameters() { @@ -67,7 +66,6 @@ namespace eosiosystem { _global2.set( _gstate2, get_self() ); _global3.set( _gstate3, get_self() ); _global4.set( _gstate4, get_self() ); - _global5.set( _gstate5, get_self() ); } void system_contract::setram( uint64_t max_ram_size ) { diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 1cec3880..63ab2f9e 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -72,6 +72,23 @@ namespace eosiosystem { return *_last_prop_finalizers_cached; } + uint64_t system_contract::get_next_finalizer_key_id() { + uint64_t next_id = 0; + + if( _fin_key_id_generator.begin() == _fin_key_id_generator.end() ) { + _fin_key_id_generator.emplace( get_self(), [&]( auto& f ) { + f.next_finalizer_key_id = next_id; + }); + } else { + next_id = _fin_key_id_generator.begin()->next_finalizer_key_id + 1; + _fin_key_id_generator.modify(_fin_key_id_generator.begin(), same_payer, [&]( auto& f ) { + f.next_finalizer_key_id = next_id; + }); + } + + return next_id; + } + /** * Action to switch to Savanna * @@ -155,7 +172,7 @@ namespace eosiosystem { // Insert the finalizer key into finalyzer_keys table auto finalizer_key_itr = _finalizer_keys.emplace( finalizer_name, [&]( auto& k ) { - k.id = _gstate5.get_next_finalizer_key_id(); + k.id = get_next_finalizer_key_id(); k.finalizer_name = finalizer_name; k.finalizer_key = finalizer_key; k.finalizer_key_binary = { fin_key_g1.begin(), fin_key_g1.end() }; From 9580f2977eee9270b536df23102f895a9ba37ba4 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 11 Apr 2024 15:47:42 -0400 Subject: [PATCH 81/94] Add missing key_id update in the entry in last_proposed_finalizers for just activated finalizer key improve comments --- contracts/eosio.system/src/finalizer_key.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 63ab2f9e..6bfd1d2f 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -225,8 +225,9 @@ namespace eosiosystem { // Check if the finalizer key is not already active check( finalizer_key_itr->id != finalizer->active_finalizer_key_id, "finalizer key was already active: " + finalizer_key ); - auto prev_fin_key_id = finalizer->active_finalizer_key_id; + auto active_key_id = finalizer->active_finalizer_key_id; + // Update finalizer's information in _finalizers table _finalizers.modify( finalizer, same_payer, [&]( auto& f ) { f.active_finalizer_key_id = finalizer_key_itr->id; f.active_finalizer_key_binary = finalizer_key_itr->finalizer_key_binary; @@ -237,13 +238,17 @@ namespace eosiosystem { return; } - // Do a binary search to see if the finalizer is in last proposed policy - auto itr = std::lower_bound(last_proposed_finalizers.begin(), last_proposed_finalizers.end(), prev_fin_key_id, [](const finalizer_auth_info& key, uint64_t id) { + // Search last_proposed_finalizers for active_key_id + auto itr = std::lower_bound(last_proposed_finalizers.begin(), last_proposed_finalizers.end(), active_key_id, [](const finalizer_auth_info& key, uint64_t id) { return key.key_id < id; }); - if( itr != last_proposed_finalizers.end() && itr->key_id == prev_fin_key_id ) { - // Replace the previous finalizer key with finalizer key just activated + // If active_key_id is in last_proposed_finalizers, it means the finalizer is + // active. Replace the existing entry in last_proposed_finalizers with + // the information of finalizer_key just activated and call set_proposed_finalizers + if( itr != last_proposed_finalizers.end() && itr->key_id == active_key_id ) { + // Update last_proposed_finalizers + itr->key_id = finalizer_key_itr->id; itr->fin_authority.public_key = finalizer_key_itr->finalizer_key_binary; // Call set_finalizers immediately From c2aa777eb2b09160e7a88f1105941f4c66e9cdcc Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 11 Apr 2024 16:36:38 -0400 Subject: [PATCH 82/94] Provide a constructor for finalizer_auth_info to construct from finalizer_info --- .../include/eosio.system/eosio.system.hpp | 3 +++ contracts/eosio.system/src/finalizer_key.cpp | 17 +++++++++-------- contracts/eosio.system/src/voting.cpp | 9 +-------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index e8d9e151..96f2ad34 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -321,6 +321,9 @@ namespace eosiosystem { // finalizer_auth_info stores a finalizer's key id and its finalizer authority struct finalizer_auth_info { + finalizer_auth_info() = default; + explicit finalizer_auth_info(const finalizer_info& finalizer); + uint64_t key_id; // A finalizer's key ID in finalizer_keys_table eosio::finalizer_authority fin_authority; // The finalizer's finalizer_authority diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 6bfd1d2f..e358c45c 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -3,6 +3,14 @@ #include namespace eosiosystem { + finalizer_auth_info::finalizer_auth_info(const finalizer_info& finalizer) + : key_id(finalizer.active_finalizer_key_id) + , fin_authority( eosio::finalizer_authority{ + .description = finalizer.finalizer_name.to_string(), + .weight = 1, + .public_key = finalizer.active_finalizer_key_binary }) + { + } // Returns true if nodeos has transitioned to Savanna (last finalizer set not empty) bool system_contract::is_savanna_consensus() { @@ -122,14 +130,7 @@ namespace eosiosystem { continue; } - proposed_finalizers.emplace_back( finalizer_auth_info { - .key_id = finalizer->active_finalizer_key_id, - .fin_authority = eosio::finalizer_authority{ - .description = finalizer->finalizer_name.to_string(), - .weight = 1, - .public_key = finalizer->active_finalizer_key_binary - }} - ); + proposed_finalizers.emplace_back(*finalizer); } check( proposed_finalizers.size() == _gstate.last_producer_schedule_size, diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index f7401d73..8bc874b1 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -130,14 +130,7 @@ namespace eosiosystem { continue; } - proposed_finalizers.emplace_back( finalizer_auth_info { - .key_id = finalizer->active_finalizer_key_id, - .fin_authority = eosio::finalizer_authority{ - .description = finalizer->finalizer_name.to_string(), - .weight = 1, - .public_key = finalizer->active_finalizer_key_binary - }} - ); + proposed_finalizers.emplace_back(*finalizer); } top_producers.emplace_back( From ceda65c004bcfac8bc378e8fb9c20bdffd56e35a Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 11 Apr 2024 19:02:08 -0400 Subject: [PATCH 83/94] Factor some common code --- .../include/eosio.system/eosio.system.hpp | 1 + contracts/eosio.system/src/finalizer_key.cpp | 45 +++++++++++-------- tests/eosio.finalizer_key_tests.cpp | 2 +- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 96f2ad34..814cd931 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1659,6 +1659,7 @@ namespace eosiosystem { void set_proposed_finalizers( std::vector& finalizers); std::vector get_last_proposed_finalizers(); uint64_t get_next_finalizer_key_id(); + finalizers_table::const_iterator get_finalizer_itr( const name& finalizer_name ) const; template class registration { diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index e358c45c..3e96d4bb 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -17,10 +17,29 @@ namespace eosiosystem { return !get_last_proposed_finalizers().empty(); } - // Returns hash of finalizer_key + eosio::bls_g1 to_binary(const std::string& finalizer_key) { + check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key does not start with PUB_BLS: " + finalizer_key); + return eosio::decode_bls_public_key_to_g1(finalizer_key); + } + + // Returns hash of finalizer_key in binary format + static eosio::checksum256 get_finalizer_key_hash(const eosio::bls_g1& finalizer_key_binary) { + return eosio::sha256(finalizer_key_binary.data(), finalizer_key_binary.size()); + } + + // Returns hash of finalizer_key in text format static eosio::checksum256 get_finalizer_key_hash(const std::string& finalizer_key) { - const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); - return eosio::sha256(fin_key_g1.data(), fin_key_g1.size()); + const auto fin_key_g1 = to_binary(finalizer_key); + return get_finalizer_key_hash(fin_key_g1); + } + + finalizers_table::const_iterator system_contract::get_finalizer_itr( const name& finalizer_name ) const { + // Check finalizer has registered keys + auto finalizer_itr = _finalizers.find(finalizer_name.value); + check( finalizer_itr != _finalizers.end(), "finalizer " + finalizer_name.to_string() + " has not registered any finalizer keys" ); + check( finalizer_itr->finalizer_key_count > 0, "finalizer " + finalizer_name.to_string() + " must have at least one registered finalizer keys, has " + std::to_string(finalizer_itr->finalizer_key_count) ); + + return finalizer_itr; } // This function may never fail, as it can be called by update_elected_producers, @@ -140,7 +159,6 @@ namespace eosiosystem { check( is_savanna_consensus(), "switching to Savanna failed" ); } - /* * Action to register a finalizer key * @@ -156,16 +174,15 @@ namespace eosiosystem { check( producer != _producers.end(), "finalizer " + finalizer_name.to_string() + " is not a registered producer"); // Basic key and signature format check - check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key does not start with PUB_BLS: " + finalizer_key); check(proof_of_possession.compare(0, 7, "SIG_BLS") == 0, "proof of possession signature does not start with SIG_BLS: " + proof_of_possession); // Convert to binary form. The validity will be checked during conversion. - const auto fin_key_g1 = eosio::decode_bls_public_key_to_g1(finalizer_key); + const auto fin_key_g1 = to_binary(finalizer_key); const auto pop_g2 = eosio::decode_bls_signature_to_g2(proof_of_possession); // Duplication check across all registered keys auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); - auto hash = eosio::sha256(fin_key_g1.data(), fin_key_g1.size()); + auto hash = get_finalizer_key_hash(fin_key_g1); check(idx.find(hash) == idx.end(), "duplicate finalizer key: " + finalizer_key); // Proof of possession check @@ -207,12 +224,7 @@ namespace eosiosystem { void system_contract::actfinkey( const name& finalizer_name, const std::string& finalizer_key ) { require_auth( finalizer_name ); - // Check finalizer has registered keys - auto finalizer = _finalizers.find(finalizer_name.value); - check( finalizer != _finalizers.end(), "finalizer has not registered any finalizer keys" ); - - // Basic format check - check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key does not start with PUB_BLS: " + finalizer_key); + auto finalizer = get_finalizer_itr(finalizer_name); // Check the key is registered auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); @@ -267,12 +279,7 @@ namespace eosiosystem { void system_contract::delfinkey( const name& finalizer_name, const std::string& finalizer_key ) { require_auth( finalizer_name ); - // Check finalizer has registered keys - auto finalizer = _finalizers.find(finalizer_name.value); - check( finalizer != _finalizers.end(), "finalizer " + finalizer_name.to_string() + " has not registered any finalizer keys" ); - check( finalizer->finalizer_key_count > 0, "finalizer " + finalizer_name.to_string() + " must have at least one registered finalizer keys, has " + std::to_string(finalizer->finalizer_key_count) ); - - check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key does not start with PUB_BLS: " + finalizer_key); + auto finalizer = get_finalizer_itr(finalizer_name); // Check the key is registered auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 5ff15933..b42e6bc9 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -251,7 +251,7 @@ BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_failure_tests, finalizer_key_test BOOST_REQUIRE_EQUAL( success(), regproducer(bob) ); // finalizer has not registered any finalizer keys yet. - BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer has not registered any finalizer keys" ), + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "finalizer alice1111111 has not registered any finalizer keys" ), activate_finalizer_key(alice, finalizer_key_1) ); // Alice registers a finalizer key From 8c72d6031abddcea9f1f353bcc1b98d487f3aab5 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 11 Apr 2024 21:44:40 -0400 Subject: [PATCH 84/94] Restore last proposed finalizers checks in tests --- tests/eosio.finalizer_key_tests.cpp | 135 ++++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 6 deletions(-) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index b42e6bc9..1cae8968 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -9,6 +9,25 @@ struct key_pair_t { std::string pop; }; +// Those are needed to unpack last_prop_finalizers_info +struct finalizer_authority_t { + std::string description; + uint64_t weight = 0; + std::vector public_key; +}; +FC_REFLECT(finalizer_authority_t, (description)(weight)(public_key)) + +struct finalizer_auth_info { + uint64_t key_id; + finalizer_authority_t fin_authority; +}; +FC_REFLECT(finalizer_auth_info, (key_id)(fin_authority)) + +struct last_prop_finalizers_info { + std::vector last_proposed_finalizers; +}; +FC_REFLECT(last_prop_finalizers_info, (last_proposed_finalizers)) + struct finalizer_key_tester : eosio_system_tester { static const std::vector key_pair; @@ -22,6 +41,36 @@ struct finalizer_key_tester : eosio_system_tester { return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "finalizer_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } + std::unordered_set get_last_prop_fin_ids() { + const auto* table_id_itr = control->db().find( + boost::make_tuple(config::system_account_name, config::system_account_name, "lastpropfins"_n)); + + if (!table_id_itr) { + return {}; + } + + auto t_id = table_id_itr->id; + const auto& idx = control->db().get_index(); + + if( idx.begin() == idx.end() ) { + return {}; + } + + vector data; + auto itr = idx.lower_bound( boost::make_tuple( t_id, 0 ) ); + data.resize( itr->value.size() ); + memcpy( data.data(), itr->value.data(), data.size() ); + fc::variant fins_info = data.empty() ? fc::variant() : abi_ser.binary_to_variant( "last_prop_finalizers_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); + std::vector finalizers = fins_info["last_proposed_finalizers"].as>(); + + std::unordered_set last_prop_fin_ids; + for(auto f: finalizers) { + last_prop_fin_ids.insert(f.key_id); + } + + return last_prop_fin_ids; + }; + action_result register_finalizer_key( const account_name& act, const std::string& finalizer_key, const std::string& pop ) { return push_action( act, "regfinkey"_n, mvo() ("finalizer_name", act) @@ -401,6 +450,14 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { register_finalizer_keys(producer_names, 21); BOOST_REQUIRE_EQUAL(success(), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); + // Verify last proposed finalizer IDs contains active ID of each finalizer + auto last_proposed_finalizer_ids = get_last_prop_fin_ids(); + for( auto& p : producer_names ) { + auto finalizer_info = get_finalizer_info(p); + uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( true, last_proposed_finalizer_ids.contains(active_finalizer_key_id) ); + } + // Produce enough blocks so transition to Savanna finishes produce_blocks(504); // 21 Producers * 12 Blocks per producer * 2 rounds to reach Legacy finality @@ -444,8 +501,20 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_no_finalizers_changed_test, fin // head_finality_data is available when nodoes is in Savanna BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); - // Let it run for awhile - produce_blocks(252); + // Verify last finalizer key id table contains all finalzer keys + auto last_finkey_ids = get_last_prop_fin_ids(); + for( auto& p : producer_names ) { + auto finalizer_info = get_finalizer_info(p); + uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_finalizer_key_id) ); + } + + // Produce for one round + produce_block( fc::minutes(2) ); + + // Since finalizer keys have not changed, last_finkey_ids should be the same + auto last_finkey_ids_2 = get_last_prop_fin_ids(); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids == last_finkey_ids_2 ); } FC_LOG_AND_RETHROW() @@ -461,15 +530,38 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finali // head_finality_data is available when nodoes is in Savanna BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); + // Verify last finalizer key id table contains all finalzer keys + auto last_finkey_ids = get_last_prop_fin_ids(); + for( auto& p : producer_names ) { + auto finalizer_info = get_finalizer_info(p); + uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_finalizer_key_id) ); + } + // Pick a producer name test_producer = producer_names.back(); + // Take a note of old active_finalizer_key_id + auto p_info = get_finalizer_info(test_producer); + uint64_t old_id = p_info["active_finalizer_key_id"].as_uint64(); + // Register and activate a new finalizer key BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(test_producer, finalizer_key_1, pop_1) ); BOOST_REQUIRE_EQUAL( success(), activate_finalizer_key(test_producer, finalizer_key_1)); - // Let it run for awhile - produce_blocks(252); + // Since producer is an active producer, the finalizer key change takes effective + // immediately. + auto last_finkey_ids_2 = get_last_prop_fin_ids(); + + // Take a note of new active_finalizer_key_id + auto p_info_2 = get_finalizer_info(test_producer); + uint64_t new_id = p_info_2["active_finalizer_key_id"].as_uint64(); + + // After replace the old_id with new_id in last_finkey_ids, + // last_finkey_ids should be the same as last_finkey_ids_2 + last_finkey_ids.erase(old_id); + last_finkey_ids.insert(new_id); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids == last_finkey_ids_2 ); } FC_LOG_AND_RETHROW() @@ -490,6 +582,14 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // head_finality_data is available when nodoes is in Savanna BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); + // Verify last finalizer key id table contains all finalzer keys + auto last_finkey_ids = get_last_prop_fin_ids(); + for( auto i = 0; i < 21; ++i ) { + auto finalizer_info = get_finalizer_info(producer_names[i]); + uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_finalizer_key_id) ); + } + // Test delete the first finalizer key // defproducerv registers its first finalizer key and is marked active @@ -513,6 +613,17 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // because defproducera does not have an active finalizer key produce_blocks(504); + // find new last_finkey_ids + auto last_finkey_ids_2 = get_last_prop_fin_ids(); + // Make sure new_id is in the new last_finkey_ids + BOOST_REQUIRE_EQUAL( true, last_finkey_ids_2.contains(producerv_id) ); + + // After replace the deleted_id with new_id in the old last_finkey_ids, + // last_finkey_ids should be the same as last_finkey_ids_2 + last_finkey_ids.erase(deleted_id); + last_finkey_ids.insert(producerv_id); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids == last_finkey_ids_2 ); + // Test delete last finalizer key // defproducerw registers its first finalizer key and is marked active @@ -527,8 +638,20 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // Delete defproducerv's finalizer key BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(producerv_name, finalizer_key_1) ); - // Let it run for awhile - produce_blocks(252); + // Wait for two rounds of producer schedule so defproducera is replaced by defproducerv + // because defproducera does not have an active finalizer key + produce_blocks(504); + + // find new last_finkey_ids + auto last_finkey_ids_3 = get_last_prop_fin_ids(); + // Make sure producerw_id is in the new last_finkey_ids + BOOST_REQUIRE_EQUAL( true, last_finkey_ids_3.contains(producerw_id) ); + + // After replace producerv_id wth producerw_id in the old last_finkey_ids_2, + // last_finkey_ids should be the same as last_finkey_ids_3 + last_finkey_ids_2.erase(producerv_id); + last_finkey_ids_2.insert(producerw_id); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids_2 == last_finkey_ids_3 ); } FC_LOG_AND_RETHROW() From f9d72e342bfec2fa4e340c21eebd8e79f1c5e773 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 11 Apr 2024 22:00:51 -0400 Subject: [PATCH 85/94] Add a test to activate 3 keys of a finalizer in a row --- tests/eosio.finalizer_key_tests.cpp | 63 +++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 1cae8968..b2e6848a 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -471,6 +471,69 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { } FC_LOG_AND_RETHROW() +// Activate 3 keys after transition to Savanna +BOOST_FIXTURE_TEST_CASE(multi_activation_tests, finalizer_key_tester) try { + // Register and vote 26 producers + auto producer_names = active_and_vote_producers(); + // Register 21 finalizer keys for the first 21 producers + register_finalizer_keys(producer_names, 21); + BOOST_REQUIRE_EQUAL(success(), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); + + // Verify last proposed finalizer IDs contains active ID of each finalizer + auto last_proposed_finalizer_ids = get_last_prop_fin_ids(); + for( auto& p : producer_names ) { + auto finalizer_info = get_finalizer_info(p); + uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( true, last_proposed_finalizer_ids.contains(active_finalizer_key_id) ); + } + + // Produce enough blocks so transition to Savanna finishes + produce_blocks(504); // 21 Producers * 12 Blocks per producer * 2 rounds to reach Legacy finality + + // If head_finality_data has value, it means we are at least after or on + // Savanna Genesis Block + BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); + + // Register two more key for defproducera + account_name producera = "defproducera"_n; + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(producera, finalizer_key_1, pop_1) ); + BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(producera, finalizer_key_2, pop_2) ); + + auto producera_info = get_finalizer_info(producera); + auto active_key_id_before = producera_info["active_finalizer_key_id"].as_uint64(); + auto last_prop_fin_ids_before = get_last_prop_fin_ids(); + + // Activate finalizer_key_1 + BOOST_REQUIRE_EQUAL( success(), activate_finalizer_key(producera, finalizer_key_1) ); + produce_block(); + + // Make sure last proposed finalizers set has changed + producera_info = get_finalizer_info(producera); + auto active_key_id_after = producera_info["active_finalizer_key_id"].as_uint64(); + auto last_prop_fin_ids_after = get_last_prop_fin_ids(); + + last_prop_fin_ids_before.erase(active_key_id_before); + last_prop_fin_ids_before.insert(active_key_id_after); + BOOST_REQUIRE_EQUAL( true, last_prop_fin_ids_before == last_prop_fin_ids_after ); + + // Activate finalizer_key_2 + last_prop_fin_ids_before = last_prop_fin_ids_after; + active_key_id_before = active_key_id_after; + + BOOST_REQUIRE_EQUAL( success(), activate_finalizer_key(producera, finalizer_key_2) ); + produce_block(); + + // Make sure last proposed finalizers set has changed + producera_info = get_finalizer_info(producera); + active_key_id_after = producera_info["active_finalizer_key_id"].as_uint64(); + last_prop_fin_ids_after = get_last_prop_fin_ids(); + + last_prop_fin_ids_before.erase(active_key_id_before); + last_prop_fin_ids_before.insert(active_key_id_after); + BOOST_REQUIRE_EQUAL( true, last_prop_fin_ids_before == last_prop_fin_ids_after ); +} +FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE(switchtosvnn_missing_authority_tests, finalizer_key_tester) try { BOOST_REQUIRE_EQUAL( error( "missing authority of eosio" ), push_action( alice, "switchtosvnn"_n, mvo()) ); From a0acd15cb77001b0da02d6e5af28b4cf0fe7fad9 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 12 Apr 2024 08:10:30 -0400 Subject: [PATCH 86/94] Make get_last_proposed_finalizers() return a const& and avoid table lookup when it does not have a valuein subsequent calls --- .../eosio.system/include/eosio.system/eosio.system.hpp | 2 +- contracts/eosio.system/src/finalizer_key.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 814cd931..d8d703ba 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1657,7 +1657,7 @@ namespace eosiosystem { // defined in finalizer_key.cpp bool is_savanna_consensus(); void set_proposed_finalizers( std::vector& finalizers); - std::vector get_last_proposed_finalizers(); + const std::vector& get_last_proposed_finalizers(); uint64_t get_next_finalizer_key_id(); finalizers_table::const_iterator get_finalizer_itr( const name& finalizer_name ) const; diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 3e96d4bb..68768f0d 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -86,14 +86,14 @@ namespace eosiosystem { } } - std::vector system_contract::get_last_proposed_finalizers() { + const std::vector& system_contract::get_last_proposed_finalizers() { if( !_last_prop_finalizers_cached.has_value() ) { const auto finalizers_itr = _last_prop_finalizers.begin(); if( finalizers_itr == _last_prop_finalizers.end() ) { - return {}; + _last_prop_finalizers_cached = {}; + } else { + _last_prop_finalizers_cached = finalizers_itr->last_proposed_finalizers; } - - _last_prop_finalizers_cached = finalizers_itr->last_proposed_finalizers; } return *_last_prop_finalizers_cached; From 7a0f1e102b2b182e5c7c7e84ab300ac4a7dd0248 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 12 Apr 2024 08:23:28 -0400 Subject: [PATCH 87/94] Store _fin_key_id_generator.begin() in a variable to avoid multiple redundant calls --- contracts/eosio.system/src/finalizer_key.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 68768f0d..16ca2dc4 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -101,14 +101,15 @@ namespace eosiosystem { uint64_t system_contract::get_next_finalizer_key_id() { uint64_t next_id = 0; + auto itr = _fin_key_id_generator.begin(); - if( _fin_key_id_generator.begin() == _fin_key_id_generator.end() ) { + if( itr == _fin_key_id_generator.end() ) { _fin_key_id_generator.emplace( get_self(), [&]( auto& f ) { f.next_finalizer_key_id = next_id; }); } else { - next_id = _fin_key_id_generator.begin()->next_finalizer_key_id + 1; - _fin_key_id_generator.modify(_fin_key_id_generator.begin(), same_payer, [&]( auto& f ) { + next_id = itr->next_finalizer_key_id + 1; + _fin_key_id_generator.modify(itr, same_payer, [&]( auto& f ) { f.next_finalizer_key_id = next_id; }); } From b1f0a818ae90afaba55ca36fbdd3371c727958d6 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 12 Apr 2024 08:44:03 -0400 Subject: [PATCH 88/94] Make set_proposed_finalizers argument a call-by-value --- .../eosio.system/include/eosio.system/eosio.system.hpp | 2 +- contracts/eosio.system/src/finalizer_key.cpp | 6 +++--- contracts/eosio.system/src/voting.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index d8d703ba..32d599c7 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1656,7 +1656,7 @@ namespace eosiosystem { // defined in finalizer_key.cpp bool is_savanna_consensus(); - void set_proposed_finalizers( std::vector& finalizers); + void set_proposed_finalizers( std::vector finalizers ); const std::vector& get_last_proposed_finalizers(); uint64_t get_next_finalizer_key_id(); finalizers_table::const_iterator get_finalizer_itr( const name& finalizer_name ) const; diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 16ca2dc4..e00551d5 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -46,12 +46,12 @@ namespace eosiosystem { // and in turn by onblock // Establish finalizer policy from `proposed_fin_keys` and calls // eosio::set_finalizers host function - void system_contract::set_proposed_finalizers( std::vector& proposed_finalizers ) { + void system_contract::set_proposed_finalizers( std::vector proposed_finalizers ) { std::sort( proposed_finalizers.begin(), proposed_finalizers.end(), []( const finalizer_auth_info& lhs, const finalizer_auth_info& rhs ) { return lhs.key_id < rhs.key_id; } ); - const auto last_proposed_finalizers = get_last_proposed_finalizers(); + const auto& last_proposed_finalizers = get_last_proposed_finalizers(); if( proposed_finalizers == last_proposed_finalizers ) { // Finalizer policy has not changed. Do not proceed. return; @@ -156,7 +156,7 @@ namespace eosiosystem { check( proposed_finalizers.size() == _gstate.last_producer_schedule_size, "not enough top producers have registered finalizer keys, has " + std::to_string(proposed_finalizers.size()) + ", require " + std::to_string(_gstate.last_producer_schedule_size) ); - set_proposed_finalizers(proposed_finalizers); + set_proposed_finalizers(std::move(proposed_finalizers)); check( is_savanna_consensus(), "switching to Savanna failed" ); } diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index 8bc874b1..388e54c5 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -164,7 +164,7 @@ namespace eosiosystem { // set_proposed_finalizers() checks if last proposed finalizer policy // has not changed, it will not call set_finalizers() host function. if( is_savanna ) { - set_proposed_finalizers( proposed_finalizers ); + set_proposed_finalizers( std::move(proposed_finalizers) ); } } From 65a54a4d88ee294836fb047ab0a4a19a98f33435 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 12 Apr 2024 09:00:58 -0400 Subject: [PATCH 89/94] Small changes from comments --- contracts/eosio.system/src/finalizer_key.cpp | 29 +++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index e00551d5..cb32850a 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -74,16 +74,23 @@ namespace eosiosystem { eosio::set_finalizers(std::move(fin_policy)); // call host function // store last proposed policy in both cache and DB table - _last_prop_finalizers_cached = proposed_finalizers; - if( _last_prop_finalizers.begin() == _last_prop_finalizers.end() ) { + auto itr = _last_prop_finalizers.begin(); + if( itr == _last_prop_finalizers.end() ) { _last_prop_finalizers.emplace( get_self(), [&]( auto& f ) { f.last_proposed_finalizers = proposed_finalizers; }); } else { - _last_prop_finalizers.modify(_last_prop_finalizers.begin(), same_payer, [&]( auto& f ) { + _last_prop_finalizers.modify(itr, same_payer, [&]( auto& f ) { f.last_proposed_finalizers = proposed_finalizers; }); } + // Ensure not invalidate anyone holding the references to the vector + // that was returned earlier by get_last_proposed_finalizer + if (_last_prop_finalizers_cached.has_value()) { + std::swap(*_last_prop_finalizers_cached, proposed_finalizers); + } else { + _last_prop_finalizers_cached.emplace(std::move(proposed_finalizers)); + } } const std::vector& system_contract::get_last_proposed_finalizers() { @@ -247,7 +254,7 @@ namespace eosiosystem { f.active_finalizer_key_binary = finalizer_key_itr->finalizer_key_binary; }); - auto last_proposed_finalizers = get_last_proposed_finalizers(); + const auto& last_proposed_finalizers = get_last_proposed_finalizers(); if( last_proposed_finalizers.empty() ) { return; } @@ -259,14 +266,16 @@ namespace eosiosystem { // If active_key_id is in last_proposed_finalizers, it means the finalizer is // active. Replace the existing entry in last_proposed_finalizers with - // the information of finalizer_key just activated and call set_proposed_finalizers + // the information of finalizer_key just activated and call + // set_proposed_finalizers immediately if( itr != last_proposed_finalizers.end() && itr->key_id == active_key_id ) { - // Update last_proposed_finalizers - itr->key_id = finalizer_key_itr->id; - itr->fin_authority.public_key = finalizer_key_itr->finalizer_key_binary; + auto proposed_finalizers = last_proposed_finalizers; + auto& matching_entry = proposed_finalizers[itr - last_proposed_finalizers.begin()]; + + matching_entry.key_id = finalizer_key_itr->id; + matching_entry.fin_authority.public_key = finalizer_key_itr->finalizer_key_binary; - // Call set_finalizers immediately - set_proposed_finalizers(last_proposed_finalizers); + set_proposed_finalizers(std::move(proposed_finalizers)); } } From be797529a2525bf8e54d83be52a348d2de6bdf55 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 12 Apr 2024 10:27:52 -0400 Subject: [PATCH 90/94] Rename active_finalizer_key_id to active_key_id and active_finalizer_key_binary to active_key_binary for shorter names --- .../include/eosio.system/eosio.system.hpp | 8 +- contracts/eosio.system/src/finalizer_key.cpp | 24 +++--- contracts/eosio.system/src/voting.cpp | 2 +- tests/eosio.finalizer_key_tests.cpp | 78 +++++++++---------- 4 files changed, 56 insertions(+), 56 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 32d599c7..05c357cc 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -310,10 +310,10 @@ namespace eosiosystem { // finalizer_info stores information about a finalizer. struct [[eosio::table("finalizers"), eosio::contract("eosio.system")]] finalizer_info { - name finalizer_name; // finalizer's name - uint64_t active_finalizer_key_id; // finalizer's active finalizer key's id in finalizer_keys_table, for fast finding key information - std::vector active_finalizer_key_binary; // finalizer's active finalizer key's binary format in Affine little endian non-montgomery g1 - uint32_t finalizer_key_count = 0; // number of finalizer keys registered by this finalizer + name finalizer_name; // finalizer's name + uint64_t active_key_id; // finalizer's active finalizer key's id in finalizer_keys_table, for fast finding key information + std::vector active_key_binary; // finalizer's active finalizer key's binary format in Affine little endian non-montgomery g1 + uint32_t finalizer_key_count = 0; // number of finalizer keys registered by this finalizer uint64_t primary_key() const { return finalizer_name.value; } }; diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index cb32850a..d3929dd3 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -4,11 +4,11 @@ namespace eosiosystem { finalizer_auth_info::finalizer_auth_info(const finalizer_info& finalizer) - : key_id(finalizer.active_finalizer_key_id) + : key_id(finalizer.active_key_id) , fin_authority( eosio::finalizer_authority{ .description = finalizer.finalizer_name.to_string(), .weight = 1, - .public_key = finalizer.active_finalizer_key_binary }) + .public_key = finalizer.active_key_binary }) { } @@ -153,7 +153,7 @@ namespace eosiosystem { } // This should never happen. Double check the finalizer has an active key just in case - if( finalizer->active_finalizer_key_binary.empty() ) { + if( finalizer->active_key_binary.empty() ) { continue; } @@ -210,10 +210,10 @@ namespace eosiosystem { // This is the first time the finalizer registering a finalizer key, // mark the key active _finalizers.emplace( finalizer_name, [&]( auto& f ) { - f.finalizer_name = finalizer_name; - f.active_finalizer_key_id = finalizer_key_itr->id; - f.active_finalizer_key_binary = finalizer_key_itr->finalizer_key_binary; - f.finalizer_key_count = 1; + f.finalizer_name = finalizer_name; + f.active_key_id = finalizer_key_itr->id; + f.active_key_binary = finalizer_key_itr->finalizer_key_binary; + f.finalizer_key_count = 1; }); } else { // Update finalizer_key_count @@ -244,14 +244,14 @@ namespace eosiosystem { check(finalizer_key_itr->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer: " + finalizer_key); // Check if the finalizer key is not already active - check( finalizer_key_itr->id != finalizer->active_finalizer_key_id, "finalizer key was already active: " + finalizer_key ); + check( finalizer_key_itr->id != finalizer->active_key_id, "finalizer key was already active: " + finalizer_key ); - auto active_key_id = finalizer->active_finalizer_key_id; + auto active_key_id = finalizer->active_key_id; // Update finalizer's information in _finalizers table _finalizers.modify( finalizer, same_payer, [&]( auto& f ) { - f.active_finalizer_key_id = finalizer_key_itr->id; - f.active_finalizer_key_binary = finalizer_key_itr->finalizer_key_binary; + f.active_key_id = finalizer_key_itr->id; + f.active_key_binary = finalizer_key_itr->finalizer_key_binary; }); const auto& last_proposed_finalizers = get_last_proposed_finalizers(); @@ -300,7 +300,7 @@ namespace eosiosystem { // Check the key belongs to the finalizer check(fin_key_itr->finalizer_name == name(finalizer_name), "finalizer key " + finalizer_key + " was not registered by the finalizer " + finalizer_name.to_string() ); - if( fin_key_itr->id == finalizer->active_finalizer_key_id ) { + if( fin_key_itr->id == finalizer->active_key_id ) { check( finalizer->finalizer_key_count == 1, "cannot delete an active key unless it is the last registered finalizer key, has " + std::to_string(finalizer->finalizer_key_count) + " keys"); } diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index 388e54c5..3636a575 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -126,7 +126,7 @@ namespace eosiosystem { } // This should never happen. Double check just in case - if( finalizer->active_finalizer_key_binary.empty() ) { + if( finalizer->active_key_binary.empty() ) { continue; } diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index b2e6848a..0a70fd68 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -208,11 +208,11 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_same_finalizer_tests, finalize auto alice_info = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( "alice1111111", alice_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( 1, alice_info["finalizer_key_count"].as_uint64() ); - BOOST_REQUIRE_EQUAL( finalizer_key_binary_1, alice_info["active_finalizer_key_binary"].as_string() ); + BOOST_REQUIRE_EQUAL( finalizer_key_binary_1, alice_info["active_key_binary"].as_string() ); // Cross check finalizer keys table - uint64_t active_finalizer_key_id = alice_info["active_finalizer_key_id"].as_uint64(); - auto fin_key_info = get_finalizer_key_info(active_finalizer_key_id); + uint64_t active_key_id = alice_info["active_key_id"].as_uint64(); + auto fin_key_info = get_finalizer_key_info(active_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", fin_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_1, fin_key_info["finalizer_key"].as_string() ); @@ -221,7 +221,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_same_finalizer_tests, finalize alice_info = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( 2, alice_info["finalizer_key_count"].as_uint64() ); // count incremented by 1 - BOOST_REQUIRE_EQUAL( active_finalizer_key_id, alice_info["active_finalizer_key_id"].as_uint64() ); // active key should not change + BOOST_REQUIRE_EQUAL( active_key_id, alice_info["active_key_id"].as_uint64() ); // active key should not change } FC_LOG_AND_RETHROW() // register_finalizer_key_by_same_finalizer_tests @@ -256,7 +256,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_different_finalizers_tests, fi auto alice_info = get_finalizer_info(alice); BOOST_REQUIRE_EQUAL( "alice1111111", alice_info["finalizer_name"].as_string() ); - BOOST_REQUIRE_EQUAL( finalizer_key_binary_1, alice_info["active_finalizer_key_binary"].as_string() ); + BOOST_REQUIRE_EQUAL( finalizer_key_binary_1, alice_info["active_key_binary"].as_string() ); BOOST_REQUIRE_EQUAL( 2, alice_info["finalizer_key_count"].as_uint64() ); // bob111111111 registers another finalizer key @@ -265,7 +265,7 @@ BOOST_FIXTURE_TEST_CASE(register_finalizer_key_by_different_finalizers_tests, fi auto bob_info = get_finalizer_info(bob); BOOST_REQUIRE_EQUAL( 2, bob_info["finalizer_key_count"].as_uint64() ); - BOOST_REQUIRE_EQUAL( finalizer_key_binary_3, bob_info["active_finalizer_key_binary"].as_string() ); + BOOST_REQUIRE_EQUAL( finalizer_key_binary_3, bob_info["active_key_binary"].as_string() ); } FC_LOG_AND_RETHROW() // register_finalizer_key_by_different_finalizers_tests @@ -332,8 +332,8 @@ BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_success_tests, finalizer_key_test // Check finalizer_key_1 is the active key auto alice_info = get_finalizer_info(alice); - uint64_t active_finalizer_key_id = alice_info["active_finalizer_key_id"].as_uint64(); - auto finalizer_key_info = get_finalizer_key_info(active_finalizer_key_id); + uint64_t active_key_id = alice_info["active_key_id"].as_uint64(); + auto finalizer_key_info = get_finalizer_key_info(active_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_1, finalizer_key_info["finalizer_key"].as_string() ); @@ -342,13 +342,13 @@ BOOST_FIXTURE_TEST_CASE(activate_finalizer_key_success_tests, finalizer_key_test // Check finalizer_key_2 is the active key alice_info = get_finalizer_info(alice); - active_finalizer_key_id = alice_info["active_finalizer_key_id"].as_uint64(); - finalizer_key_info = get_finalizer_key_info(active_finalizer_key_id); + active_key_id = alice_info["active_key_id"].as_uint64(); + finalizer_key_info = get_finalizer_key_info(active_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_2, finalizer_key_info["finalizer_key"].as_string() ); - // Make sure active_finalizer_key_binary is correct. This test is important. - BOOST_REQUIRE_EQUAL( finalizer_key_binary_2, alice_info["active_finalizer_key_binary"].as_string() ); + // Make sure active_key_binary is correct. This test is important. + BOOST_REQUIRE_EQUAL( finalizer_key_binary_2, alice_info["active_key_binary"].as_string() ); } FC_LOG_AND_RETHROW() // activate_finalizer_key_success_tests @@ -383,8 +383,8 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_failure_tests, finalizer_key_tester // Make sure finalizer_key_2 is Bob's active finalizer key and Bob has 2 keys auto bob_info = get_finalizer_info(bob); - uint64_t active_finalizer_key_id = bob_info["active_finalizer_key_id"].as_uint64(); - auto finalizer_key_info = get_finalizer_key_info(active_finalizer_key_id); + uint64_t active_key_id = bob_info["active_key_id"].as_uint64(); + auto finalizer_key_info = get_finalizer_key_info(active_key_id); BOOST_REQUIRE_EQUAL( finalizer_key_2, finalizer_key_info["finalizer_key"].as_string() ); BOOST_REQUIRE_EQUAL( 2, bob_info["finalizer_key_count"].as_uint64() ); @@ -405,9 +405,9 @@ BOOST_FIXTURE_TEST_CASE(delete_finalizer_key_success_test, finalizer_key_tester) // Check finalizer_key_1 is the active key auto alice_info = get_finalizer_info(alice); - uint64_t active_finalizer_key_id = alice_info["active_finalizer_key_id"].as_uint64(); + uint64_t active_key_id = alice_info["active_key_id"].as_uint64(); auto finalizer_key_count_before = alice_info["finalizer_key_count"].as_uint64(); - auto finalizer_key_info = get_finalizer_key_info(active_finalizer_key_id); + auto finalizer_key_info = get_finalizer_key_info(active_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_1, finalizer_key_info["finalizer_key"].as_string() ); @@ -429,8 +429,8 @@ BOOST_FIXTURE_TEST_CASE(delete_last_finalizer_key_test, finalizer_key_tester) tr // Check finalizer_key_1 is the active key auto alice_info = get_finalizer_info(alice); - uint64_t active_finalizer_key_id = alice_info["active_finalizer_key_id"].as_uint64(); - auto finalizer_key_info = get_finalizer_key_info(active_finalizer_key_id); + uint64_t active_key_id = alice_info["active_key_id"].as_uint64(); + auto finalizer_key_info = get_finalizer_key_info(active_key_id); BOOST_REQUIRE_EQUAL( "alice1111111", finalizer_key_info["finalizer_name"].as_string() ); BOOST_REQUIRE_EQUAL( finalizer_key_1, finalizer_key_info["finalizer_key"].as_string() ); @@ -438,7 +438,7 @@ BOOST_FIXTURE_TEST_CASE(delete_last_finalizer_key_test, finalizer_key_tester) tr BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(alice, finalizer_key_1) ); // Both finalizer_key_1 and alice should be removed from finalizers and finalizer_keys tables - BOOST_REQUIRE_EQUAL( true, get_finalizer_key_info(active_finalizer_key_id).is_null() ); + BOOST_REQUIRE_EQUAL( true, get_finalizer_key_info(active_key_id).is_null() ); BOOST_REQUIRE_EQUAL( true, get_finalizer_info(alice).is_null() ); } FC_LOG_AND_RETHROW() // delete_last_finalizer_key_test @@ -454,8 +454,8 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { auto last_proposed_finalizer_ids = get_last_prop_fin_ids(); for( auto& p : producer_names ) { auto finalizer_info = get_finalizer_info(p); - uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_proposed_finalizer_ids.contains(active_finalizer_key_id) ); + uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( true, last_proposed_finalizer_ids.contains(active_key_id) ); } // Produce enough blocks so transition to Savanna finishes @@ -483,8 +483,8 @@ BOOST_FIXTURE_TEST_CASE(multi_activation_tests, finalizer_key_tester) try { auto last_proposed_finalizer_ids = get_last_prop_fin_ids(); for( auto& p : producer_names ) { auto finalizer_info = get_finalizer_info(p); - uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_proposed_finalizer_ids.contains(active_finalizer_key_id) ); + uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( true, last_proposed_finalizer_ids.contains(active_key_id) ); } // Produce enough blocks so transition to Savanna finishes @@ -500,7 +500,7 @@ BOOST_FIXTURE_TEST_CASE(multi_activation_tests, finalizer_key_tester) try { BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(producera, finalizer_key_2, pop_2) ); auto producera_info = get_finalizer_info(producera); - auto active_key_id_before = producera_info["active_finalizer_key_id"].as_uint64(); + auto active_key_id_before = producera_info["active_key_id"].as_uint64(); auto last_prop_fin_ids_before = get_last_prop_fin_ids(); // Activate finalizer_key_1 @@ -509,7 +509,7 @@ BOOST_FIXTURE_TEST_CASE(multi_activation_tests, finalizer_key_tester) try { // Make sure last proposed finalizers set has changed producera_info = get_finalizer_info(producera); - auto active_key_id_after = producera_info["active_finalizer_key_id"].as_uint64(); + auto active_key_id_after = producera_info["active_key_id"].as_uint64(); auto last_prop_fin_ids_after = get_last_prop_fin_ids(); last_prop_fin_ids_before.erase(active_key_id_before); @@ -525,7 +525,7 @@ BOOST_FIXTURE_TEST_CASE(multi_activation_tests, finalizer_key_tester) try { // Make sure last proposed finalizers set has changed producera_info = get_finalizer_info(producera); - active_key_id_after = producera_info["active_finalizer_key_id"].as_uint64(); + active_key_id_after = producera_info["active_key_id"].as_uint64(); last_prop_fin_ids_after = get_last_prop_fin_ids(); last_prop_fin_ids_before.erase(active_key_id_before); @@ -568,8 +568,8 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_no_finalizers_changed_test, fin auto last_finkey_ids = get_last_prop_fin_ids(); for( auto& p : producer_names ) { auto finalizer_info = get_finalizer_info(p); - uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_finalizer_key_id) ); + uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_key_id) ); } // Produce for one round @@ -597,16 +597,16 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finali auto last_finkey_ids = get_last_prop_fin_ids(); for( auto& p : producer_names ) { auto finalizer_info = get_finalizer_info(p); - uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_finalizer_key_id) ); + uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_key_id) ); } // Pick a producer name test_producer = producer_names.back(); - // Take a note of old active_finalizer_key_id + // Take a note of old active_key_id auto p_info = get_finalizer_info(test_producer); - uint64_t old_id = p_info["active_finalizer_key_id"].as_uint64(); + uint64_t old_id = p_info["active_key_id"].as_uint64(); // Register and activate a new finalizer key BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(test_producer, finalizer_key_1, pop_1) ); @@ -616,9 +616,9 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finali // immediately. auto last_finkey_ids_2 = get_last_prop_fin_ids(); - // Take a note of new active_finalizer_key_id + // Take a note of new active_key_id auto p_info_2 = get_finalizer_info(test_producer); - uint64_t new_id = p_info_2["active_finalizer_key_id"].as_uint64(); + uint64_t new_id = p_info_2["active_key_id"].as_uint64(); // After replace the old_id with new_id in last_finkey_ids, // last_finkey_ids should be the same as last_finkey_ids_2 @@ -649,8 +649,8 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final auto last_finkey_ids = get_last_prop_fin_ids(); for( auto i = 0; i < 21; ++i ) { auto finalizer_info = get_finalizer_info(producer_names[i]); - uint64_t active_finalizer_key_id = finalizer_info["active_finalizer_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_finalizer_key_id) ); + uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); + BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_key_id) ); } // Test delete the first finalizer key @@ -659,7 +659,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final account_name producerv_name = "defproducerv"_n; BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(producerv_name, finalizer_key_1, pop_1) ); auto producerv_info = get_finalizer_info(producerv_name); - uint64_t producerv_id = producerv_info["active_finalizer_key_id"].as_uint64(); + uint64_t producerv_id = producerv_info["active_key_id"].as_uint64(); // Wait for two rounds of producer schedule so new finalizer policy takes effect produce_block( fc::minutes(2) ); @@ -667,7 +667,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // Delete defproducera's finalizer key name producera_name = "defproducera"_n; auto p_info = get_finalizer_info(producera_name); - uint64_t deleted_id = p_info["active_finalizer_key_id"].as_uint64(); + uint64_t deleted_id = p_info["active_key_id"].as_uint64(); auto k_info = get_finalizer_key_info(deleted_id); auto producera_id = k_info["finalizer_key"].as_string(); BOOST_REQUIRE_EQUAL( success(), delete_finalizer_key(producera_name, producera_id) ); @@ -693,7 +693,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final account_name producerw_name = "defproducerw"_n; BOOST_REQUIRE_EQUAL( success(), register_finalizer_key(producerw_name, finalizer_key_2, pop_2) ); auto producerw_info = get_finalizer_info(producerw_name); - uint64_t producerw_id = producerw_info["active_finalizer_key_id"].as_uint64(); + uint64_t producerw_id = producerw_info["active_key_id"].as_uint64(); // Wait for two rounds of producer schedule so new finalizer policy takes effect produce_block( fc::minutes(2) ); From 74f7a47578950183e487446da07cdf5bae9fd7f0 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 12 Apr 2024 11:45:46 -0400 Subject: [PATCH 91/94] Provide a utility method is_active to finalizer_key struct; add more comments --- .../include/eosio.system/eosio.system.hpp | 2 + contracts/eosio.system/src/finalizer_key.cpp | 51 +++++++++++-------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 05c357cc..218de7dd 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -301,6 +301,8 @@ namespace eosiosystem { // which only happens if the table row is modified. There won't be any // modification of the table rows of; it may only be removed. checksum256 by_fin_key() const { return eosio::sha256(finalizer_key_binary.data(), finalizer_key_binary.size()); } + + bool is_active(uint64_t finalizer_active_key_id) const { return id == finalizer_active_key_id ; } }; typedef eosio::multi_index< "finkeys"_n, finalizer_key_info, diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index d3929dd3..878c4a51 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -12,11 +12,12 @@ namespace eosiosystem { { } - // Returns true if nodeos has transitioned to Savanna (last finalizer set not empty) + // Returns true if nodeos has transitioned to Savanna (having last proposed finalizers) bool system_contract::is_savanna_consensus() { return !get_last_proposed_finalizers().empty(); } + // Validates finalizer_key in text form and returns a binary form eosio::bls_g1 to_binary(const std::string& finalizer_key) { check(finalizer_key.compare(0, 7, "PUB_BLS") == 0, "finalizer key does not start with PUB_BLS: " + finalizer_key); return eosio::decode_bls_public_key_to_g1(finalizer_key); @@ -33,6 +34,7 @@ namespace eosiosystem { return get_finalizer_key_hash(fin_key_g1); } + // Validates finalizer and returns the iterator to finalizers table finalizers_table::const_iterator system_contract::get_finalizer_itr( const name& finalizer_name ) const { // Check finalizer has registered keys auto finalizer_itr = _finalizers.find(finalizer_name.value); @@ -42,15 +44,17 @@ namespace eosiosystem { return finalizer_itr; } - // This function may never fail, as it can be called by update_elected_producers, - // and in turn by onblock - // Establish finalizer policy from `proposed_fin_keys` and calls - // eosio::set_finalizers host function + // If finalizers have changed since last round, establishs finalizer policy + // from `proposed_finalizers` and calls eosio::set_finalizers host function + // Note: this function may never fail, as it can be called by update_elected_producers, + // and in turn by onblock. void system_contract::set_proposed_finalizers( std::vector proposed_finalizers ) { + // Sort proposed_finalizers by finalizer key ID std::sort( proposed_finalizers.begin(), proposed_finalizers.end(), []( const finalizer_auth_info& lhs, const finalizer_auth_info& rhs ) { return lhs.key_id < rhs.key_id; } ); + // Compare with last_proposed_finalizers to see if finalizers have changed. const auto& last_proposed_finalizers = get_last_proposed_finalizers(); if( proposed_finalizers == last_proposed_finalizers ) { // Finalizer policy has not changed. Do not proceed. @@ -64,16 +68,16 @@ namespace eosiosystem { finalizer_authorities.emplace_back(k.fin_authority); } - // Establish finalizer policy + // Establish new finalizer policy eosio::finalizer_policy fin_policy { .threshold = ( finalizer_authorities.size() * 2 ) / 3 + 1, .finalizers = std::move(finalizer_authorities) }; - // call host function + // Call host function eosio::set_finalizers(std::move(fin_policy)); // call host function - // store last proposed policy in both cache and DB table + // Store last proposed policy in both cache and DB table auto itr = _last_prop_finalizers.begin(); if( itr == _last_prop_finalizers.end() ) { _last_prop_finalizers.emplace( get_self(), [&]( auto& f ) { @@ -93,6 +97,7 @@ namespace eosiosystem { } } + // Returns last proposed finalizers const std::vector& system_contract::get_last_proposed_finalizers() { if( !_last_prop_finalizers_cached.has_value() ) { const auto finalizers_itr = _last_prop_finalizers.begin(); @@ -106,6 +111,8 @@ namespace eosiosystem { return *_last_prop_finalizers_cached; } + // Generates an ID for a new finalizer key to be used in finalizer_keys table. + // It may never be reused. uint64_t system_contract::get_next_finalizer_key_id() { uint64_t next_id = 0; auto itr = _fin_key_id_generator.begin(); @@ -181,7 +188,7 @@ namespace eosiosystem { auto producer = _producers.find( finalizer_name.value ); check( producer != _producers.end(), "finalizer " + finalizer_name.to_string() + " is not a registered producer"); - // Basic key and signature format check + // Basic signature format check check(proof_of_possession.compare(0, 7, "SIG_BLS") == 0, "proof of possession signature does not start with SIG_BLS: " + proof_of_possession); // Convert to binary form. The validity will be checked during conversion. @@ -189,15 +196,15 @@ namespace eosiosystem { const auto pop_g2 = eosio::decode_bls_signature_to_g2(proof_of_possession); // Duplication check across all registered keys - auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); - auto hash = get_finalizer_key_hash(fin_key_g1); + const auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); + const auto hash = get_finalizer_key_hash(fin_key_g1); check(idx.find(hash) == idx.end(), "duplicate finalizer key: " + finalizer_key); // Proof of possession check check(eosio::bls_pop_verify(fin_key_g1, pop_g2), "proof of possession check failed"); // Insert the finalizer key into finalyzer_keys table - auto finalizer_key_itr = _finalizer_keys.emplace( finalizer_name, [&]( auto& k ) { + const auto finalizer_key_itr = _finalizer_keys.emplace( finalizer_name, [&]( auto& k ) { k.id = get_next_finalizer_key_id(); k.finalizer_name = finalizer_name; k.finalizer_key = finalizer_key; @@ -232,23 +239,23 @@ namespace eosiosystem { void system_contract::actfinkey( const name& finalizer_name, const std::string& finalizer_key ) { require_auth( finalizer_name ); - auto finalizer = get_finalizer_itr(finalizer_name); + const auto finalizer = get_finalizer_itr(finalizer_name); // Check the key is registered - auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); - auto hash = get_finalizer_key_hash(finalizer_key); - auto finalizer_key_itr = idx.find(hash); + const auto idx = _finalizer_keys.get_index<"byfinkey"_n>(); + const auto hash = get_finalizer_key_hash(finalizer_key); + const auto finalizer_key_itr = idx.find(hash); check(finalizer_key_itr != idx.end(), "finalizer key was not registered: " + finalizer_key); // Check the key belongs to finalizer check(finalizer_key_itr->finalizer_name == name(finalizer_name), "finalizer key was not registered by the finalizer: " + finalizer_key); // Check if the finalizer key is not already active - check( finalizer_key_itr->id != finalizer->active_key_id, "finalizer key was already active: " + finalizer_key ); + check( !finalizer_key_itr->is_active(finalizer->active_key_id), "finalizer key was already active: " + finalizer_key ); - auto active_key_id = finalizer->active_key_id; + const auto active_key_id = finalizer->active_key_id; - // Update finalizer's information in _finalizers table + // Mark the finalizer key as active by updating finalizer's information in finalizers table _finalizers.modify( finalizer, same_payer, [&]( auto& f ) { f.active_key_id = finalizer_key_itr->id; f.active_key_binary = finalizer_key_itr->finalizer_key_binary; @@ -256,6 +263,7 @@ namespace eosiosystem { const auto& last_proposed_finalizers = get_last_proposed_finalizers(); if( last_proposed_finalizers.empty() ) { + // prior to switching to Savanna return; } @@ -266,8 +274,7 @@ namespace eosiosystem { // If active_key_id is in last_proposed_finalizers, it means the finalizer is // active. Replace the existing entry in last_proposed_finalizers with - // the information of finalizer_key just activated and call - // set_proposed_finalizers immediately + // the information of finalizer_key just activated and call set_proposed_finalizers immediately if( itr != last_proposed_finalizers.end() && itr->key_id == active_key_id ) { auto proposed_finalizers = last_proposed_finalizers; auto& matching_entry = proposed_finalizers[itr - last_proposed_finalizers.begin()]; @@ -300,7 +307,7 @@ namespace eosiosystem { // Check the key belongs to the finalizer check(fin_key_itr->finalizer_name == name(finalizer_name), "finalizer key " + finalizer_key + " was not registered by the finalizer " + finalizer_name.to_string() ); - if( fin_key_itr->id == finalizer->active_key_id ) { + if( fin_key_itr->is_active(finalizer->active_key_id) ) { check( finalizer->finalizer_key_count == 1, "cannot delete an active key unless it is the last registered finalizer key, has " + std::to_string(finalizer->finalizer_key_count) + " keys"); } From e88b8ca4d5613a424ea22586384621f1ea92ebdf Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 12 Apr 2024 12:44:54 -0400 Subject: [PATCH 92/94] Make sure number of last proposed finalizers correct in tests --- tests/eosio.finalizer_key_tests.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index 0a70fd68..a4e82606 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -452,6 +452,7 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { // Verify last proposed finalizer IDs contains active ID of each finalizer auto last_proposed_finalizer_ids = get_last_prop_fin_ids(); + BOOST_REQUIRE_EQUAL( 21, last_proposed_finalizer_ids.size() ); for( auto& p : producer_names ) { auto finalizer_info = get_finalizer_info(p); uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); @@ -481,6 +482,7 @@ BOOST_FIXTURE_TEST_CASE(multi_activation_tests, finalizer_key_tester) try { // Verify last proposed finalizer IDs contains active ID of each finalizer auto last_proposed_finalizer_ids = get_last_prop_fin_ids(); + BOOST_REQUIRE_EQUAL( 21, last_proposed_finalizer_ids.size() ); for( auto& p : producer_names ) { auto finalizer_info = get_finalizer_info(p); uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); @@ -502,6 +504,7 @@ BOOST_FIXTURE_TEST_CASE(multi_activation_tests, finalizer_key_tester) try { auto producera_info = get_finalizer_info(producera); auto active_key_id_before = producera_info["active_key_id"].as_uint64(); auto last_prop_fin_ids_before = get_last_prop_fin_ids(); + BOOST_REQUIRE_EQUAL( 21, last_prop_fin_ids_before.size() ); // Activate finalizer_key_1 BOOST_REQUIRE_EQUAL( success(), activate_finalizer_key(producera, finalizer_key_1) ); @@ -511,6 +514,7 @@ BOOST_FIXTURE_TEST_CASE(multi_activation_tests, finalizer_key_tester) try { producera_info = get_finalizer_info(producera); auto active_key_id_after = producera_info["active_key_id"].as_uint64(); auto last_prop_fin_ids_after = get_last_prop_fin_ids(); + BOOST_REQUIRE_EQUAL( 21, last_prop_fin_ids_after.size() ); last_prop_fin_ids_before.erase(active_key_id_before); last_prop_fin_ids_before.insert(active_key_id_after); @@ -527,6 +531,7 @@ BOOST_FIXTURE_TEST_CASE(multi_activation_tests, finalizer_key_tester) try { producera_info = get_finalizer_info(producera); active_key_id_after = producera_info["active_key_id"].as_uint64(); last_prop_fin_ids_after = get_last_prop_fin_ids(); + BOOST_REQUIRE_EQUAL( 21, last_prop_fin_ids_after.size() ); last_prop_fin_ids_before.erase(active_key_id_before); last_prop_fin_ids_before.insert(active_key_id_after); @@ -566,6 +571,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_no_finalizers_changed_test, fin // Verify last finalizer key id table contains all finalzer keys auto last_finkey_ids = get_last_prop_fin_ids(); + BOOST_REQUIRE_EQUAL( 21, last_finkey_ids.size() ); for( auto& p : producer_names ) { auto finalizer_info = get_finalizer_info(p); uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); @@ -577,6 +583,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_no_finalizers_changed_test, fin // Since finalizer keys have not changed, last_finkey_ids should be the same auto last_finkey_ids_2 = get_last_prop_fin_ids(); + BOOST_REQUIRE_EQUAL( 21, last_finkey_ids_2.size() ); BOOST_REQUIRE_EQUAL( true, last_finkey_ids == last_finkey_ids_2 ); } FC_LOG_AND_RETHROW() @@ -595,6 +602,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finali // Verify last finalizer key id table contains all finalzer keys auto last_finkey_ids = get_last_prop_fin_ids(); + BOOST_REQUIRE_EQUAL( 21, last_finkey_ids.size() ); for( auto& p : producer_names ) { auto finalizer_info = get_finalizer_info(p); uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); @@ -615,6 +623,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finali // Since producer is an active producer, the finalizer key change takes effective // immediately. auto last_finkey_ids_2 = get_last_prop_fin_ids(); + BOOST_REQUIRE_EQUAL( 21, last_finkey_ids_2.size() ); // Take a note of new active_key_id auto p_info_2 = get_finalizer_info(test_producer); @@ -647,6 +656,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // Verify last finalizer key id table contains all finalzer keys auto last_finkey_ids = get_last_prop_fin_ids(); + BOOST_REQUIRE_EQUAL( 21, last_finkey_ids.size() ); for( auto i = 0; i < 21; ++i ) { auto finalizer_info = get_finalizer_info(producer_names[i]); uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); @@ -678,6 +688,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // find new last_finkey_ids auto last_finkey_ids_2 = get_last_prop_fin_ids(); + BOOST_REQUIRE_EQUAL( 21, last_finkey_ids_2.size() ); // Make sure new_id is in the new last_finkey_ids BOOST_REQUIRE_EQUAL( true, last_finkey_ids_2.contains(producerv_id) ); @@ -707,6 +718,7 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // find new last_finkey_ids auto last_finkey_ids_3 = get_last_prop_fin_ids(); + BOOST_REQUIRE_EQUAL( 21, last_finkey_ids_3.size() ); // Make sure producerw_id is in the new last_finkey_ids BOOST_REQUIRE_EQUAL( true, last_finkey_ids_3.contains(producerw_id) ); From 021213a2b62fc3eea3409ec4e9beacd917d5e9c9 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 15 Apr 2024 09:29:38 -0400 Subject: [PATCH 93/94] Add public key check to last proposed finalizers in tests --- tests/eosio.finalizer_key_tests.cpp | 74 ++++++++++++++--------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/tests/eosio.finalizer_key_tests.cpp b/tests/eosio.finalizer_key_tests.cpp index a4e82606..fd2d22a5 100644 --- a/tests/eosio.finalizer_key_tests.cpp +++ b/tests/eosio.finalizer_key_tests.cpp @@ -41,7 +41,7 @@ struct finalizer_key_tester : eosio_system_tester { return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "finalizer_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } - std::unordered_set get_last_prop_fin_ids() { + std::vector get_last_prop_finalizers_info() { const auto* table_id_itr = control->db().find( boost::make_tuple(config::system_account_name, config::system_account_name, "lastpropfins"_n)); @@ -63,6 +63,12 @@ struct finalizer_key_tester : eosio_system_tester { fc::variant fins_info = data.empty() ? fc::variant() : abi_ser.binary_to_variant( "last_prop_finalizers_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); std::vector finalizers = fins_info["last_proposed_finalizers"].as>(); + return finalizers; + }; + + std::unordered_set get_last_prop_fin_ids() { + auto finalizers = get_last_prop_finalizers_info(); + std::unordered_set last_prop_fin_ids; for(auto f: finalizers) { last_prop_fin_ids.insert(f.key_id); @@ -101,6 +107,21 @@ struct finalizer_key_tester : eosio_system_tester { } } } + + // Verify finalizers_table and last_prop_fins_table match + void verify_last_proposed_finalizers(const std::vector& producer_names) { + auto last_finalizers = get_last_prop_finalizers_info(); + BOOST_REQUIRE_EQUAL( 21, last_finalizers.size() ); + for( auto& p : producer_names ) { + auto finalizer_info = get_finalizer_info(p); + uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); + auto itr = std::find_if(last_finalizers.begin(), last_finalizers.end(), [&active_key_id](const finalizer_auth_info& f) { return f.key_id == active_key_id; }); + // finalizer's active key id is in last proposed finalizers table + BOOST_REQUIRE_EQUAL( true, itr != last_finalizers.end() ); + // finalizer's active key matches one in last proposed finalizers table + BOOST_REQUIRE_EQUAL( true, itr->fin_authority.public_key == finalizer_info["active_key_binary"].as>() ); + } + } }; @@ -450,14 +471,8 @@ BOOST_FIXTURE_TEST_CASE(switchtosvnn_success_tests, finalizer_key_tester) try { register_finalizer_keys(producer_names, 21); BOOST_REQUIRE_EQUAL(success(), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); - // Verify last proposed finalizer IDs contains active ID of each finalizer - auto last_proposed_finalizer_ids = get_last_prop_fin_ids(); - BOOST_REQUIRE_EQUAL( 21, last_proposed_finalizer_ids.size() ); - for( auto& p : producer_names ) { - auto finalizer_info = get_finalizer_info(p); - uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_proposed_finalizer_ids.contains(active_key_id) ); - } + // Verify finalizers_table and last_prop_fins_table match + verify_last_proposed_finalizers(producer_names); // Produce enough blocks so transition to Savanna finishes produce_blocks(504); // 21 Producers * 12 Blocks per producer * 2 rounds to reach Legacy finality @@ -480,14 +495,8 @@ BOOST_FIXTURE_TEST_CASE(multi_activation_tests, finalizer_key_tester) try { register_finalizer_keys(producer_names, 21); BOOST_REQUIRE_EQUAL(success(), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); - // Verify last proposed finalizer IDs contains active ID of each finalizer - auto last_proposed_finalizer_ids = get_last_prop_fin_ids(); - BOOST_REQUIRE_EQUAL( 21, last_proposed_finalizer_ids.size() ); - for( auto& p : producer_names ) { - auto finalizer_info = get_finalizer_info(p); - uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_proposed_finalizer_ids.contains(active_key_id) ); - } + // Verify finalizers_table and last_prop_fins_table match + verify_last_proposed_finalizers(producer_names); // Produce enough blocks so transition to Savanna finishes produce_blocks(504); // 21 Producers * 12 Blocks per producer * 2 rounds to reach Legacy finality @@ -569,14 +578,10 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_no_finalizers_changed_test, fin // head_finality_data is available when nodoes is in Savanna BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); - // Verify last finalizer key id table contains all finalzer keys + // Verify finalizers_table and last_prop_fins_table match + verify_last_proposed_finalizers(producer_names); + auto last_finkey_ids = get_last_prop_fin_ids(); - BOOST_REQUIRE_EQUAL( 21, last_finkey_ids.size() ); - for( auto& p : producer_names ) { - auto finalizer_info = get_finalizer_info(p); - uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_key_id) ); - } // Produce for one round produce_block( fc::minutes(2) ); @@ -600,14 +605,10 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_changed_test, finali // head_finality_data is available when nodoes is in Savanna BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); + // Verify finalizers_table and last_prop_fins_table match + verify_last_proposed_finalizers(producer_names); // Verify last finalizer key id table contains all finalzer keys auto last_finkey_ids = get_last_prop_fin_ids(); - BOOST_REQUIRE_EQUAL( 21, last_finkey_ids.size() ); - for( auto& p : producer_names ) { - auto finalizer_info = get_finalizer_info(p); - uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_key_id) ); - } // Pick a producer name test_producer = producer_names.back(); @@ -649,19 +650,16 @@ BOOST_FIXTURE_TEST_CASE(update_elected_producers_finalizers_replaced_test, final // Transition to Savanna BOOST_REQUIRE_EQUAL(success(), push_action( config::system_account_name, "switchtosvnn"_n, mvo()) ); + auto last_finkey_ids = get_last_prop_fin_ids(); + // Produce enough blocks so transition to Savanna finishes produce_blocks(2 * 21 * 12); // head_finality_data is available when nodoes is in Savanna BOOST_REQUIRE_EQUAL( true, control->head_finality_data().has_value() ); - // Verify last finalizer key id table contains all finalzer keys - auto last_finkey_ids = get_last_prop_fin_ids(); - BOOST_REQUIRE_EQUAL( 21, last_finkey_ids.size() ); - for( auto i = 0; i < 21; ++i ) { - auto finalizer_info = get_finalizer_info(producer_names[i]); - uint64_t active_key_id = finalizer_info["active_key_id"].as_uint64(); - BOOST_REQUIRE_EQUAL( true, last_finkey_ids.contains(active_key_id) ); - } + // Verify finalizers_table and last_prop_fins_table match + std::vector producer_names_first_21(producer_names.begin(), producer_names.begin() + 21); + verify_last_proposed_finalizers(producer_names_first_21); // Test delete the first finalizer key From bc2e6389a2170fb917303c5d28500e7b6ae50291 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 15 Apr 2024 09:33:15 -0400 Subject: [PATCH 94/94] Fix a couple fo typos in comments --- contracts/eosio.system/include/eosio.system/eosio.system.hpp | 2 +- contracts/eosio.system/src/finalizer_key.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 218de7dd..1730a8a8 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -342,7 +342,7 @@ namespace eosiosystem { // A single entry storing information about last proposed finalizers. // Should avoid using the global singleton pattern as it unnecessarily // serializes data at construction/desstruction of system_contract, - // even the data is not used. + // even if the data is not used. struct [[eosio::table("lastpropfins"), eosio::contract("eosio.system")]] last_prop_finalizers_info { std::vector last_proposed_finalizers; // sorted by ascending finalizer key id diff --git a/contracts/eosio.system/src/finalizer_key.cpp b/contracts/eosio.system/src/finalizer_key.cpp index 878c4a51..3e2b95db 100644 --- a/contracts/eosio.system/src/finalizer_key.cpp +++ b/contracts/eosio.system/src/finalizer_key.cpp @@ -44,7 +44,7 @@ namespace eosiosystem { return finalizer_itr; } - // If finalizers have changed since last round, establishs finalizer policy + // If finalizers have changed since last round, establishes finalizer policy // from `proposed_finalizers` and calls eosio::set_finalizers host function // Note: this function may never fail, as it can be called by update_elected_producers, // and in turn by onblock.