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

Avoid voting until caught up with network #262

Merged
merged 6 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
13 changes: 6 additions & 7 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1232,7 +1232,7 @@ struct controller_impl {
chain_id( chain_id ),
read_mode( cfg.read_mode ),
thread_pool(),
my_finalizers(fc::time_point::now(), cfg.finalizers_dir / "safety.dat"),
my_finalizers(cfg.finalizers_dir / "safety.dat"),
wasmif( conf.wasm_runtime, conf.eosvmoc_tierup, db, conf.state_dir, conf.eosvmoc_config, !conf.profile_accounts.empty() )
{
assert(cfg.chain_thread_pool_size > 0);
Expand Down Expand Up @@ -3701,8 +3701,7 @@ struct controller_impl {
return;

// Each finalizer configured on the node which is present in the active finalizer policy may create and sign a vote.
my_finalizers.maybe_vote(
*bsp->active_finalizer_policy, bsp, bsp->strong_digest, [&](const vote_message_ptr& vote) {
my_finalizers.maybe_vote(bsp, [&](const vote_message_ptr& vote) {
// net plugin subscribed to this signal. it will broadcast the vote message on receiving the signal
emit(voted_block, std::tuple{uint32_t{0}, vote_status::success, std::cref(vote)}, __FILE__, __LINE__);

Expand Down Expand Up @@ -4612,8 +4611,8 @@ struct controller_impl {
wasmif.code_block_num_last_used(code_hash, vm_type, vm_version, block_num);
}

void set_node_finalizer_keys(const bls_pub_priv_key_map_t& finalizer_keys) {
my_finalizers.set_keys(finalizer_keys);
void set_node_finalizer_keys(const bls_pub_priv_key_map_t& finalizer_keys, bool enable_immediate_voting) {
my_finalizers.set_keys(finalizer_keys, enable_immediate_voting);
}

bool irreversible_mode() const { return read_mode == db_read_mode::IRREVERSIBLE; }
Expand Down Expand Up @@ -5763,8 +5762,8 @@ void controller::code_block_num_last_used(const digest_type& code_hash, uint8_t
return my->code_block_num_last_used(code_hash, vm_type, vm_version, block_num);
}

void controller::set_node_finalizer_keys(const bls_pub_priv_key_map_t& finalizer_keys) {
my->set_node_finalizer_keys(finalizer_keys);
void controller::set_node_finalizer_keys(const bls_pub_priv_key_map_t& finalizer_keys, bool enable_immediate_voting) {
my->set_node_finalizer_keys(finalizer_keys, enable_immediate_voting);
}

/// Protocol feature activation handlers:
Expand Down
4 changes: 3 additions & 1 deletion libraries/chain/finality/finalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ my_finalizers_t::fsi_map my_finalizers_t::load_finalizer_safety_info() {
}

// ----------------------------------------------------------------------------------------
void my_finalizers_t::set_keys(const std::map<std::string, std::string>& finalizer_keys) {
void my_finalizers_t::set_keys(const std::map<std::string, std::string>& finalizer_keys, bool enable_immediate_voting) {
if (finalizer_keys.empty())
return;

Expand All @@ -226,6 +226,8 @@ void my_finalizers_t::set_keys(const std::map<std::string, std::string>& finaliz

// now only inactive finalizers remain in safety_info => move it to inactive_safety_info
inactive_safety_info = std::move(safety_info);

enable_voting = enable_immediate_voting;
}


Expand Down
2 changes: 1 addition & 1 deletion libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ namespace eosio::chain {
void set_to_read_window();
bool is_write_window() const;
void code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, uint32_t block_num);
void set_node_finalizer_keys(const bls_pub_priv_key_map_t& finalizer_keys);
void set_node_finalizer_keys(const bls_pub_priv_key_map_t& finalizer_keys, bool enable_immediate_voting = false);

private:
friend class apply_context;
Expand Down
25 changes: 15 additions & 10 deletions libraries/chain/include/eosio/chain/finality/finalizer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,41 +71,44 @@ namespace eosio::chain {
using fsi_map = std::map<bls_public_key, fsi_t>;

private:
const block_timestamp_type t_startup; // nodeos startup time, used for default safety_information
const std::filesystem::path persist_file_path; // where we save the safety data
mutable std::mutex mtx;
mutable fc::datastream<fc::cfile> persist_file; // we want to keep the file open for speed
std::map<bls_public_key, finalizer> finalizers; // the active finalizers for this node, loaded at startup, not mutated afterwards
fsi_map inactive_safety_info; // loaded at startup, not mutated afterwards
fsi_t default_fsi = fsi_t::unset_fsi(); // default provided at spring startup
mutable bool inactive_safety_info_written{false};
bool enable_voting = false;

public:
my_finalizers_t(block_timestamp_type startup_time, const std::filesystem::path& persist_file_path)
: t_startup(startup_time)
, persist_file_path(persist_file_path)
explicit my_finalizers_t(const std::filesystem::path& persist_file_path)
: persist_file_path(persist_file_path)
{}

template<class F> // thread safe
void maybe_vote(const finalizer_policy& fin_pol,
const block_state_ptr& bsp,
const digest_type& digest,
F&& process_vote) {
void maybe_vote(const block_state_ptr& bsp, F&& process_vote) {

if (finalizers.empty())
return;

assert(bsp->active_finalizer_policy);
const auto& fin_pol = *bsp->active_finalizer_policy;

std::vector<vote_message_ptr> votes;
votes.reserve(finalizers.size());

// Possible improvement in the future, look at locking only individual finalizers and releasing the lock for writing the file.
// Would require making sure that only the latest is ever written to the file and that the file access was protected separately.
std::unique_lock g(mtx);

if (!enable_voting && bsp->timestamp() < fc::time_point::now() - fc::seconds(30))
linh2931 marked this conversation as resolved.
Show resolved Hide resolved
return;
enable_voting = true;
linh2931 marked this conversation as resolved.
Show resolved Hide resolved

// first accumulate all the votes
for (const auto& f : fin_pol.finalizers) {
if (auto it = finalizers.find(f.public_key); it != finalizers.end()) {
vote_message_ptr vote_msg = it->second.maybe_vote(it->first, bsp, digest);
vote_message_ptr vote_msg = it->second.maybe_vote(it->first, bsp, bsp->strong_digest);
if (vote_msg)
votes.push_back(std::move(vote_msg));
}
Expand All @@ -127,7 +130,9 @@ namespace eosio::chain {
return std::ranges::all_of(std::views::keys(finalizers), std::forward<F>(f));
}

void set_keys(const std::map<std::string, std::string>& finalizer_keys); // only call on startup
/// only call on startup
/// @param enable_immediate_voting if true enable immediate voting on startup (for testing)
void set_keys(const std::map<std::string, std::string>& finalizer_keys, bool enable_immediate_voting);
void set_default_safety_information(const fsi_t& fsi);

// following two member functions could be private, but are used in testing, not thread safe
Expand Down
4 changes: 2 additions & 2 deletions libraries/testing/tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1253,7 +1253,7 @@ namespace eosio::testing {
("pop", pop.to_string()));
}

control->set_node_finalizer_keys(local_finalizer_keys);
greg7mdp marked this conversation as resolved.
Show resolved Hide resolved
control->set_node_finalizer_keys(local_finalizer_keys, true);

fc::mutable_variant_object fin_policy_variant;
fin_policy_variant("threshold", input.threshold);
Expand All @@ -1271,7 +1271,7 @@ 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);
control->set_node_finalizer_keys(local_finalizer_keys, true);
}

base_tester::set_finalizers_output_t base_tester::set_active_finalizers(std::span<const account_name> names) {
Expand Down
3 changes: 3 additions & 0 deletions plugins/net_plugin/net_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2705,6 +2705,9 @@ namespace eosio {
}

void dispatch_manager::bcast_vote_msg( uint32_t exclude_peer, send_buffer_type msg ) {
if (my_impl->sync_master->syncing_from_peer())
return;

my_impl->connections.for_each_block_connection( [exclude_peer, msg{std::move(msg)}]( auto& cp ) {
if( !cp->current() ) return true;
if( cp->connection_id == exclude_peer ) return true;
Expand Down
32 changes: 16 additions & 16 deletions unittests/finalizer_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ BOOST_AUTO_TEST_CASE( basic_finalizer_safety_file_io ) try {
bls_pub_priv_key_map_t local_finalizers = { { k.pubkey_str, k.privkey_str } };

{
my_finalizers_t fset{block_timestamp_type{}, safety_file_path};
fset.set_keys(local_finalizers);
my_finalizers_t fset{safety_file_path};
fset.set_keys(local_finalizers, false);

fset.set_fsi(k.pubkey, fsi);
fset.save_finalizer_safety_info();
Expand All @@ -101,8 +101,8 @@ BOOST_AUTO_TEST_CASE( basic_finalizer_safety_file_io ) try {
}

{
my_finalizers_t fset{block_timestamp_type{}, safety_file_path};
fset.set_keys(local_finalizers); // that's when the finalizer safety file is read
my_finalizers_t fset{safety_file_path};
fset.set_keys(local_finalizers, false); // that's when the finalizer safety file is read

// make sure the safety info for our finalizer that we saved above is restored correctly
BOOST_CHECK_EQUAL(fset.get_fsi(k.pubkey), fsi);
Expand All @@ -123,8 +123,8 @@ BOOST_AUTO_TEST_CASE( corrupt_finalizer_safety_file ) try {
bls_pub_priv_key_map_t local_finalizers = { { k.pubkey_str, k.privkey_str } };

{
my_finalizers_t fset{block_timestamp_type{}, safety_file_path};
fset.set_keys(local_finalizers);
my_finalizers_t fset{safety_file_path};
fset.set_keys(local_finalizers, false);

fset.set_fsi(k.pubkey, fsi);
fset.save_finalizer_safety_info();
Expand All @@ -140,8 +140,8 @@ BOOST_AUTO_TEST_CASE( corrupt_finalizer_safety_file ) try {
}

{
my_finalizers_t fset{block_timestamp_type{}, safety_file_path};
BOOST_REQUIRE_THROW(fset.set_keys(local_finalizers), // that's when the finalizer safety file is read
my_finalizers_t fset{safety_file_path};
BOOST_REQUIRE_THROW(fset.set_keys(local_finalizers, false), // that's when the finalizer safety file is read
finalizer_safety_exception);

// make sure the safety info for our finalizer that we saved above is restored correctly
Expand All @@ -159,9 +159,9 @@ BOOST_AUTO_TEST_CASE( finalizer_safety_file_io ) try {
std::vector<bls_keys_t> keys = create_keys(10);

{
my_finalizers_t fset{block_timestamp_type{}, safety_file_path};
my_finalizers_t fset{safety_file_path};
bls_pub_priv_key_map_t local_finalizers = create_local_finalizers<1, 3, 5, 6>(keys);
fset.set_keys(local_finalizers);
fset.set_keys(local_finalizers, false);

set_fsi<decltype(fsi), 1, 3, 5, 6>(fset, keys, fsi);
fset.save_finalizer_safety_info();
Expand All @@ -171,9 +171,9 @@ BOOST_AUTO_TEST_CASE( finalizer_safety_file_io ) try {
}

{
my_finalizers_t fset{block_timestamp_type{}, safety_file_path};
my_finalizers_t fset{safety_file_path};
bls_pub_priv_key_map_t local_finalizers = create_local_finalizers<3>(keys);
fset.set_keys(local_finalizers);
fset.set_keys(local_finalizers, false);

// make sure the safety info for our finalizer that we saved above is restored correctly
BOOST_CHECK_EQUAL(fset.get_fsi(keys[3].pubkey), fsi[3]);
Expand All @@ -186,9 +186,9 @@ BOOST_AUTO_TEST_CASE( finalizer_safety_file_io ) try {
}

{
my_finalizers_t fset{block_timestamp_type{}, safety_file_path};
my_finalizers_t fset{safety_file_path};
bls_pub_priv_key_map_t local_finalizers = create_local_finalizers<3>(keys);
fset.set_keys(local_finalizers);
fset.set_keys(local_finalizers, false);

// make sure the safety info for our finalizer that we saved above is restored correctly
BOOST_CHECK_EQUAL(fset.get_fsi(keys[3].pubkey), fsi[4]);
Expand All @@ -197,9 +197,9 @@ BOOST_AUTO_TEST_CASE( finalizer_safety_file_io ) try {
// even though we didn't activate finalizers 1, 5, or 6 in the prior test, and we wrote the safety file,
// make sure we have not lost the fsi that was set originally for these finalizers.
{
my_finalizers_t fset{block_timestamp_type{}, safety_file_path};
my_finalizers_t fset{safety_file_path};
bls_pub_priv_key_map_t local_finalizers = create_local_finalizers<1, 5, 6>(keys);
fset.set_keys(local_finalizers);
fset.set_keys(local_finalizers, false);

// make sure the safety info for our previously inactive finalizer was preserved
BOOST_CHECK_EQUAL(fset.get_fsi(keys[1].pubkey), fsi[1]);
Expand Down
Loading