Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.0] Add testcase validating the new fsi design from issue #621. #636

Merged
merged 25 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7b0f1e7
Start on `gh_534_liveness_issue` testcase
greg7mdp Aug 23, 2024
994a9a0
Merge branch 'gh_544' of github.com:AntelopeIO/spring into gh_621
greg7mdp Aug 23, 2024
3a9d896
Some progress on `gh_534_liveness_issue` testcase
greg7mdp Aug 23, 2024
fe23716
Merge branch 'gh_544' of github.com:AntelopeIO/spring into gh_621
greg7mdp Aug 24, 2024
baad9f2
Minor cleanup
greg7mdp Aug 26, 2024
040d4b2
Implement vote delay for `savanna_cluster`
greg7mdp Aug 26, 2024
0391637
Finish `gh_534_liveness_issue` testcase
greg7mdp Aug 26, 2024
74d1668
Validate testcase `gh_534_liveness_issue` with fsi changes.
greg7mdp Aug 26, 2024
bf5f7cd
Comment out new testcase as it fails with current fsi implementation
greg7mdp Aug 26, 2024
1d19e44
Add big block comment copied from issue #621.
greg7mdp Aug 26, 2024
5cbed82
Merge branch 'release/1.0' of github.com:AntelopeIO/spring into gh_621
greg7mdp Aug 26, 2024
b8d832c
Address PR comment.
greg7mdp Aug 26, 2024
27cbf08
Merge branch 'release/1.0' of github.com:AntelopeIO/spring into gh_621
greg7mdp Aug 26, 2024
8f383b6
Address PR comments, incl. not skipping slots for b5 to b8.
greg7mdp Aug 27, 2024
3a5f697
Make the checks a little cleaner by using `strong_qc/weak_qc` and sam…
greg7mdp Aug 27, 2024
9153e40
Forgot this file!
greg7mdp Aug 27, 2024
8a0163c
Merge branch 'release/1.0' of github.com:AntelopeIO/spring into gh_621
greg7mdp Aug 27, 2024
511c2a1
Remove `#ifdef`, align comments.
greg7mdp Aug 27, 2024
d873f75
Merge branch 'release/1.0' of github.com:AntelopeIO/spring into gh_621
greg7mdp Aug 27, 2024
d3bb815
Add `fsi` checks.
greg7mdp Aug 27, 2024
4d5f1cb
Make `check_fsi` checks a bit clearer.
greg7mdp Aug 27, 2024
81df896
Make `get_node_finalizers` private and fix test.
greg7mdp Aug 27, 2024
7db6083
Add `Boost::crc` as a controller dependency.
greg7mdp Aug 27, 2024
9758307
Move `check_fsi()` to `savanna_cluster` so it can be re-used.
greg7mdp Aug 27, 2024
cd44dc7
Add `Boost::crc` to `EosioTester.cmake.in` and `EosioTesterBuild.cmak…
greg7mdp Aug 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion libraries/testing/tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1304,7 +1304,8 @@ namespace eosio::testing {
auto [privkey, pubkey, pop] = get_bls_key(name);
local_finalizer_keys[pubkey.to_string()] = privkey.to_string();
}
control->set_node_finalizer_keys(local_finalizer_keys);
if (control)
control->set_node_finalizer_keys(local_finalizer_keys);
heifner marked this conversation as resolved.
Show resolved Hide resolved
}

base_tester::set_finalizers_output_t base_tester::set_active_finalizers(std::span<const account_name> names) {
Expand Down
30 changes: 20 additions & 10 deletions unittests/savanna_cluster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,48 @@ namespace savanna_cluster {

node_t::node_t(size_t node_idx, cluster_t& cluster, setup_policy policy /* = setup_policy::none */)
: tester(policy)
, node_idx(node_idx) {
, _node_idx(node_idx) {

// since we are creating forks, finalizers may be locked on another fork and unable to vote.
do_check_for_votes(false);

voted_block_cb = [&, node_idx](const eosio::chain::vote_signal_params& v) {
_voted_block_cb = [&, node_idx](const eosio::chain::vote_signal_params& v) {
// no mutex needed because controller is set in tester (via `disable_async_voting(true)`)
// to vote (and emit the `voted_block` signal) synchronously.
// --------------------------------------------------------------------------------------
vote_result_t status = std::get<1>(v);

if (status == vote_result_t::success) {
vote_message_ptr vote_msg = std::get<2>(v);
last_vote = vote_t(vote_msg);
if (propagate_votes)
cluster.dispatch_vote_to_peers(node_idx, skip_self_t::yes, std::get<2>(v));
_last_vote = vote_t(vote_msg);

if (_propagate_votes) {
if (_vote_delay)
_delayed_votes.push_back(std::move(vote_msg));
while (_delayed_votes.size() > _vote_delay) {
vote_message_ptr vote = _delayed_votes.front();
_delayed_votes.erase(_delayed_votes.cbegin());
cluster.dispatch_vote_to_peers(node_idx, skip_self_t::yes, vote);
}
if (!_vote_delay)
cluster.dispatch_vote_to_peers(node_idx, skip_self_t::yes, vote_msg);
}
}
};

// called on `commit_block`, for both blocks received from `push_block` and produced blocks
accepted_block_cb = [&, node_idx](const eosio::chain::block_signal_params& p) {
if (!pushing_a_block) {
_accepted_block_cb = [&, node_idx](const eosio::chain::block_signal_params& p) {
if (!_pushing_a_block) {
// we want to propagate only blocks we produce, not the ones we receive from the network
auto& b = std::get<0>(p);
cluster.push_block_to_peers(node_idx, skip_self_t::yes, b);
}
};

auto node_initialization_fn = [&, node_idx]() {
[[maybe_unused]] auto _a = control->voted_block().connect(voted_block_cb);
[[maybe_unused]] auto _b = control->accepted_block().connect(accepted_block_cb);
tester::set_node_finalizers(node_finalizers);
[[maybe_unused]] auto _a = control->voted_block().connect(_voted_block_cb);
[[maybe_unused]] auto _b = control->accepted_block().connect(_accepted_block_cb);
tester::set_node_finalizers(_node_finalizers);
cluster.get_new_blocks_from_peers(node_idx);
};

Expand Down
109 changes: 58 additions & 51 deletions unittests/savanna_cluster.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,34 +51,51 @@ namespace savanna_cluster {
vector<bls_private_key> privkeys;
};

// two classes for comparisons in BOOST_REQUIRE_EQUAL
// --------------------------------------------------
struct vote_t {
vote_t() : strong(false) {}
explicit vote_t(const vote_message_ptr& p) : id(p->block_id), strong(p->strong) {}
explicit vote_t(const signed_block_ptr& p, bool strong) : id(p->calculate_id()), strong(strong) {}

friend std::ostream& operator<<(std::ostream& s, const vote_t& v) {
s << "vote_t(" << v.id.str().substr(8, 16) << ", " << (v.strong ? "strong" : "weak") << ")";
return s;
}
bool operator==(const vote_t&) const = default;

block_id_type id;
bool strong;
};

struct qc_s {
explicit qc_s(const signed_block_ptr& p, bool strong) : block_num(p->block_num()), strong(strong) {}
explicit qc_s(const std::optional<qc_t>& qc) : block_num(qc->block_num), strong(qc->is_strong()) {}

friend std::ostream& operator<<(std::ostream& s, const qc_s& v) {
s << "qc_s(" << v.block_num << ", " << (v.strong ? "strong" : "weak") << ")";
return s;
}
bool operator==(const qc_s&) const = default;

uint32_t block_num; // claimed block
bool strong;
};

// ----------------------------------------------------------------------------
class node_t : public tester {
private:
size_t node_idx;
bool pushing_a_block{false};
size_t _node_idx;
bool _pushing_a_block{false};
bool _propagate_votes{true}; // if false, votes are dropped
vote_t _last_vote;
std::vector<account_name> _node_finalizers;

std::function<void(const block_signal_params&)> accepted_block_cb;
std::function<void(const vote_signal_params&)> voted_block_cb;
size_t _vote_delay{0}; // delay vote propagation by this much
std::vector<vote_message_ptr> _delayed_votes;

public:
struct vote_t {
vote_t() : strong(false) {}
explicit vote_t(const vote_message_ptr& p) : id(p->block_id), strong(p->strong) {}
explicit vote_t(const signed_block_ptr& p, bool strong) : id(p->calculate_id()), strong(strong) {}

friend std::ostream& operator<<(std::ostream& s, const vote_t& v) {
s << "vote_t(" << v.id.str().substr(8, 16) << ", " << (v.strong ? "strong" : "weak") << ")";
return s;
}
bool operator==(const vote_t&) const = default;

block_id_type id;
bool strong;
};

bool propagate_votes{true};
vote_t last_vote;
std::vector<account_name> node_finalizers;
std::function<void(const block_signal_params&)> _accepted_block_cb;
std::function<void(const vote_signal_params&)> _voted_block_cb;

public:
node_t(size_t node_idx, cluster_t& cluster, setup_policy policy = setup_policy::none);
Expand All @@ -87,9 +104,15 @@ namespace savanna_cluster {

node_t(node_t&&) = default;

bool& propagate_votes() { return _propagate_votes; }

size_t& vote_delay() { return _vote_delay; }

const vote_t& last_vote() const { return _last_vote; }

void set_node_finalizers(std::span<const account_name> names) {
node_finalizers = std::vector<account_name>{ names.begin(), names.end() };
tester::set_node_finalizers(node_finalizers);
_node_finalizers = std::vector<account_name>{ names.begin(), names.end() };
tester::set_node_finalizers(_node_finalizers);
}

void transition_to_savanna(std::span<const account_name> finalizer_policy_names) {
Expand Down Expand Up @@ -167,8 +190,8 @@ namespace savanna_cluster {

void push_block(const signed_block_ptr& b) {
if (is_open() && !fetch_block_by_id(b->calculate_id())) {
assert(!pushing_a_block);
fc::scoped_set_value set_pushing_a_block(pushing_a_block, true);
assert(!_pushing_a_block);
fc::scoped_set_value set_pushing_a_block(_pushing_a_block, true);
tester::push_block(b);
}
}
Expand All @@ -189,19 +212,19 @@ namespace savanna_cluster {
}

std::string snapshot() const {
dlog("node ${i} - taking snapshot", ("i", node_idx));
dlog("node ${i} - taking snapshot", ("i", _node_idx));
auto writer = buffered_snapshot_suite::get_writer();
control->write_snapshot(writer);
return buffered_snapshot_suite::finalize(writer);
}

void open_from_snapshot(const std::string& snapshot) {
dlog("node ${i} - restoring from snapshot", ("i", node_idx));
dlog("node ${i} - restoring from snapshot", ("i", _node_idx));
open(buffered_snapshot_suite::get_reader(snapshot));
}

std::vector<uint8_t> save_fsi() const {
dlog("node ${i} - saving fsi", ("i", node_idx));
dlog("node ${i} - saving fsi", ("i", _node_idx));
auto finalizer_path = get_fsi_path();
std::ifstream file(finalizer_path.generic_string(), std::ios::binary | std::ios::ate);
std::streamsize size = file.tellg();
Expand All @@ -214,21 +237,21 @@ namespace savanna_cluster {
}

void overwrite_fsi(const std::vector<uint8_t>& fsi) const {
dlog("node ${i} - overwriting fsi", ("i", node_idx));
dlog("node ${i} - overwriting fsi", ("i", _node_idx));
auto finalizer_path = get_fsi_path();
std::ofstream file(finalizer_path.generic_string(), std::ios::binary);
assert(!fsi.empty());
file.write((const char *)fsi.data(), fsi.size());
}

void remove_fsi() {
dlog("node ${i} - removing fsi", ("i", node_idx));
dlog("node ${i} - removing fsi", ("i", _node_idx));
remove_all(get_fsi_path());
}

void remove_state() {
auto state_path = cfg.state_dir;
dlog("node ${i} - removing state data from: ${state_path}", ("i", node_idx)("${state_path}", state_path));
dlog("node ${i} - removing state data from: ${state_path}", ("i", _node_idx)("${state_path}", state_path));
remove_all(state_path);
fs::create_directories(state_path);
}
Expand All @@ -246,7 +269,7 @@ namespace savanna_cluster {
for (auto const& dir_entry : std::filesystem::directory_iterator{path}) {
auto path = dir_entry.path();
if (path.filename().generic_string() != "reversible") {
dlog("node ${i} - removing : ${path}", ("i", node_idx)("${path}", path));
dlog("node ${i} - removing : ${path}", ("i", _node_idx)("${path}", path));
remove_all(path);
}
}
Expand All @@ -259,7 +282,7 @@ namespace savanna_cluster {
void remove_blocks(bool rm_blocks_log) {
auto reversible_path = cfg.blocks_dir / config::reversible_blocks_dir_name;
auto& path = rm_blocks_log ? cfg.blocks_dir : reversible_path;
dlog("node ${i} - removing : ${path}", ("i", node_idx)("${path}", path));
dlog("node ${i} - removing : ${path}", ("i", _node_idx)("${path}", path));
remove_all(path);
fs::create_directories(reversible_path);
}
Expand Down Expand Up @@ -471,22 +494,6 @@ namespace savanna_cluster {

size_t num_nodes() const { return _num_nodes; }

// Class for comparisons in BOOST_REQUIRE_EQUAL
// --------------------------------------------
struct qc_s {
explicit qc_s(const signed_block_ptr& p, bool strong) : block_num(p->block_num()), strong(strong) {}
explicit qc_s(const std::optional<qc_t>& qc) : block_num(qc->block_num), strong(qc->is_strong()) {}

friend std::ostream& operator<<(std::ostream& s, const qc_s& v) {
s << "qc_s(" << v.block_num << ", " << (v.strong ? "strong" : "weak") << ")";
return s;
}
bool operator==(const qc_s&) const = default;

uint32_t block_num; // claimed block
bool strong;
};

static qc_claim_t qc_claim(const signed_block_ptr& b) {
return b->extract_header_extension<finality_extension>().qc_claim;
}
Expand Down
12 changes: 6 additions & 6 deletions unittests/savanna_finalizer_policy_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ BOOST_FIXTURE_TEST_CASE(policy_change, savanna_cluster::cluster_t) try {
// --------------------------------------------------------------------------------------------------
B.close();
// update `B.node_finalizers` with the new key so that B can vote both on the active and pending policy
B.node_finalizers = std::vector<account_name>{ _fin_keys[1], _fin_keys[num_nodes()] }; // see node_t::node_t
B.set_node_finalizers(std::vector<account_name>{ _fin_keys[1], _fin_keys[num_nodes()] }); // see node_t::node_t
B.open();

// quick sanity check
Expand Down Expand Up @@ -144,8 +144,8 @@ BOOST_FIXTURE_TEST_CASE(policy_change_reduce_threshold_replace_all_keys, savanna
// -----------------------------------------------------------------------------------------------
A.close();
B.close();
A.node_finalizers = std::vector<account_name>{ _fin_keys[0], _fin_keys[num_nodes()] };
B.node_finalizers = std::vector<account_name>{ _fin_keys[1], _fin_keys[num_nodes() + 1] };
A.set_node_finalizers(std::vector<account_name>{ _fin_keys[0], _fin_keys[num_nodes()] });
B.set_node_finalizers(std::vector<account_name>{ _fin_keys[1], _fin_keys[num_nodes() + 1] });
A.open();
B.open();

Expand Down Expand Up @@ -206,9 +206,9 @@ BOOST_FIXTURE_TEST_CASE(policy_change_restart_from_snapshot, savanna_cluster::cl
A.close();
B.close();
C.close();
A.node_finalizers = std::vector<account_name>{ _fin_keys[0], _fin_keys[num_nodes()] };
B.node_finalizers = std::vector<account_name>{ _fin_keys[1], _fin_keys[num_nodes() + 1] };
C.node_finalizers = std::vector<account_name>{ _fin_keys[2], _fin_keys[num_nodes() + 2] };
A.set_node_finalizers(std::vector<account_name>{ _fin_keys[0], _fin_keys[num_nodes()] });
B.set_node_finalizers(std::vector<account_name>{ _fin_keys[1], _fin_keys[num_nodes() + 1] });
C.set_node_finalizers(std::vector<account_name>{ _fin_keys[2], _fin_keys[num_nodes() + 2] });
A.open();
B.open();
C.open();
Expand Down
Loading
Loading