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

Fix online reps live votes update #3084

Merged
merged 3 commits into from
Jan 28, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
38 changes: 19 additions & 19 deletions nano/core_test/active_transactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -613,19 +613,19 @@ TEST (active_transactions, vote_replays)
ASSERT_EQ (2, node.active.size ());
// First vote is not a replay and confirms the election, second vote should be a replay since the election has confirmed but not yet removed
auto vote_send1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 0, send1));
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote_send1, true));
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote_send1));
ASSERT_EQ (2, node.active.size ());
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_send1, true));
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_send1));
// Wait until the election is removed, at which point the vote is still a replay since it's been recently confirmed
ASSERT_TIMELY (3s, node.active.size () == 1);
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_send1, true));
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_send1));
// Open new account
auto vote_open1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 0, open1));
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote_open1, true));
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote_open1));
ASSERT_EQ (1, node.active.size ());
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_open1, true));
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_open1));
ASSERT_TIMELY (3s, node.active.empty ());
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_open1, true));
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_open1));
ASSERT_EQ (nano::Gxrb_ratio, node.ledger.weight (key.pub));

auto send2 = builder.make_block ()
Expand All @@ -643,27 +643,27 @@ TEST (active_transactions, vote_replays)
ASSERT_EQ (1, node.active.size ());
auto vote1_send2 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 0, send2));
auto vote2_send2 (std::make_shared<nano::vote> (key.pub, key.prv, 0, send2));
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote2_send2, true));
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote2_send2));
ASSERT_EQ (1, node.active.size ());
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote2_send2, true));
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote2_send2));
ASSERT_EQ (1, node.active.size ());
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote1_send2, true));
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote1_send2));
ASSERT_EQ (1, node.active.size ());
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote1_send2, true));
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote1_send2));
ASSERT_TIMELY (3s, node.active.empty ());
ASSERT_EQ (0, node.active.size ());
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote1_send2, true));
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote2_send2, true));
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote1_send2));
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote2_send2));

// Removing blocks as recently confirmed makes every vote indeterminate
{
nano::lock_guard<std::mutex> guard (node.active.mutex);
node.active.recently_confirmed.clear ();
}
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote_send1, true));
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote_open1, true));
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote1_send2, true));
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote2_send2, true));
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote_send1));
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote_open1));
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote1_send2));
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote2_send2));
}
}

Expand Down Expand Up @@ -1498,7 +1498,7 @@ TEST (active_transactions, conflicting_block_vote_existing_election)
ASSERT_EQ (1, node.active.size ());

// Vote for conflicting block, but the block does not yet exist in the ledger
node.active.vote (vote_fork, true);
node.active.vote (vote_fork);

