Skip to content

Commit

Permalink
Merge pull request #2208 from AntelopeIO/new_activate_if_unittest
Browse files Browse the repository at this point in the history
IF: Add a new set_finalizer (with weights, threshold, and local finalizer) to libtester and add more tests using it
  • Loading branch information
linh2931 authored Feb 6, 2024
2 parents 746f022 + c42eacf commit ed4209f
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 11 deletions.
19 changes: 18 additions & 1 deletion libraries/testing/include/eosio/testing/tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,24 @@ namespace eosio { namespace testing {
transaction_trace_ptr set_producers(const vector<account_name>& producer_names);
transaction_trace_ptr set_producer_schedule(const vector<producer_authority>& schedule);
transaction_trace_ptr set_producers_legacy(const vector<account_name>& producer_names);
transaction_trace_ptr set_finalizers(const vector<account_name>& finalier_names);

// libtester uses 1 as weight of each of the finalizer, sets (2/3 finalizers + 1)
// as threshold, and makes all finalizers vote QC
transaction_trace_ptr set_finalizers(const vector<account_name>& finalizer_names);

// Finalizer policy input to set up a test: weights, threshold and local finalizers
// which participate voting.
struct finalizer_policy_input {
struct finalizer_info {
account_name name;
uint64_t weight;
};

std::vector<finalizer_info> finalizers;
uint64_t threshold {0};
std::vector<account_name> local_finalizers;
};
transaction_trace_ptr set_finalizers(const finalizer_policy_input& input);

void link_authority( account_name account, account_name code, permission_name req, action_name type = {} );
void unlink_authority( account_name account, account_name code, action_name type = {} );
Expand Down
39 changes: 29 additions & 10 deletions libraries/testing/tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1188,27 +1188,46 @@ namespace eosio { namespace testing {
}

transaction_trace_ptr base_tester::set_finalizers(const vector<account_name>& finalizer_names) {
uint64_t threshold = finalizer_names.size() * 2 / 3 + 1;
auto num_finalizers = finalizer_names.size();
std::vector<finalizer_policy_input::finalizer_info> finalizers_info;
finalizers_info.reserve(num_finalizers);
for (const auto& f: finalizer_names) {
finalizers_info.push_back({.name = f, .weight = 1});
}

finalizer_policy_input policy_input = {
.finalizers = finalizers_info,
.threshold = num_finalizers * 2 / 3 + 1,
.local_finalizers = finalizer_names
};

chain::bls_pub_priv_key_map_t finalizer_keys;
return set_finalizers(policy_input);
}

transaction_trace_ptr base_tester::set_finalizers(const finalizer_policy_input& input) {
chain::bls_pub_priv_key_map_t local_finalizer_keys;
fc::variants finalizer_auths;
for (const auto& n: finalizer_names) {
auto [privkey, pubkey, pop] = get_bls_key( n );

finalizer_keys[pubkey.to_string()] = privkey.to_string();
for (const auto& f: input.finalizers) {
auto [privkey, pubkey, pop] = get_bls_key( f.name );

// if it is a local finalizer, set up public to private key mapping for voting
if( auto it = std::ranges::find_if(input.local_finalizers, [&](const auto& name) { return name == f.name; }); it != input.local_finalizers.end()) {
local_finalizer_keys[pubkey.to_string()] = privkey.to_string();
};

finalizer_auths.emplace_back(
fc::mutable_variant_object()
("description", n.to_string() + " description")
("weight", (uint64_t)1)
("description", f.name.to_string() + " description")
("weight", f.weight)
("public_key", pubkey.to_string({}))
("pop", pop.to_string({})));
}

// configure finalizer keys on controller for signing votes
control->set_node_finalizer_keys(finalizer_keys);
control->set_node_finalizer_keys(local_finalizer_keys);

fc::mutable_variant_object fin_policy_variant;
fin_policy_variant("threshold", threshold);
fin_policy_variant("threshold", input.threshold);
fin_policy_variant("finalizers", std::move(finalizer_auths));

return push_action( config::system_account_name, "setfinalizer"_n, config::system_account_name,
Expand Down
114 changes: 114 additions & 0 deletions unittests/api_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3917,4 +3917,118 @@ BOOST_AUTO_TEST_CASE(set_finalizer_test) { try {
BOOST_CHECK_GT(lib, lib_after_transition);
} FC_LOG_AND_RETHROW() }

void test_finality_transition(const vector<account_name>& accounts, const base_tester::finalizer_policy_input& input, bool lib_advancing_expected) {
validating_tester t;

uint32_t lib = 0;
t.control->irreversible_block.connect([&](const block_signal_params& t) {
const auto& [ block, id ] = t;
lib = block->block_num();
});

t.produce_block();

// Create finalizer accounts
t.create_accounts(accounts);
t.produce_block();

// activate hotstuff
t.set_finalizers(input);
auto block = t.produce_block(); // this block contains the header extension for the instant finality

std::optional<block_header_extension> ext = block->extract_header_extension(instant_finality_extension::extension_id());
BOOST_TEST(!!ext);
std::optional<finalizer_policy> fin_policy = std::get<instant_finality_extension>(*ext).new_finalizer_policy;
BOOST_TEST(!!fin_policy);
BOOST_TEST(fin_policy->finalizers.size() == accounts.size());
BOOST_TEST(fin_policy->generation == 1);

block = t.produce_block(); // hotstuff now active
BOOST_TEST(block->confirmed == 0);
auto fb = t.control->fetch_block_by_id(block->calculate_id());
BOOST_REQUIRE(!!fb);
BOOST_TEST(fb == block);
ext = fb->extract_header_extension(instant_finality_extension::extension_id());
BOOST_REQUIRE(ext);

auto lib_after_transition = lib;

t.produce_blocks(4);
if( lib_advancing_expected ) {
BOOST_CHECK_GT(lib, lib_after_transition);
} else {
BOOST_CHECK_EQUAL(lib, lib_after_transition);
}
}

BOOST_AUTO_TEST_CASE(threshold_equal_to_half_weight_sum_test) { try {
vector<account_name> account_names = {
"alice"_n, "bob"_n, "carol"_n
};

// threshold set to half of the weight sum of finalizers
base_tester::finalizer_policy_input policy_input = {
.finalizers = { {.name = "alice"_n, .weight = 1},
{.name = "bob"_n, .weight = 2},
{.name = "carol"_n, .weight = 3} },
.threshold = 3,
.local_finalizers = {"alice"_n, "bob"_n}
};

// threshold must be greater than half of the sum of the weights
BOOST_REQUIRE_THROW( test_finality_transition(account_names, policy_input, false), eosio_assert_message_exception );

} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_CASE(votes_equal_to_threshold_test) { try {
vector<account_name> account_names = {
"alice"_n, "bob"_n, "carol"_n
};

base_tester::finalizer_policy_input policy_input = {
.finalizers = { {.name = "alice"_n, .weight = 1},
{.name = "bob"_n, .weight = 3},
{.name = "carol"_n, .weight = 5} },
.threshold = 5,
.local_finalizers = {"carol"_n}
};

// Carol votes with weight 5 and threshold 5
test_finality_transition(account_names, policy_input, true); // lib_advancing_expected
} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_CASE(votes_greater_than_threshold_test) { try {
vector<account_name> account_names = {
"alice"_n, "bob"_n, "carol"_n
};

base_tester::finalizer_policy_input policy_input = {
.finalizers = { {.name = "alice"_n, .weight = 1},
{.name = "bob"_n, .weight = 4},
{.name = "carol"_n, .weight = 2} },
.threshold = 4,
.local_finalizers = {"alice"_n, "bob"_n}
};

// alice and bob vote with weight 5 and threshold 4
test_finality_transition(account_names, policy_input, true); // lib_advancing_expected
} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_CASE(votes_less_than_threshold_test) { try {
vector<account_name> account_names = {
"alice"_n, "bob"_n, "carol"_n
};

base_tester::finalizer_policy_input policy_input = {
.finalizers = { {.name = "alice"_n, .weight = 1},
{.name = "bob"_n, .weight = 3},
{.name = "carol"_n, .weight = 10} },
.threshold = 8,
.local_finalizers = {"alice"_n, "bob"_n}
};

// alice and bob vote with weight 4 but threshold 8. LIB cannot advance
test_finality_transition(account_names, policy_input, false); // not expecting lib advancing
} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit ed4209f

Please sign in to comment.