Skip to content

Commit

Permalink
Merge pull request #37 from AntelopeIO/svnn_ibc_proof_generation
Browse files Browse the repository at this point in the history
Svnn ibc proof generation
  • Loading branch information
systemzax authored May 2, 2024
2 parents 5a3550a + dd1689b commit a3fa40e
Show file tree
Hide file tree
Showing 11 changed files with 633 additions and 393 deletions.
12 changes: 0 additions & 12 deletions libraries/chain/block_header_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,6 @@ namespace eosio::chain {
// gets updated if a protocol feature causes a breaking change to light block
// header validation

// data for finality_digest
struct finality_digest_data_v1 {
uint32_t major_version{light_header_protocol_version_major};
uint32_t minor_version{light_header_protocol_version_minor};
uint32_t active_finalizer_policy_generation {0};
digest_type finality_tree_digest;
digest_type active_finalizer_policy_and_base_digest;
};

// compute base_digest explicitly because of pointers involved.
digest_type block_header_state::compute_base_digest() const {
digest_type::encoder enc;
Expand Down Expand Up @@ -298,6 +289,3 @@ block_header_state block_header_state::next(const signed_block_header& h, valida

} // namespace eosio::chain

FC_REFLECT( eosio::chain::finality_digest_data_v1,
(major_version)(minor_version)(active_finalizer_policy_generation)
(finality_tree_digest)(active_finalizer_policy_and_base_digest) )
12 changes: 12 additions & 0 deletions libraries/chain/include/eosio/chain/block_header_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ namespace detail { struct schedule_info; };
constexpr uint32_t light_header_protocol_version_major = 1;
constexpr uint32_t light_header_protocol_version_minor = 0;

// data for finality_digest
struct finality_digest_data_v1 {
uint32_t major_version{light_header_protocol_version_major};
uint32_t minor_version{light_header_protocol_version_minor};
uint32_t active_finalizer_policy_generation {0};
digest_type finality_tree_digest;
digest_type active_finalizer_policy_and_base_digest;

};

// ------------------------------------------------------------------------------------------
// this is used for tracking in-flight `finalizer_policy` changes, which have been requested,
// but are not activated yet. This struct is associated to a block_number in the
Expand Down Expand Up @@ -128,3 +138,5 @@ FC_REFLECT( eosio::chain::block_header_state, (block_id)(header)
(activated_protocol_features)(core)(active_finalizer_policy)
(active_proposer_policy)(proposer_policies)(finalizer_policies)
(finalizer_policy_generation)(header_exts))

FC_REFLECT( eosio::chain::finality_digest_data_v1, (major_version)(minor_version)(active_finalizer_policy_generation)(finality_tree_digest)(active_finalizer_policy_and_base_digest) )
44 changes: 30 additions & 14 deletions unittests/finality_test_cluster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ finality_test_cluster::finality_test_cluster() {
setup_node(node1, "node1"_n);
setup_node(node2, "node2"_n);

produce_and_push_block(); // make setfinalizer irreversible

// node0's votes
node0.node.control->voted_block().connect( [&]( const eosio::chain::vote_signal_params& v ) {
last_vote_status = std::get<1>(v);
Expand All @@ -26,6 +24,24 @@ finality_test_cluster::finality_test_cluster() {
node2.votes.emplace_back(std::get<2>(v));
});

}

void finality_test_cluster::initial_tests(){

auto block_1_n0 = node0.node.produce_block();
auto block_1_n1 = node1.node.produce_block();
auto block_1_n2 = node2.node.produce_block();

// this block contains the header exten/sion for the instant finality
std::optional<eosio::chain::block_header_extension> ext = block_1_n0->extract_header_extension(eosio::chain::instant_finality_extension::extension_id());
BOOST_TEST(!!ext);
std::optional<eosio::chain::finalizer_policy> fin_policy = std::get<eosio::chain::instant_finality_extension>(*ext).new_finalizer_policy;
BOOST_TEST(!!fin_policy);
BOOST_TEST(fin_policy->finalizers.size() == 3);
BOOST_TEST(fin_policy->generation == 1);

produce_and_push_block(); // make setfinalizer irreversible

// form a 3-chain to make LIB advacing on node0
// node0's vote (internal voting) and node1's vote make the quorum
for (auto i = 0; i < 3; ++i) {
Expand All @@ -46,6 +62,7 @@ finality_test_cluster::finality_test_cluster() {
n.votes.clear();
n.prev_lib_num = n.node.control->if_irreversible_block_num();
}

}

eosio::chain::vote_status finality_test_cluster::wait_on_vote(uint32_t connection_id, bool duplicate) {
Expand All @@ -61,13 +78,14 @@ eosio::chain::vote_status finality_test_cluster::wait_on_vote(uint32_t connectio
FC_ASSERT(false, "Duplicate should not have been signaled");
}
return duplicate ? eosio::chain::vote_status::duplicate : last_vote_status.load();
}
}

// node0 produces a block and pushes it to node1 and node2
void finality_test_cluster::produce_and_push_block() {
eosio::chain::signed_block_ptr finality_test_cluster::produce_and_push_block() {
auto b = node0.node.produce_block();
node1.node.push_block(b);
node2.node.push_block(b);
return b;
}

// send node1's vote identified by "vote_index" in the collected votes
Expand Down Expand Up @@ -128,6 +146,13 @@ bool finality_test_cluster::produce_blocks_and_verify_lib_advancing() {
return true;
}

void finality_test_cluster::produce_blocks(uint32_t blocks_count) {
for (uint32_t i = 0; i < blocks_count; ++i) {
produce_and_push_block();
process_node1_vote();
}
}

void finality_test_cluster::node1_corrupt_vote_block_id() {
std::lock_guard g(node1.votes_mtx);
node1_orig_vote = node1.votes[0];
Expand Down Expand Up @@ -194,15 +219,6 @@ void finality_test_cluster::setup_node(node_info& node, eosio::chain::account_na
FC_ASSERT( priv_keys.size() == 1, "number of private keys should be 1" );
node.priv_key = priv_keys[0]; // we only have one private key

auto block = node.node.produce_block();

// this block contains the header extension for the instant finality
std::optional<eosio::chain::block_header_extension> ext = block->extract_header_extension(eosio::chain::instant_finality_extension::extension_id());
BOOST_TEST(!!ext);
std::optional<eosio::chain::finalizer_policy> fin_policy = std::get<eosio::chain::instant_finality_extension>(*ext).new_finalizer_policy;
BOOST_TEST(!!fin_policy);
BOOST_TEST(fin_policy->finalizers.size() == 3);
BOOST_TEST(fin_policy->generation == 1);
}

// send a vote to node0
Expand Down Expand Up @@ -235,4 +251,4 @@ eosio::chain::vote_status finality_test_cluster::process_vote(node_info& node, v
vote_index = node.votes.size() - 1;
g.unlock();
return process_vote( node, vote_index, mode );
}
}
37 changes: 22 additions & 15 deletions unittests/finality_test_cluster.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <eosio/chain/block.hpp>
#include <eosio/chain/finality/finalizer_authority.hpp>
#include <fc/crypto/bls_private_key.hpp>

Expand Down Expand Up @@ -29,11 +30,22 @@ class finality_test_cluster {
weak,
};

struct node_info {
eosio::testing::tester node;
uint32_t prev_lib_num{0};
std::mutex votes_mtx;
std::vector<eosio::chain::vote_message_ptr> votes;
fc::crypto::blslib::bls_private_key priv_key;
};

// Construct a test network and activate IF.
finality_test_cluster();

// node0 produces a block and pushes it to node1 and node2
void produce_and_push_block();
eosio::chain::signed_block_ptr produce_and_push_block();

// make setfinalizer final and test finality
void initial_tests();

// send node1's vote identified by "index" in the collected votes
eosio::chain::vote_status process_node1_vote(uint32_t vote_index, vote_mode mode = vote_mode::strong, bool duplicate = false);
Expand All @@ -46,7 +58,7 @@ class finality_test_cluster {

// send node2's latest vote
eosio::chain::vote_status process_node2_vote(vote_mode mode = vote_mode::strong);

// returns true if node0's LIB has advanced
bool node0_lib_advancing();

Expand All @@ -61,6 +73,9 @@ class finality_test_cluster {
// node1_votes and node2_votes when starting.
bool produce_blocks_and_verify_lib_advancing();

// Produces and propagate finality votes block_count blocks.
void produce_blocks(uint32_t blocks_count);

// Intentionally corrupt node1's vote's block_id and save the original vote
void node1_corrupt_vote_block_id();

Expand All @@ -73,24 +88,16 @@ class finality_test_cluster {
// Restore node1's original vote
void node1_restore_to_original_vote();

private:

struct node_info {
eosio::testing::tester node;
uint32_t prev_lib_num{0};
std::mutex votes_mtx;
std::vector<eosio::chain::vote_message_ptr> votes;
fc::crypto::blslib::bls_private_key priv_key;
};

std::atomic<uint32_t> last_connection_vote{0};
std::atomic<eosio::chain::vote_status> last_vote_status{};

std::array<node_info, 3> nodes;
node_info& node0 = nodes[0];
node_info& node1 = nodes[1];
node_info& node2 = nodes[2];

private:

std::atomic<uint32_t> last_connection_vote{0};
std::atomic<eosio::chain::vote_status> last_vote_status{};

eosio::chain::vote_message_ptr node1_orig_vote;

// sets up "node_index" node
Expand Down
43 changes: 31 additions & 12 deletions unittests/finality_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ BOOST_AUTO_TEST_SUITE(finality_tests)
// verify LIB advances with 2 finalizers voting.
BOOST_AUTO_TEST_CASE(two_votes) { try {
finality_test_cluster cluster;

cluster.initial_tests();

for (auto i = 0; i < 3; ++i) {
// node0 produces a block and pushes to node1 and node2
cluster.produce_and_push_block();
Expand All @@ -26,6 +27,7 @@ BOOST_AUTO_TEST_CASE(two_votes) { try {
// verify LIB does not advances with finalizers not voting.
BOOST_AUTO_TEST_CASE(no_votes) { try {
finality_test_cluster cluster;
cluster.initial_tests();

cluster.produce_and_push_block();
cluster.node0_lib_advancing(); // reset
Expand All @@ -47,7 +49,8 @@ BOOST_AUTO_TEST_CASE(no_votes) { try {
// verify LIB advances with all of the three finalizers voting
BOOST_AUTO_TEST_CASE(all_votes) { try {
finality_test_cluster cluster;

cluster.initial_tests();

cluster.produce_and_push_block();
for (auto i = 0; i < 3; ++i) {
// process node1 and node2's votes
Expand All @@ -66,7 +69,8 @@ BOOST_AUTO_TEST_CASE(all_votes) { try {
// verify LIB advances when votes conflict (strong first and followed by weak)
BOOST_AUTO_TEST_CASE(conflicting_votes_strong_first) { try {
finality_test_cluster cluster;

cluster.initial_tests();

cluster.produce_and_push_block();
for (auto i = 0; i < 3; ++i) {
cluster.process_node1_vote(); // strong
Expand All @@ -82,7 +86,8 @@ BOOST_AUTO_TEST_CASE(conflicting_votes_strong_first) { try {
// verify LIB advances when votes conflict (weak first and followed by strong)
BOOST_AUTO_TEST_CASE(conflicting_votes_weak_first) { try {
finality_test_cluster cluster;

cluster.initial_tests();

cluster.produce_and_push_block();
for (auto i = 0; i < 3; ++i) {
cluster.process_node1_vote(finality_test_cluster::vote_mode::weak); // weak
Expand All @@ -98,6 +103,7 @@ BOOST_AUTO_TEST_CASE(conflicting_votes_weak_first) { try {
// Verify a delayed vote works
BOOST_AUTO_TEST_CASE(one_delayed_votes) { try {
finality_test_cluster cluster;
cluster.initial_tests();

// hold the vote for the first block to simulate delay
cluster.produce_and_push_block();
Expand Down Expand Up @@ -131,6 +137,7 @@ BOOST_AUTO_TEST_CASE(one_delayed_votes) { try {
// Verify 3 consecutive delayed votes work
BOOST_AUTO_TEST_CASE(three_delayed_votes) { try {
finality_test_cluster cluster;
cluster.initial_tests();

// produce 4 blocks and hold the votes for the first 3 to simulate delayed votes
// The 4 blocks have the same QC claim as no QCs are created because missing one vote
Expand Down Expand Up @@ -171,7 +178,8 @@ BOOST_AUTO_TEST_CASE(three_delayed_votes) { try {

BOOST_AUTO_TEST_CASE(out_of_order_votes) { try {
finality_test_cluster cluster;

cluster.initial_tests();

// produce 3 blocks and hold the votes to simulate delayed votes
// The 3 blocks have the same QC claim as no QCs are created because missing votes
for (auto i = 0; i < 3; ++i) {
Expand Down Expand Up @@ -211,7 +219,8 @@ BOOST_AUTO_TEST_CASE(out_of_order_votes) { try {
// Verify a vote which was delayed by a large number of blocks does not cause any issues
BOOST_AUTO_TEST_CASE(long_delayed_votes) { try {
finality_test_cluster cluster;

cluster.initial_tests();

// Produce and push a block, vote on it after a long delay.
constexpr uint32_t delayed_vote_index = 0;
cluster.produce_and_push_block();
Expand Down Expand Up @@ -244,7 +253,8 @@ BOOST_AUTO_TEST_CASE(long_delayed_votes) { try {

BOOST_AUTO_TEST_CASE(lost_votes) { try {
finality_test_cluster cluster;

cluster.initial_tests();

// Produce and push a block, never vote on it to simulate lost.
// The block contains a strong QC extension for prior block
cluster.produce_and_push_block();
Expand All @@ -270,7 +280,8 @@ BOOST_AUTO_TEST_CASE(lost_votes) { try {

BOOST_AUTO_TEST_CASE(one_weak_vote) { try {
finality_test_cluster cluster;

cluster.initial_tests();

// Produce and push a block
cluster.produce_and_push_block();
// Change the vote to a weak vote and process it
Expand Down Expand Up @@ -303,6 +314,7 @@ BOOST_AUTO_TEST_CASE(one_weak_vote) { try {

BOOST_AUTO_TEST_CASE(two_weak_votes) { try {
finality_test_cluster cluster;
cluster.initial_tests();

// Produce and push a block
cluster.produce_and_push_block();
Expand Down Expand Up @@ -340,6 +352,7 @@ BOOST_AUTO_TEST_CASE(two_weak_votes) { try {

BOOST_AUTO_TEST_CASE(intertwined_weak_votes) { try {
finality_test_cluster cluster;
cluster.initial_tests();

cluster.produce_and_push_block();
BOOST_REQUIRE(cluster.node2_lib_advancing());
Expand Down Expand Up @@ -385,7 +398,8 @@ BOOST_AUTO_TEST_CASE(intertwined_weak_votes) { try {
// Verify a combination of weak, delayed, lost votes still work
BOOST_AUTO_TEST_CASE(weak_delayed_lost_vote) { try {
finality_test_cluster cluster;

cluster.initial_tests();

cluster.produce_and_push_block();
BOOST_REQUIRE(cluster.node2_lib_advancing());
BOOST_REQUIRE(cluster.node1_lib_advancing());
Expand Down Expand Up @@ -431,7 +445,8 @@ BOOST_AUTO_TEST_CASE(weak_delayed_lost_vote) { try {
// Verify a combination of delayed, weak, lost votes still work
BOOST_AUTO_TEST_CASE(delayed_strong_weak_lost_vote) { try {
finality_test_cluster cluster;

cluster.initial_tests();

// A delayed vote (index 0)
constexpr uint32_t delayed_index = 0;
cluster.produce_and_push_block();
Expand Down Expand Up @@ -478,7 +493,8 @@ BOOST_AUTO_TEST_CASE(delayed_strong_weak_lost_vote) { try {
// verify duplicate votes do not affect LIB advancing
BOOST_AUTO_TEST_CASE(duplicate_votes) { try {
finality_test_cluster cluster;

cluster.initial_tests();

cluster.produce_and_push_block();
for (auto i = 0; i < 5; ++i) {
cluster.process_node1_vote(i, finality_test_cluster::vote_mode::strong);
Expand All @@ -495,6 +511,7 @@ BOOST_AUTO_TEST_CASE(duplicate_votes) { try {
// verify unknown_proposal votes are handled properly
BOOST_AUTO_TEST_CASE(unknown_proposal_votes) { try {
finality_test_cluster cluster;
cluster.initial_tests();

// node0 produces a block and pushes to node1
cluster.produce_and_push_block();
Expand All @@ -519,6 +536,7 @@ BOOST_AUTO_TEST_CASE(unknown_proposal_votes) { try {
// verify unknown finalizer_key votes are handled properly
BOOST_AUTO_TEST_CASE(unknown_finalizer_key_votes) { try {
finality_test_cluster cluster;
cluster.initial_tests();

// node0 produces a block and pushes to node1
cluster.produce_and_push_block();
Expand All @@ -542,7 +560,8 @@ BOOST_AUTO_TEST_CASE(unknown_finalizer_key_votes) { try {
// verify corrupted signature votes are handled properly
BOOST_AUTO_TEST_CASE(corrupted_signature_votes) { try {
finality_test_cluster cluster;

cluster.initial_tests();

// node0 produces a block and pushes to node1
cluster.produce_and_push_block();

Expand Down
Loading

0 comments on commit a3fa40e

Please sign in to comment.