// Block now gets processed
ASSERT_EQ (nano::process_result::fork, node.process_local (fork).code);
Expand Down Expand Up @@ -1735,9 +1735,9 @@ TEST (active_transactions, pessimistic_elections)
// Make dummy election with winner.
{
nano::election election1 (
node, send, [](auto const &) {}, [](auto const &, bool) {}, false, nano::election_behavior::normal);
node, send, [](auto const &) {}, [](auto const &) {}, false, nano::election_behavior::normal);
nano::election election2 (
node, open, [](auto const &) {}, [](auto const &, bool) {}, false, nano::election_behavior::normal);
node, open, [](auto const &) {}, [](auto const &) {}, false, nano::election_behavior::normal);
node.active.add_expired_optimistic_election (election1);
node.active.add_expired_optimistic_election (election2);
}
Expand Down
2 changes: 1 addition & 1 deletion nano/core_test/conflicts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ TEST (conflicts, add_existing)
auto election1 = node1.active.insert (send2);
ASSERT_EQ (1, node1.active.size ());
auto vote1 (std::make_shared<nano::vote> (key2.pub, key2.prv, 0, send2));
node1.active.vote (vote1, true);
node1.active.vote (vote1);
ASSERT_NE (nullptr, election1.election);
ASSERT_EQ (2, election1.election->votes ().size ());
auto votes (election1.election->votes ());
Expand Down
12 changes: 6 additions & 6 deletions nano/core_test/election.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ TEST (election, quorum_minimum_flip_success)
ASSERT_NE (nullptr, election.election);
ASSERT_EQ (2, election.election->blocks ().size ());
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send2));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
node1.block_processor.flush ();
ASSERT_NE (nullptr, node1.block (send2->hash ()));
ASSERT_TRUE (election.election->confirmed ());
Expand Down Expand Up @@ -98,7 +98,7 @@ TEST (election, quorum_minimum_flip_fail)
ASSERT_NE (nullptr, election.election);
ASSERT_EQ (2, election.election->blocks ().size ());
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send2));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
node1.block_processor.flush ();
ASSERT_NE (nullptr, node1.block (send1->hash ()));
ASSERT_FALSE (election.election->confirmed ());
Expand Down Expand Up @@ -130,7 +130,7 @@ TEST (election, quorum_minimum_confirm_success)
ASSERT_NE (nullptr, election.election);
ASSERT_EQ (1, election.election->blocks ().size ());
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send1));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
node1.block_processor.flush ();
ASSERT_NE (nullptr, node1.block (send1->hash ()));
ASSERT_TRUE (election.election->confirmed ());
Expand Down Expand Up @@ -162,7 +162,7 @@ TEST (election, quorum_minimum_confirm_fail)
ASSERT_NE (nullptr, election.election);
ASSERT_EQ (1, election.election->blocks ().size ());
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send1));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
node1.block_processor.flush ();
ASSERT_NE (nullptr, node1.block (send1->hash ()));
ASSERT_FALSE (election.election->confirmed ());
Expand Down Expand Up @@ -232,7 +232,7 @@ TEST (election, quorum_minimum_update_weight_before_quorum_checks)
ASSERT_NE (nullptr, election.election);
ASSERT_EQ (1, election.election->blocks ().size ());
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, nano::milliseconds_since_epoch (), send1));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
auto vote2 (std::make_shared<nano::vote> (key1.pub, key1.prv, nano::milliseconds_since_epoch (), send1));
auto channel = node1.network.find_channel (node2.network.endpoint ());
ASSERT_NE (channel, nullptr);
Expand All @@ -243,7 +243,7 @@ TEST (election, quorum_minimum_update_weight_before_quorum_checks)
// Modify online_m for online_reps to more than is available, this checks that voting below updates it to current online reps.
node1.online_reps.online_m = node_config.online_weight_minimum.number () + 20;
}
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2, true));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2));
node1.block_processor.flush ();
ASSERT_NE (nullptr, node1.block (send1->hash ()));
ASSERT_TRUE (election.election->confirmed ());
Expand Down
14 changes: 7 additions & 7 deletions nano/core_test/ledger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -790,9 +790,9 @@ TEST (votes, add_one)
auto election1 = node1.active.insert (send1);
ASSERT_EQ (1, election1.election->votes ().size ());
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send1));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
auto vote2 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 2, send1));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2, true));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2));
ASSERT_EQ (2, election1.election->votes ().size ());
auto votes1 (election1.election->votes ());
auto existing1 (votes1.find (nano::dev_genesis_key.pub));
Expand All @@ -818,9 +818,9 @@ TEST (votes, add_two)
nano::keypair key2;
auto send2 (std::make_shared<nano::send_block> (genesis.hash (), key2.pub, 0, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, 0));
auto vote2 (std::make_shared<nano::vote> (key2.pub, key2.prv, 1, send2));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2, true));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2));
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send1));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
ASSERT_EQ (3, election1.election->votes ().size ());
auto votes1 (election1.election->votes ());
ASSERT_NE (votes1.end (), votes1.find (nano::dev_genesis_key.pub));
Expand Down Expand Up @@ -855,7 +855,7 @@ TEST (votes, add_existing)
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (node1.store.tx_begin_write (), *send1).code);
auto election1 = node1.active.insert (send1);
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send1));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
// Block is already processed from vote
ASSERT_TRUE (node1.active.publish (send1));
ASSERT_EQ (1, election1.election->last_votes[nano::dev_genesis_key.pub].timestamp);
Expand All @@ -875,14 +875,14 @@ TEST (votes, add_existing)
nano::unique_lock<std::mutex> lock (election1.election->mutex);
election1.election->last_votes[nano::dev_genesis_key.pub].time = std::chrono::steady_clock::now () - std::chrono::seconds (20);
lock.unlock ();
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2, true));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2));
ASSERT_FALSE (node1.active.publish (send2));
ASSERT_EQ (2, election1.election->last_votes[nano::dev_genesis_key.pub].timestamp);
// Also resend the old vote, and see if we respect the timestamp
lock.lock ();
election1.election->last_votes[nano::dev_genesis_key.pub].time = std::chrono::steady_clock::now () - std::chrono::seconds (20);
lock.unlock ();
ASSERT_EQ (nano::vote_code::replay, node1.active.vote (vote1, true));
ASSERT_EQ (nano::vote_code::replay, node1.active.vote (vote1));
ASSERT_EQ (2, election1.election->votes ()[nano::dev_genesis_key.pub].timestamp);
auto votes (election1.election->votes ());
ASSERT_EQ (2, votes.size ());
Expand Down
54 changes: 53 additions & 1 deletion nano/core_test/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2432,6 +2432,58 @@ TEST (node, online_reps)
ASSERT_EQ (node1.config.online_weight_minimum, node1.online_reps.trended ());
}

namespace nano
{
TEST (node, online_reps_rep_crawler)
{
nano::system system;
nano::node_flags flags;
flags.disable_rep_crawler = true;
auto & node1 = *system.add_node (flags);
auto vote = std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, nano::milliseconds_since_epoch (), std::vector<nano::block_hash>{ nano::genesis_hash });
ASSERT_EQ (0, node1.online_reps.online ());
// Without rep crawler
node1.vote_processor.vote_blocking (vote, std::make_shared<nano::transport::channel_loopback> (node1));
ASSERT_EQ (0, node1.online_reps.online ());
// After inserting to rep crawler
{
nano::lock_guard<std::mutex> guard (node1.rep_crawler.probable_reps_mutex);
node1.rep_crawler.active.insert (nano::genesis_hash);
}
node1.vote_processor.vote_blocking (vote, std::make_shared<nano::transport::channel_loopback> (node1));
ASSERT_EQ (nano::genesis_amount, node1.online_reps.online ());
}
}

TEST (node, online_reps_election)
{
nano::system system;
nano::node_flags flags;
flags.disable_rep_crawler = true;
auto & node1 = *system.add_node (flags);
// Start election
nano::genesis genesis;
nano::keypair key;
nano::state_block_builder builder;
auto send1 = builder.make_block ()
.account (nano::dev_genesis_key.pub)
.previous (genesis.hash ())
.representative (nano::dev_genesis_key.pub)
.balance (nano::genesis_amount - nano::Gxrb_ratio)
.link (key.pub)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*node1.work_generate_blocking (genesis.hash ()))
.build_shared ();
node1.process_active (send1);
node1.block_processor.flush ();
ASSERT_EQ (1, node1.active.size ());
// Process vote for ongoing election
auto vote = std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, nano::milliseconds_since_epoch (), std::vector<nano::block_hash>{ send1->hash () });
ASSERT_EQ (0, node1.online_reps.online ());
node1.vote_processor.vote_blocking (vote, std::make_shared<nano::transport::channel_loopback> (node1));
ASSERT_EQ (nano::genesis_amount - nano::Gxrb_ratio, node1.online_reps.online ());
}

TEST (node, block_confirm)
{
std::vector<nano::transport::transport_type> types{ nano::transport::transport_type::tcp, nano::transport::transport_type::udp };
Expand Down Expand Up @@ -3946,7 +3998,7 @@ TEST (node, rollback_vote_self)
{
ASSERT_EQ (1, election->votes ().size ());
// Vote with key to switch the winner
election->vote (key.pub, 0, fork->hash (), true);
election->vote (key.pub, 0, fork->hash ());
ASSERT_EQ (2, election->votes ().size ());
// The winner changed
ASSERT_EQ (election->winner (), fork);
Expand Down
6 changes: 3 additions & 3 deletions nano/core_test/vote_processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ TEST (vote_processor, no_broadcast_local)
ASSERT_FALSE (node.wallets.reps ().have_half_rep ());
// Process a vote
auto vote = std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, nano::milliseconds_since_epoch (), std::vector<nano::block_hash>{ send->hash () });
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote, true));
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote));
// Make sure the vote was processed
auto election (node.active.election (send->qualified_root ()));
ASSERT_NE (nullptr, election);
Expand Down Expand Up @@ -242,7 +242,7 @@ TEST (vote_processor, no_broadcast_local)
node.block_confirm (send2);
// Process a vote
auto vote2 = std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, nano::milliseconds_since_epoch (), std::vector<nano::block_hash>{ send2->hash () });
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote2, true));
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote2));
// Make sure the vote was processed
auto election2 (node.active.election (send2->qualified_root ()));
ASSERT_NE (nullptr, election2);
Expand Down Expand Up @@ -276,7 +276,7 @@ TEST (vote_processor, no_broadcast_local)
ASSERT_TRUE (node.wallets.reps ().have_half_rep ());
// Process a vote
auto vote3 = std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, nano::milliseconds_since_epoch (), std::vector<nano::block_hash>{ open->hash () });
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote3, true));
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote3));
// Make sure the vote was processed
auto election3 (node.active.election (open->qualified_root ()));
ASSERT_NE (nullptr, election3);
Expand Down
13 changes: 5 additions & 8 deletions nano/node/active_transactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,12 +826,9 @@ nano::election_insertion_result nano::active_transactions::insert_impl (nano::un
double multiplier (normalized_multiplier (*block_a));
bool prioritized = roots.size () < prioritized_cutoff || multiplier > last_prioritized_multiplier.value_or (0);
result.election = nano::make_shared<nano::election> (
node, block_a, confirmation_action_a, [& node = node](auto const & rep_a, bool rep_is_active_a) {
if (rep_is_active_a)
{
// Representative is defined as online if replying to live votes or rep_crawler queries
node.online_reps.observe (rep_a);
}
node, block_a, confirmation_action_a, [& node = node](auto const & rep_a) {
// Representative is defined as online if replying to live votes or rep_crawler queries
node.online_reps.observe (rep_a);
},
prioritized, election_behavior_a);
roots.get<tag_root> ().emplace (nano::active_transactions::conflict_info{ root, multiplier, result.election, epoch, previous_balance });
Expand Down Expand Up @@ -869,7 +866,7 @@ nano::election_insertion_result nano::active_transactions::insert (std::shared_p
}

// Validate a vote and apply it to the current election if one exists
nano::vote_code nano::active_transactions::vote (std::shared_ptr<nano::vote> const & vote_a, bool active_in_rep_crawler_a)
nano::vote_code nano::active_transactions::vote (std::shared_ptr<nano::vote> const & vote_a)
{
nano::vote_code result{ nano::vote_code::indeterminate };
// If all hashes were recently confirmed then it is a replay
Expand Down Expand Up @@ -923,7 +920,7 @@ nano::vote_code nano::active_transactions::vote (std::shared_ptr<nano::vote> con
bool processed (false);
for (auto const & [election, block_hash] : process)
{
auto const result_l = election->vote (vote_a->account, vote_a->timestamp, block_hash, active_in_rep_crawler_a);
auto const result_l = election->vote (vote_a->account, vote_a->timestamp, block_hash);
processed = processed || result_l.processed;
replay = replay || result_l.replay;
}
Expand Down
2 changes: 1 addition & 1 deletion nano/node/active_transactions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class active_transactions final
nano::election_insertion_result insert (std::shared_ptr<nano::block> const &, boost::optional<nano::uint128_t> const & = boost::none, nano::election_behavior = nano::election_behavior::normal, std::function<void(std::shared_ptr<nano::block> const&)> const & = nullptr);
// clang-format on
// Distinguishes replay votes, cannot be determined if the block is not in any election
nano::vote_code vote (std::shared_ptr<nano::vote> const &, bool);
nano::vote_code vote (std::shared_ptr<nano::vote> const &);
// Is the root of this block in the roots container
bool active (nano::block const &);
bool active (nano::qualified_root const &);
Expand Down
Loading