Election encapsulation (#2961)
* Making election time factors unsigned And with C++17, no need to declare them in the source file * Making more election members private * Renaming election_behavior -> behavior * Using const ref to avoid some copies * Encapsulating with election::force_confirm This calls the now private method confirm_once and can only be used in tests. Simplifies many tests and ensures `confirm_once` isn't called where it shouldn't be. * Encapsulating last_votes in election::votes() * Encapsulation status.winner in election::winner() * Encapsulating last_blocks in election::blocks() * Removing unused active_transactions::list_blocks() * Moving election cleanup responsibility to active_transactions::cleanup_election Election now provides cleanup_info (copies blocks)
This commit is contained in:
parent
bd014357b3
commit
1e7be31727
17 changed files with 464 additions and 663 deletions
|
|
@ -55,7 +55,7 @@ TEST (active_transactions, confirm_active)
|
|||
// At least one confirmation request
|
||||
ASSERT_GT (election->confirmation_request_count, 0u);
|
||||
// Blocks were cleared (except for not_an_account)
|
||||
ASSERT_EQ (1, election->blocks.size ());
|
||||
ASSERT_EQ (1, election->blocks ().size ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -122,14 +122,13 @@ TEST (active_transactions, keep_local)
|
|||
// should not drop wallet created transactions
|
||||
ASSERT_TIMELY (5s, node.active.size () == 6);
|
||||
ASSERT_EQ (0, node.active.recently_dropped.size ());
|
||||
while (!node.active.empty ())
|
||||
for (auto const & block : { send1, send2, send3, send4, send5, send6 })
|
||||
{
|
||||
nano::lock_guard<std::mutex> active_guard (node.active.mutex);
|
||||
if (!node.active.roots.empty ())
|
||||
{
|
||||
node.active.roots.begin ()->election->confirm_once ();
|
||||
}
|
||||
auto election = node.active.election (block->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
}
|
||||
ASSERT_TIMELY (5s, node.active.empty ());
|
||||
nano::state_block_builder builder;
|
||||
auto open1 = builder.make_block ()
|
||||
.account (key1.pub)
|
||||
|
|
@ -260,38 +259,28 @@ TEST (active_transactions, inactive_votes_cache_existing_vote)
|
|||
node.block_processor.add (open);
|
||||
node.block_processor.flush ();
|
||||
ASSERT_TIMELY (5s, node.active.size () == 1);
|
||||
std::shared_ptr<nano::election> election;
|
||||
{
|
||||
nano::lock_guard<std::mutex> active_guard (node.active.mutex);
|
||||
auto it (node.active.roots.begin ());
|
||||
ASSERT_NE (node.active.roots.end (), it);
|
||||
election = it->election;
|
||||
}
|
||||
auto election (node.active.election (send->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election);
|
||||
ASSERT_GT (node.weight (key.pub), node.minimum_principal_weight ());
|
||||
// Insert vote
|
||||
auto vote1 (std::make_shared<nano::vote> (key.pub, key.prv, 1, std::vector<nano::block_hash> (1, send->hash ())));
|
||||
node.vote_processor.vote (vote1, std::make_shared<nano::transport::channel_udp> (node.network.udp_channels, node.network.endpoint (), node.network_params.protocol.protocol_version));
|
||||
system.deadline_set (5s);
|
||||
bool done (false);
|
||||
while (!done)
|
||||
{
|
||||
nano::unique_lock<std::mutex> active_lock (node.active.mutex);
|
||||
done = (election->last_votes.size () == 2);
|
||||
active_lock.unlock ();
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
ASSERT_TIMELY (5s, election->votes ().size () == 2)
|
||||
ASSERT_EQ (1, node.stats.count (nano::stat::type::election, nano::stat::detail::vote_new));
|
||||
nano::lock_guard<std::mutex> active_guard (node.active.mutex);
|
||||
auto last_vote1 (election->last_votes[key.pub]);
|
||||
auto last_vote1 (election->votes ()[key.pub]);
|
||||
ASSERT_EQ (send->hash (), last_vote1.hash);
|
||||
ASSERT_EQ (1, last_vote1.sequence);
|
||||
// Attempt to change vote with inactive_votes_cache
|
||||
node.active.add_inactive_votes_cache (send->hash (), key.pub);
|
||||
ASSERT_EQ (1, node.active.find_inactive_votes_cache (send->hash ()).voters.size ());
|
||||
election->insert_inactive_votes_cache (send->hash ());
|
||||
{
|
||||
nano::lock_guard<std::mutex> active_guard (node.active.mutex);
|
||||
node.active.add_inactive_votes_cache (send->hash (), key.pub);
|
||||
ASSERT_EQ (1, node.active.find_inactive_votes_cache (send->hash ()).voters.size ());
|
||||
election->insert_inactive_votes_cache (send->hash ());
|
||||
}
|
||||
// Check that election data is not changed
|
||||
ASSERT_EQ (2, election->last_votes.size ());
|
||||
auto last_vote2 (election->last_votes[key.pub]);
|
||||
ASSERT_EQ (2, election->votes ().size ());
|
||||
auto last_vote2 (election->votes ()[key.pub]);
|
||||
ASSERT_EQ (last_vote1.hash, last_vote2.hash);
|
||||
ASSERT_EQ (last_vote1.sequence, last_vote2.sequence);
|
||||
ASSERT_EQ (last_vote1.time, last_vote2.time);
|
||||
|
|
@ -354,12 +343,8 @@ TEST (active_transactions, inactive_votes_cache_multiple_votes)
|
|||
ASSERT_EQ (1, node.active.inactive_votes_cache_size ());
|
||||
// Start election
|
||||
node.active.insert (send1);
|
||||
{
|
||||
nano::lock_guard<std::mutex> active_guard (node.active.mutex);
|
||||
auto it (node.active.roots.begin ());
|
||||
ASSERT_NE (node.active.roots.end (), it);
|
||||
ASSERT_EQ (3, it->election->last_votes.size ()); // 2 votes and 1 default not_an_acount
|
||||
}
|
||||
auto election = node.active.insert (send1).election;
|
||||
ASSERT_EQ (3, election->votes ().size ()); // 2 votes and 1 default not_an_acount
|
||||
ASSERT_EQ (2, node.stats.count (nano::stat::type::election, nano::stat::detail::vote_cached));
|
||||
}
|
||||
|
||||
|
|
@ -725,10 +710,7 @@ TEST (active_transactions, dropped_cleanup)
|
|||
|
||||
// Now simulate dropping the election, which performs a cleanup in the background using the node worker
|
||||
ASSERT_FALSE (election->confirmed ());
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
election->cleanup ();
|
||||
}
|
||||
node.active.erase (*block);
|
||||
|
||||
// Push a worker task to ensure the cleanup is already performed
|
||||
std::atomic<bool> flag{ false };
|
||||
|
|
@ -1056,12 +1038,9 @@ TEST (active_transactions, election_difficulty_update_fork)
|
|||
for (auto block : { open1, send2 })
|
||||
{
|
||||
node.block_confirm (block);
|
||||
{
|
||||
auto election = node.active.election (block->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node.active.election (block->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (2s, node.block_confirmed (block->hash ()));
|
||||
node.active.erase (*block);
|
||||
}
|
||||
|
|
@ -1324,25 +1303,19 @@ TEST (active_transactions, activate_account_chain)
|
|||
auto result = node.active.activate (nano::dev_genesis_key.pub);
|
||||
ASSERT_TRUE (result.inserted);
|
||||
ASSERT_EQ (1, node.active.size ());
|
||||
ASSERT_EQ (1, result.election->blocks.count (send->hash ()));
|
||||
ASSERT_EQ (1, result.election->blocks ().count (send->hash ()));
|
||||
auto result2 = node.active.activate (nano::dev_genesis_key.pub);
|
||||
ASSERT_FALSE (result2.inserted);
|
||||
ASSERT_EQ (result2.election, result.election);
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
result.election->confirm_once ();
|
||||
}
|
||||
result.election->force_confirm ();
|
||||
ASSERT_TIMELY (3s, node.block_confirmed (send->hash ()));
|
||||
// On cementing, the next election is started
|
||||
ASSERT_TIMELY (3s, node.active.active (send2->qualified_root ()));
|
||||
auto result3 = node.active.activate (nano::dev_genesis_key.pub);
|
||||
ASSERT_FALSE (result3.inserted);
|
||||
ASSERT_NE (nullptr, result3.election);
|
||||
ASSERT_EQ (1, result3.election->blocks.count (send2->hash ()));
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
result3.election->confirm_once ();
|
||||
}
|
||||
ASSERT_EQ (1, result3.election->blocks ().count (send2->hash ()));
|
||||
result3.election->force_confirm ();
|
||||
ASSERT_TIMELY (3s, node.block_confirmed (send2->hash ()));
|
||||
// On cementing, the next election is started
|
||||
ASSERT_TIMELY (3s, node.active.active (open->qualified_root ()));
|
||||
|
|
@ -1350,25 +1323,19 @@ TEST (active_transactions, activate_account_chain)
|
|||
auto result4 = node.active.activate (nano::dev_genesis_key.pub);
|
||||
ASSERT_FALSE (result4.inserted);
|
||||
ASSERT_NE (nullptr, result4.election);
|
||||
ASSERT_EQ (1, result4.election->blocks.count (send3->hash ()));
|
||||
ASSERT_EQ (1, result4.election->blocks ().count (send3->hash ()));
|
||||
auto result5 = node.active.activate (key.pub);
|
||||
ASSERT_FALSE (result5.inserted);
|
||||
ASSERT_NE (nullptr, result5.election);
|
||||
ASSERT_EQ (1, result5.election->blocks.count (open->hash ()));
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
result5.election->confirm_once ();
|
||||
}
|
||||
ASSERT_EQ (1, result5.election->blocks ().count (open->hash ()));
|
||||
result5.election->force_confirm ();
|
||||
ASSERT_TIMELY (3s, node.block_confirmed (open->hash ()));
|
||||
// Until send3 is also confirmed, the receive block should not activate
|
||||
std::this_thread::sleep_for (200ms);
|
||||
auto result6 = node.active.activate (key.pub);
|
||||
ASSERT_FALSE (result6.inserted);
|
||||
ASSERT_EQ (nullptr, result6.election);
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
result4.election->confirm_once ();
|
||||
}
|
||||
result4.election->force_confirm ();
|
||||
ASSERT_TIMELY (3s, node.block_confirmed (send3->hash ()));
|
||||
ASSERT_TIMELY (3s, node.active.active (receive->qualified_root ()));
|
||||
}
|
||||
|
|
@ -1416,12 +1383,9 @@ TEST (active_transactions, activate_inactive)
|
|||
ASSERT_EQ (nano::process_result::progress, node.process (*open).code);
|
||||
|
||||
node.block_confirm (send2);
|
||||
{
|
||||
auto election = node.active.election (send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node.active.election (send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (3s, !node.confirmation_height_processor.is_processing_added_block (send2->hash ()));
|
||||
ASSERT_TRUE (node.block_confirmed (send2->hash ()));
|
||||
|
|
@ -1523,13 +1487,10 @@ TEST (active_transactions, pessimistic_elections)
|
|||
ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ());
|
||||
ASSERT_EQ (node.active.expired_optimistic_election_infos_size, node.active.expired_optimistic_election_infos.size ());
|
||||
|
||||
{
|
||||
ASSERT_EQ (1, node.active.size ());
|
||||
auto election = node.active.election (send->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
ASSERT_EQ (1, node.active.size ());
|
||||
auto election = node.active.election (send->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (3s, node.block_confirmed (send->hash ()) && !node.confirmation_height_processor.is_processing_added_block (send->hash ()));
|
||||
|
||||
|
|
@ -1551,12 +1512,9 @@ TEST (active_transactions, pessimistic_elections)
|
|||
ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ());
|
||||
|
||||
// Confirm it
|
||||
{
|
||||
auto election = node.active.election (send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
election = node.active.election (send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (3s, node.block_confirmed (send2->hash ()));
|
||||
|
||||
|
|
@ -1578,12 +1536,9 @@ TEST (active_transactions, pessimistic_elections)
|
|||
ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ());
|
||||
node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count);
|
||||
|
||||
{
|
||||
auto election = node.active.election (open->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
election = node.active.election (open->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (3s, node.block_confirmed (open->hash ()));
|
||||
|
||||
|
|
|
|||
|
|
@ -879,12 +879,9 @@ TEST (bootstrap_processor, bootstrap_fork)
|
|||
ASSERT_EQ (nano::process_result::progress, node0->process (*send).code);
|
||||
// Confirm send block to vote later
|
||||
node0->block_confirm (send);
|
||||
{
|
||||
auto election = node0->active.election (send->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node0->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node0->active.election (send->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (2s, node0->block_confirmed (send->hash ()));
|
||||
node0->active.erase (*send);
|
||||
auto open_work (*system.work.generate (key.pub));
|
||||
|
|
|
|||
|
|
@ -151,12 +151,9 @@ TEST (confirmation_height, multiple_accounts)
|
|||
node->process_active (receive3);
|
||||
node->block_processor.flush ();
|
||||
node->block_confirm (receive3);
|
||||
{
|
||||
auto election = node->active.election (receive3->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node->active.election (receive3->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 10);
|
||||
|
||||
|
|
@ -435,12 +432,9 @@ TEST (confirmation_height, send_receive_between_2_accounts)
|
|||
node->process_active (receive4);
|
||||
node->block_processor.flush ();
|
||||
node->block_confirm (receive4);
|
||||
{
|
||||
auto election = node->active.election (receive4->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node->active.election (receive4->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 10);
|
||||
|
||||
|
|
@ -509,12 +503,9 @@ TEST (confirmation_height, send_receive_self)
|
|||
add_callback_stats (*node);
|
||||
|
||||
node->block_confirm (receive3);
|
||||
{
|
||||
auto election = node->active.election (receive3->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node->active.election (receive3->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 6);
|
||||
|
||||
|
|
@ -609,12 +600,9 @@ TEST (confirmation_height, all_block_types)
|
|||
|
||||
add_callback_stats (*node);
|
||||
node->block_confirm (state_send2);
|
||||
{
|
||||
auto election = node->active.election (state_send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node->active.election (state_send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 15);
|
||||
|
||||
|
|
@ -685,13 +673,9 @@ TEST (confirmation_height, conflict_rollback_cemented)
|
|||
node1->block_processor.flush ();
|
||||
node2->network.process_message (publish1, channel2);
|
||||
node2->block_processor.flush ();
|
||||
nano::unique_lock<std::mutex> lock (node2->active.mutex);
|
||||
auto conflict (node2->active.roots.find (nano::qualified_root (genesis.hash (), genesis.hash ())));
|
||||
ASSERT_NE (node2->active.roots.end (), conflict);
|
||||
auto votes1 (conflict->election);
|
||||
ASSERT_NE (nullptr, votes1);
|
||||
ASSERT_EQ (1, votes1->last_votes.size ());
|
||||
lock.unlock ();
|
||||
auto election (node2->active.election (nano::qualified_root (genesis.hash (), genesis.hash ())));
|
||||
ASSERT_NE (nullptr, election);
|
||||
ASSERT_EQ (1, election->votes ().size ());
|
||||
// Force blocks to be cemented on both nodes
|
||||
{
|
||||
auto transaction (node1->store.tx_begin_write ());
|
||||
|
|
@ -714,8 +698,8 @@ TEST (confirmation_height, conflict_rollback_cemented)
|
|||
}
|
||||
auto transaction1 (node1->store.tx_begin_read ());
|
||||
auto transaction2 (node2->store.tx_begin_read ());
|
||||
lock.lock ();
|
||||
auto winner (*votes1->tally ().begin ());
|
||||
nano::unique_lock<std::mutex> lock (node2->active.mutex);
|
||||
auto winner (*election->tally ().begin ());
|
||||
ASSERT_EQ (*publish1.block, *winner.second);
|
||||
ASSERT_EQ (nano::genesis_amount - 100, winner.first);
|
||||
ASSERT_TRUE (node1->store.block_exists (transaction1, publish1.block->hash ()));
|
||||
|
|
@ -1025,12 +1009,9 @@ TEST (confirmation_height, callback_confirmed_history)
|
|||
auto write_guard = node->write_database_queue.wait (nano::writer::testing);
|
||||
|
||||
// Confirm send1
|
||||
{
|
||||
auto election = node->active.election (send1->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node->active.election (send1->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (10s, node->active.size () == 0);
|
||||
ASSERT_EQ (0, node->active.list_recently_cemented ().size ());
|
||||
{
|
||||
|
|
@ -1104,12 +1085,9 @@ TEST (confirmation_height, dependent_election)
|
|||
node->block_confirm (send1);
|
||||
// Start an election and confirm it
|
||||
node->block_confirm (send2);
|
||||
{
|
||||
auto election = node->active.election (send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node->active.election (send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 3);
|
||||
|
||||
|
|
@ -1186,12 +1164,9 @@ TEST (confirmation_height, cemented_gap_below_receive)
|
|||
add_callback_stats (*node, &observer_order, &mutex);
|
||||
|
||||
node->block_confirm (open1);
|
||||
{
|
||||
auto election = node->active.election (open1->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node->active.election (open1->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 10);
|
||||
|
||||
auto transaction = node->store.tx_begin_read ();
|
||||
|
|
@ -1279,12 +1254,9 @@ TEST (confirmation_height, cemented_gap_below_no_cache)
|
|||
add_callback_stats (*node);
|
||||
|
||||
node->block_confirm (open1);
|
||||
{
|
||||
auto election = node->active.election (open1->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node->active.election (open1->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 6);
|
||||
|
||||
auto transaction = node->store.tx_begin_read ();
|
||||
|
|
@ -1329,23 +1301,17 @@ TEST (confirmation_height, election_winner_details_clearing)
|
|||
add_callback_stats (*node);
|
||||
|
||||
node->block_confirm (send1);
|
||||
{
|
||||
auto election = node->active.election (send1->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node->active.election (send1->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 2);
|
||||
|
||||
ASSERT_EQ (0, node->active.election_winner_details_size ());
|
||||
node->block_confirm (send);
|
||||
{
|
||||
auto election = node->active.election (send->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
election = node->active.election (send->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
// Wait until this block is confirmed
|
||||
ASSERT_TIMELY (10s, node->active.election_winner_details_size () == 1 || node->confirmation_height_processor.current ().is_zero ());
|
||||
|
|
@ -1353,12 +1319,9 @@ TEST (confirmation_height, election_winner_details_clearing)
|
|||
ASSERT_EQ (1, node->stats.count (nano::stat::type::confirmation_observer, nano::stat::detail::inactive_conf_height, nano::stat::dir::out));
|
||||
|
||||
node->block_confirm (send2);
|
||||
{
|
||||
auto election = node->active.election (send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
election = node->active.election (send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 3);
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ TEST (confirmation_solicitor, batches)
|
|||
ASSERT_EQ (1, node2.stats.count (nano::stat::type::message, nano::stat::detail::confirm_req, nano::stat::dir::out));
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
TEST (confirmation_solicitor, different_hash)
|
||||
{
|
||||
nano::system system;
|
||||
|
|
@ -73,15 +75,12 @@ TEST (confirmation_solicitor, different_hash)
|
|||
ASSERT_TIMELY (3s, node2.network.size () == 1);
|
||||
auto send (std::make_shared<nano::send_block> (nano::genesis_hash, nano::keypair ().pub, nano::genesis_amount - 100, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (nano::genesis_hash)));
|
||||
send->sideband_set ({});
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node2.active.mutex);
|
||||
auto election (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal));
|
||||
// Add a vote for something else, not the winner
|
||||
election->last_votes[representative.account] = { std::chrono::steady_clock::now (), 1, 1 };
|
||||
// Ensure the request and broadcast goes through
|
||||
ASSERT_FALSE (solicitor.add (*election));
|
||||
ASSERT_FALSE (solicitor.broadcast (*election));
|
||||
}
|
||||
auto election (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal));
|
||||
// Add a vote for something else, not the winner
|
||||
election->last_votes[representative.account] = { std::chrono::steady_clock::now (), 1, 1 };
|
||||
// Ensure the request and broadcast goes through
|
||||
ASSERT_FALSE (solicitor.add (*election));
|
||||
ASSERT_FALSE (solicitor.broadcast (*election));
|
||||
// One publish through directed broadcasting and another through random flooding
|
||||
ASSERT_EQ (2, node2.stats.count (nano::stat::type::message, nano::stat::detail::publish, nano::stat::dir::out));
|
||||
solicitor.flush ();
|
||||
|
|
@ -112,32 +111,26 @@ TEST (confirmation_solicitor, bypass_max_requests_cap)
|
|||
ASSERT_TIMELY (3s, node2.network.size () == 1);
|
||||
auto send (std::make_shared<nano::send_block> (nano::genesis_hash, nano::keypair ().pub, nano::genesis_amount - 100, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (nano::genesis_hash)));
|
||||
send->sideband_set ({});
|
||||
auto election (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal));
|
||||
// Add a vote for something else, not the winner
|
||||
for (auto const & rep : representatives)
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node2.active.mutex);
|
||||
auto election (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal));
|
||||
// Add a vote for something else, not the winner
|
||||
for (auto const & rep : representatives)
|
||||
{
|
||||
election->last_votes[rep.account] = { std::chrono::steady_clock::now (), 1, 1 };
|
||||
}
|
||||
ASSERT_FALSE (solicitor.add (*election));
|
||||
ASSERT_FALSE (solicitor.broadcast (*election));
|
||||
nano::lock_guard<std::mutex> guard (node1.active.mutex);
|
||||
election->last_votes[rep.account] = { std::chrono::steady_clock::now (), 1, 1 };
|
||||
}
|
||||
ASSERT_FALSE (solicitor.add (*election));
|
||||
ASSERT_FALSE (solicitor.broadcast (*election));
|
||||
solicitor.flush ();
|
||||
// All requests went through, the last one would normally not go through due to the cap but a vote for a different hash does not count towards the cap
|
||||
ASSERT_EQ (max_representatives + 1, node2.stats.count (nano::stat::type::message, nano::stat::detail::confirm_req, nano::stat::dir::out));
|
||||
|
||||
solicitor.prepare (representatives);
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node2.active.mutex);
|
||||
auto election (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal));
|
||||
// Erase all votes
|
||||
election->last_votes.clear ();
|
||||
ASSERT_FALSE (solicitor.add (*election));
|
||||
ASSERT_FALSE (solicitor.broadcast (*election));
|
||||
}
|
||||
auto election2 (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal));
|
||||
ASSERT_FALSE (solicitor.add (*election2));
|
||||
ASSERT_FALSE (solicitor.broadcast (*election2));
|
||||
|
||||
solicitor.flush ();
|
||||
// All requests but one went through, due to the cap
|
||||
ASSERT_EQ (2 * max_representatives + 1, node2.stats.count (nano::stat::type::message, nano::stat::detail::confirm_req, nano::stat::dir::out));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,8 @@ TEST (conflicts, start_stop)
|
|||
ASSERT_EQ (0, node1.active.size ());
|
||||
auto election1 = node1.active.insert (send1);
|
||||
ASSERT_EQ (1, node1.active.size ());
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node1.active.mutex);
|
||||
ASSERT_NE (nullptr, election1.election);
|
||||
ASSERT_EQ (1, election1.election->last_votes.size ());
|
||||
}
|
||||
ASSERT_NE (nullptr, election1.election);
|
||||
ASSERT_EQ (1, election1.election->votes ().size ());
|
||||
}
|
||||
|
||||
TEST (conflicts, add_existing)
|
||||
|
|
@ -44,13 +41,10 @@ TEST (conflicts, add_existing)
|
|||
ASSERT_EQ (1, node1.active.size ());
|
||||
auto vote1 (std::make_shared<nano::vote> (key2.pub, key2.prv, 0, send2));
|
||||
node1.active.vote (vote1);
|
||||
ASSERT_EQ (1, node1.active.size ());
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node1.active.mutex);
|
||||
ASSERT_NE (nullptr, election1.election);
|
||||
ASSERT_EQ (2, election1.election->last_votes.size ());
|
||||
ASSERT_NE (election1.election->last_votes.end (), election1.election->last_votes.find (key2.pub));
|
||||
}
|
||||
ASSERT_NE (nullptr, election1.election);
|
||||
ASSERT_EQ (2, election1.election->votes ().size ());
|
||||
auto votes (election1.election->votes ());
|
||||
ASSERT_NE (votes.end (), votes.find (key2.pub));
|
||||
}
|
||||
|
||||
TEST (conflicts, add_two)
|
||||
|
|
|
|||
|
|
@ -73,12 +73,9 @@ TEST (gap_cache, gap_bootstrap)
|
|||
ASSERT_EQ (nano::genesis_amount, node2.balance (nano::genesis_account));
|
||||
// Confirm send block, allowing voting on the upcoming block
|
||||
node1.block_confirm (send);
|
||||
{
|
||||
auto election = node1.active.election (send->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node1.active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node1.active.election (send->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (2s, node1.block_confirmed (send->hash ()));
|
||||
node1.active.erase (*send);
|
||||
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
|
||||
|
|
|
|||
|
|
@ -767,10 +767,7 @@ TEST (votes, check_signature)
|
|||
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code);
|
||||
}
|
||||
auto election1 = node1.active.insert (send1);
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (node1.active.mutex);
|
||||
ASSERT_EQ (1, election1.election->last_votes.size ());
|
||||
}
|
||||
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));
|
||||
vote1->signature.bytes[0] ^= 1;
|
||||
ASSERT_EQ (nano::vote_code::invalid, node1.vote_processor.vote_blocking (vote1, std::make_shared<nano::transport::channel_udp> (node1.network.udp_channels, nano::endpoint (boost::asio::ip::address_v6 (), 0), node1.network_params.protocol.protocol_version)));
|
||||
|
|
@ -790,18 +787,17 @@ TEST (votes, add_one)
|
|||
auto transaction (node1.store.tx_begin_write ());
|
||||
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code);
|
||||
auto election1 = node1.active.insert (send1);
|
||||
nano::unique_lock<std::mutex> lock (node1.active.mutex);
|
||||
ASSERT_EQ (1, election1.election->last_votes.size ());
|
||||
lock.unlock ();
|
||||
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));
|
||||
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));
|
||||
lock.lock ();
|
||||
ASSERT_EQ (2, election1.election->last_votes.size ());
|
||||
auto existing1 (election1.election->last_votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (election1.election->last_votes.end (), existing1);
|
||||
ASSERT_EQ (2, election1.election->votes ().size ());
|
||||
auto votes1 (election1.election->votes ());
|
||||
auto existing1 (votes1.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (votes1.end (), existing1);
|
||||
ASSERT_EQ (send1->hash (), existing1->second.hash);
|
||||
nano::lock_guard<std::mutex> guard (node1.active.mutex);
|
||||
auto winner (*election1.election->tally ().begin ());
|
||||
ASSERT_EQ (*send1, *winner.second);
|
||||
ASSERT_EQ (nano::genesis_amount - 100, winner.first);
|
||||
|
|
@ -818,24 +814,23 @@ TEST (votes, add_two)
|
|||
auto transaction (node1.store.tx_begin_write ());
|
||||
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code);
|
||||
auto election1 = node1.active.insert (send1);
|
||||
nano::unique_lock<std::mutex> lock (node1.active.mutex);
|
||||
lock.unlock ();
|
||||
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));
|
||||
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));
|
||||
lock.lock ();
|
||||
ASSERT_EQ (3, election1.election->last_votes.size ());
|
||||
ASSERT_NE (election1.election->last_votes.end (), election1.election->last_votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_EQ (send1->hash (), election1.election->last_votes[nano::dev_genesis_key.pub].hash);
|
||||
ASSERT_NE (election1.election->last_votes.end (), election1.election->last_votes.find (key2.pub));
|
||||
ASSERT_EQ (send2->hash (), election1.election->last_votes[key2.pub].hash);
|
||||
auto winner (*election1.election->tally ().begin ());
|
||||
ASSERT_EQ (*send1, *winner.second);
|
||||
ASSERT_EQ (3, election1.election->votes ().size ());
|
||||
auto votes1 (election1.election->votes ());
|
||||
ASSERT_NE (votes1.end (), votes1.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_EQ (send1->hash (), votes1[nano::dev_genesis_key.pub].hash);
|
||||
ASSERT_NE (votes1.end (), votes1.find (key2.pub));
|
||||
ASSERT_EQ (send2->hash (), votes1[key2.pub].hash);
|
||||
ASSERT_EQ (*send1, *election1.election->winner ());
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
// Higher sequence numbers change the vote
|
||||
TEST (votes, add_existing)
|
||||
{
|
||||
|
|
@ -857,33 +852,30 @@ TEST (votes, add_existing)
|
|||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
|
||||
// Block is already processed from vote
|
||||
ASSERT_TRUE (node1.active.publish (send1));
|
||||
nano::unique_lock<std::mutex> lock (node1.active.mutex);
|
||||
ASSERT_EQ (1, election1.election->last_votes[nano::dev_genesis_key.pub].sequence);
|
||||
ASSERT_EQ (1, election1.election->votes ()[nano::dev_genesis_key.pub].sequence);
|
||||
nano::keypair key2;
|
||||
auto send2 (std::make_shared<nano::send_block> (genesis.hash (), key2.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, 0));
|
||||
node1.work_generate_blocking (*send2);
|
||||
auto vote2 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 2, send2));
|
||||
// Pretend we've waited the timeout
|
||||
nano::unique_lock<std::mutex> lock (node1.active.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));
|
||||
ASSERT_FALSE (node1.active.publish (send2));
|
||||
lock.lock ();
|
||||
ASSERT_EQ (2, election1.election->last_votes[nano::dev_genesis_key.pub].sequence);
|
||||
ASSERT_EQ (2, election1.election->votes ()[nano::dev_genesis_key.pub].sequence);
|
||||
// Also resend the old vote, and see if we respect the sequence number
|
||||
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));
|
||||
ASSERT_EQ (2, election1.election->votes ()[nano::dev_genesis_key.pub].sequence);
|
||||
auto votes (election1.election->votes ());
|
||||
ASSERT_EQ (2, votes.size ());
|
||||
ASSERT_NE (votes.end (), votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_EQ (send2->hash (), votes[nano::dev_genesis_key.pub].hash);
|
||||
lock.lock ();
|
||||
ASSERT_EQ (2, election1.election->last_votes[nano::dev_genesis_key.pub].sequence);
|
||||
ASSERT_EQ (2, election1.election->last_votes.size ());
|
||||
ASSERT_NE (election1.election->last_votes.end (), election1.election->last_votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_EQ (send2->hash (), election1.election->last_votes[nano::dev_genesis_key.pub].hash);
|
||||
{
|
||||
auto transaction (node1.store.tx_begin_read ());
|
||||
auto winner (*election1.election->tally ().begin ());
|
||||
ASSERT_EQ (*send2, *winner.second);
|
||||
}
|
||||
ASSERT_EQ (*send2, *election1.election->tally ().begin ()->second);
|
||||
}
|
||||
|
||||
// Lower sequence numbers are ignored
|
||||
|
|
@ -910,12 +902,12 @@ TEST (votes, add_old)
|
|||
election1.election->last_votes[nano::dev_genesis_key.pub].time = std::chrono::steady_clock::now () - std::chrono::seconds (20);
|
||||
}
|
||||
node1.vote_processor.vote_blocking (vote2, channel);
|
||||
ASSERT_EQ (2, election1.election->last_votes_size ());
|
||||
nano::lock_guard<std::mutex> lock (node1.active.mutex);
|
||||
ASSERT_NE (election1.election->last_votes.end (), election1.election->last_votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_EQ (send1->hash (), election1.election->last_votes[nano::dev_genesis_key.pub].hash);
|
||||
auto winner (*election1.election->tally ().begin ());
|
||||
ASSERT_EQ (*send1, *winner.second);
|
||||
ASSERT_EQ (2, election1.election->votes ().size ());
|
||||
auto votes (election1.election->votes ());
|
||||
ASSERT_NE (votes.end (), votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_EQ (send1->hash (), votes[nano::dev_genesis_key.pub].hash);
|
||||
ASSERT_EQ (*send1, *election1.election->winner ());
|
||||
}
|
||||
}
|
||||
|
||||
// Lower sequence numbers are accepted for different accounts
|
||||
|
|
@ -936,28 +928,27 @@ TEST (votes, add_old_different_account)
|
|||
ASSERT_NE (nullptr, election1);
|
||||
auto election2 = node1.active.election (send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election2);
|
||||
ASSERT_EQ (1, election1->last_votes_size ());
|
||||
ASSERT_EQ (1, election2->last_votes_size ());
|
||||
ASSERT_EQ (1, election1->votes ().size ());
|
||||
ASSERT_EQ (1, election2->votes ().size ());
|
||||
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 2, send1));
|
||||
auto channel (std::make_shared<nano::transport::channel_udp> (node1.network.udp_channels, node1.network.endpoint (), node1.network_params.protocol.protocol_version));
|
||||
auto vote_result1 (node1.vote_processor.vote_blocking (vote1, channel));
|
||||
ASSERT_EQ (nano::vote_code::vote, vote_result1);
|
||||
ASSERT_EQ (2, election1->last_votes_size ());
|
||||
ASSERT_EQ (1, election2->last_votes_size ());
|
||||
ASSERT_EQ (2, election1->votes ().size ());
|
||||
ASSERT_EQ (1, election2->votes ().size ());
|
||||
auto vote2 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send2));
|
||||
auto vote_result2 (node1.vote_processor.vote_blocking (vote2, channel));
|
||||
ASSERT_EQ (nano::vote_code::vote, vote_result2);
|
||||
ASSERT_EQ (2, election1->last_votes_size ());
|
||||
ASSERT_EQ (2, election2->last_votes_size ());
|
||||
nano::unique_lock<std::mutex> lock (node1.active.mutex);
|
||||
ASSERT_NE (election1->last_votes.end (), election1->last_votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (election2->last_votes.end (), election2->last_votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_EQ (send1->hash (), election1->last_votes[nano::dev_genesis_key.pub].hash);
|
||||
ASSERT_EQ (send2->hash (), election2->last_votes[nano::dev_genesis_key.pub].hash);
|
||||
auto winner1 (*election1->tally ().begin ());
|
||||
ASSERT_EQ (*send1, *winner1.second);
|
||||
auto winner2 (*election2->tally ().begin ());
|
||||
ASSERT_EQ (*send2, *winner2.second);
|
||||
ASSERT_EQ (2, election1->votes ().size ());
|
||||
ASSERT_EQ (2, election2->votes ().size ());
|
||||
auto votes1 (election1->votes ());
|
||||
auto votes2 (election2->votes ());
|
||||
ASSERT_NE (votes1.end (), votes1.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (votes2.end (), votes2.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_EQ (send1->hash (), votes1[nano::dev_genesis_key.pub].hash);
|
||||
ASSERT_EQ (send2->hash (), votes2[nano::dev_genesis_key.pub].hash);
|
||||
ASSERT_EQ (*send1, *election1->winner ());
|
||||
ASSERT_EQ (*send2, *election2->winner ());
|
||||
}
|
||||
|
||||
// The voting cooldown is respected
|
||||
|
|
@ -980,12 +971,11 @@ TEST (votes, add_cooldown)
|
|||
node1.work_generate_blocking (*send2);
|
||||
auto vote2 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 2, send2));
|
||||
node1.vote_processor.vote_blocking (vote2, channel);
|
||||
nano::unique_lock<std::mutex> lock (node1.active.mutex);
|
||||
ASSERT_EQ (2, election1.election->last_votes.size ());
|
||||
ASSERT_NE (election1.election->last_votes.end (), election1.election->last_votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_EQ (send1->hash (), election1.election->last_votes[nano::dev_genesis_key.pub].hash);
|
||||
auto winner (*election1.election->tally ().begin ());
|
||||
ASSERT_EQ (*send1, *winner.second);
|
||||
ASSERT_EQ (2, election1.election->votes ().size ());
|
||||
auto votes (election1.election->votes ());
|
||||
ASSERT_NE (votes.end (), votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_EQ (send1->hash (), votes[nano::dev_genesis_key.pub].hash);
|
||||
ASSERT_EQ (*send1, *election1.election->winner ());
|
||||
}
|
||||
|
||||
// Query for block successor
|
||||
|
|
@ -2718,15 +2708,14 @@ TEST (ledger, block_hash_account_conflict)
|
|||
ASSERT_NE (nullptr, election3);
|
||||
auto election4 = node1.active.election (open_epoch1->qualified_root ());
|
||||
ASSERT_NE (nullptr, election4);
|
||||
nano::lock_guard<std::mutex> lock (node1.active.mutex);
|
||||
auto winner1 (*election1->tally ().begin ());
|
||||
auto winner2 (*election2->tally ().begin ());
|
||||
auto winner3 (*election3->tally ().begin ());
|
||||
auto winner4 (*election4->tally ().begin ());
|
||||
ASSERT_EQ (*send1, *winner1.second);
|
||||
ASSERT_EQ (*receive1, *winner2.second);
|
||||
ASSERT_EQ (*send2, *winner3.second);
|
||||
ASSERT_EQ (*open_epoch1, *winner4.second);
|
||||
auto winner1 (election1->winner ());
|
||||
auto winner2 (election2->winner ());
|
||||
auto winner3 (election3->winner ());
|
||||
auto winner4 (election4->winner ());
|
||||
ASSERT_EQ (*send1, *winner1);
|
||||
ASSERT_EQ (*receive1, *winner2);
|
||||
ASSERT_EQ (*send2, *winner3);
|
||||
ASSERT_EQ (*open_epoch1, *winner4);
|
||||
}
|
||||
|
||||
TEST (ledger, could_fit)
|
||||
|
|
|
|||
|
|
@ -256,13 +256,10 @@ TEST (node, node_receive_quorum)
|
|||
.build_shared ();
|
||||
node1.process_active (send);
|
||||
ASSERT_TIMELY (10s, node1.ledger.block_exists (send->hash ()));
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node1.active.mutex);
|
||||
auto info (node1.active.roots.find (nano::qualified_root (previous, previous)));
|
||||
ASSERT_NE (node1.active.roots.end (), info);
|
||||
ASSERT_FALSE (info->election->confirmed ());
|
||||
ASSERT_EQ (1, info->election->last_votes.size ());
|
||||
}
|
||||
auto election (node1.active.election (nano::qualified_root (previous, previous)));
|
||||
ASSERT_NE (nullptr, election);
|
||||
ASSERT_FALSE (election->confirmed ());
|
||||
ASSERT_EQ (1, election->votes ().size ());
|
||||
nano::system system2;
|
||||
system2.add_node (node_flags);
|
||||
|
||||
|
|
@ -1023,25 +1020,17 @@ TEST (node, fork_publish)
|
|||
node1.process_active (send1);
|
||||
node1.block_processor.flush ();
|
||||
ASSERT_EQ (1, node1.active.size ());
|
||||
nano::unique_lock<std::mutex> lock (node1.active.mutex);
|
||||
auto existing (node1.active.roots.find (send1->qualified_root ()));
|
||||
ASSERT_NE (node1.active.roots.end (), existing);
|
||||
auto election (existing->election);
|
||||
lock.unlock ();
|
||||
system.deadline_set (1s);
|
||||
auto election (node1.active.election (send1->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election);
|
||||
// Wait until the genesis rep activated & makes vote
|
||||
while (election->last_votes_size () != 2)
|
||||
{
|
||||
node1.vote_processor.flush ();
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
ASSERT_TIMELY (1s, election->votes ().size () == 2);
|
||||
node1.process_active (send2);
|
||||
node1.block_processor.flush ();
|
||||
lock.lock ();
|
||||
auto existing1 (election->last_votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (election->last_votes.end (), existing1);
|
||||
auto votes1 (election->votes ());
|
||||
auto existing1 (votes1.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (votes1.end (), existing1);
|
||||
ASSERT_EQ (send1->hash (), existing1->second.hash);
|
||||
auto transaction (node1.store.tx_begin_read ());
|
||||
nano::lock_guard<std::mutex> guard (node1.active.mutex);
|
||||
auto winner (*election->tally ().begin ());
|
||||
ASSERT_EQ (*send1, *winner.second);
|
||||
ASSERT_EQ (nano::genesis_amount - 100, winner.first);
|
||||
|
|
@ -1076,14 +1065,11 @@ TEST (node, fork_publish_inactive)
|
|||
ASSERT_EQ (nano::process_result::fork, node.process_local (send2).code);
|
||||
auto election (node.active.election (send1->qualified_root ()));
|
||||
ASSERT_NE (election, nullptr);
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
auto & blocks (election->blocks);
|
||||
ASSERT_NE (blocks.end (), blocks.find (send1->hash ()));
|
||||
ASSERT_NE (blocks.end (), blocks.find (send2->hash ()));
|
||||
ASSERT_NE (election->status.winner, send1);
|
||||
ASSERT_NE (election->status.winner, send2);
|
||||
}
|
||||
auto blocks (election->blocks ());
|
||||
ASSERT_NE (blocks.end (), blocks.find (send1->hash ()));
|
||||
ASSERT_NE (blocks.end (), blocks.find (send2->hash ()));
|
||||
ASSERT_NE (election->winner (), send1);
|
||||
ASSERT_NE (election->winner (), send2);
|
||||
}
|
||||
|
||||
TEST (node, fork_keep)
|
||||
|
|
@ -1122,26 +1108,18 @@ TEST (node, fork_keep)
|
|||
node1.block_processor.flush ();
|
||||
node2.process_active (send2);
|
||||
node2.block_processor.flush ();
|
||||
nano::unique_lock<std::mutex> lock (node2.active.mutex);
|
||||
auto conflict (node2.active.roots.find (nano::qualified_root (genesis.hash (), genesis.hash ())));
|
||||
ASSERT_NE (node2.active.roots.end (), conflict);
|
||||
auto votes1 (conflict->election);
|
||||
ASSERT_NE (nullptr, votes1);
|
||||
ASSERT_EQ (1, votes1->last_votes.size ());
|
||||
lock.unlock ();
|
||||
{
|
||||
auto transaction0 (node1.store.tx_begin_read ());
|
||||
auto transaction1 (node2.store.tx_begin_read ());
|
||||
ASSERT_TRUE (node1.store.block_exists (transaction0, send1->hash ()));
|
||||
ASSERT_TRUE (node2.store.block_exists (transaction1, send1->hash ()));
|
||||
}
|
||||
auto election1 (node2.active.election (nano::qualified_root (genesis.hash (), genesis.hash ())));
|
||||
ASSERT_NE (nullptr, election1);
|
||||
ASSERT_EQ (1, election1->votes ().size ());
|
||||
ASSERT_TRUE (node1.ledger.block_exists (send1->hash ()));
|
||||
ASSERT_TRUE (node2.ledger.block_exists (send1->hash ()));
|
||||
// Wait until the genesis rep makes a vote
|
||||
ASSERT_TIMELY (1.5min, votes1->last_votes_size () != 1);
|
||||
ASSERT_TIMELY (1.5min, election1->votes ().size () != 1);
|
||||
auto transaction0 (node1.store.tx_begin_read ());
|
||||
auto transaction1 (node2.store.tx_begin_read ());
|
||||
// The vote should be in agreement with what we already have.
|
||||
lock.lock ();
|
||||
auto winner (*votes1->tally ().begin ());
|
||||
nano::lock_guard<std::mutex> guard (node2.active.mutex);
|
||||
auto winner (*election1->tally ().begin ());
|
||||
ASSERT_EQ (*send1, *winner.second);
|
||||
ASSERT_EQ (nano::genesis_amount - 100, winner.first);
|
||||
ASSERT_TRUE (node1.store.block_exists (transaction0, send1->hash ()));
|
||||
|
|
@ -1187,37 +1165,19 @@ TEST (node, fork_flip)
|
|||
node1.block_processor.flush ();
|
||||
node2.network.process_message (publish1, channel2);
|
||||
node2.block_processor.flush ();
|
||||
auto election1 (node2.active.election (nano::qualified_root (genesis.hash (), genesis.hash ())));
|
||||
ASSERT_NE (nullptr, election1);
|
||||
ASSERT_EQ (1, election1->votes ().size ());
|
||||
ASSERT_NE (nullptr, node1.block (publish1.block->hash ()));
|
||||
ASSERT_NE (nullptr, node2.block (publish2.block->hash ()));
|
||||
ASSERT_TIMELY (10s, node2.ledger.block_exists (publish1.block->hash ()));
|
||||
nano::unique_lock<std::mutex> lock (node2.active.mutex);
|
||||
auto conflict (node2.active.roots.find (nano::qualified_root (genesis.hash (), genesis.hash ())));
|
||||
ASSERT_NE (node2.active.roots.end (), conflict);
|
||||
auto votes1 (conflict->election);
|
||||
ASSERT_NE (nullptr, votes1);
|
||||
ASSERT_EQ (1, votes1->last_votes.size ());
|
||||
lock.unlock ();
|
||||
{
|
||||
auto transaction (node1.store.tx_begin_read ());
|
||||
ASSERT_TRUE (node1.store.block_exists (transaction, publish1.block->hash ()));
|
||||
}
|
||||
{
|
||||
auto transaction (node2.store.tx_begin_read ());
|
||||
ASSERT_TRUE (node2.store.block_exists (transaction, publish2.block->hash ()));
|
||||
}
|
||||
system.deadline_set (10s);
|
||||
auto done (false);
|
||||
while (!done)
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
done = node2.ledger.block_exists (publish1.block->hash ());
|
||||
}
|
||||
auto transaction1 (node1.store.tx_begin_read ());
|
||||
auto transaction2 (node2.store.tx_begin_read ());
|
||||
lock.lock ();
|
||||
auto winner (*votes1->tally ().begin ());
|
||||
auto winner (*election1->tally ().begin ());
|
||||
ASSERT_EQ (*publish1.block, *winner.second);
|
||||
ASSERT_EQ (nano::genesis_amount - 100, winner.first);
|
||||
ASSERT_TRUE (node1.store.block_exists (transaction1, publish1.block->hash ()));
|
||||
ASSERT_TRUE (node2.store.block_exists (transaction2, publish1.block->hash ()));
|
||||
ASSERT_FALSE (node2.store.block_exists (transaction2, publish2.block->hash ()));
|
||||
ASSERT_TRUE (node1.ledger.block_exists (publish1.block->hash ()));
|
||||
ASSERT_TRUE (node2.ledger.block_exists (publish1.block->hash ()));
|
||||
ASSERT_FALSE (node2.ledger.block_exists (publish2.block->hash ()));
|
||||
}
|
||||
|
||||
TEST (node, fork_multi_flip)
|
||||
|
|
@ -1280,39 +1240,21 @@ TEST (node, fork_multi_flip)
|
|||
node1.block_processor.flush ();
|
||||
node2.network.process_message (publish1, node2.network.udp_channels.create (node2.network.endpoint ()));
|
||||
node2.block_processor.flush ();
|
||||
auto election1 (node2.active.election (nano::qualified_root (genesis.hash (), genesis.hash ())));
|
||||
ASSERT_NE (nullptr, election1);
|
||||
ASSERT_EQ (1, election1->votes ().size ());
|
||||
ASSERT_TRUE (node1.ledger.block_exists (publish1.block->hash ()));
|
||||
ASSERT_TRUE (node2.ledger.block_exists (publish2.block->hash ()));
|
||||
ASSERT_TRUE (node2.ledger.block_exists (publish3.block->hash ()));
|
||||
ASSERT_TIMELY (10s, node2.ledger.block_exists (publish1.block->hash ()));
|
||||
nano::unique_lock<std::mutex> lock (node2.active.mutex);
|
||||
auto conflict (node2.active.roots.find (nano::qualified_root (genesis.hash (), genesis.hash ())));
|
||||
ASSERT_NE (node2.active.roots.end (), conflict);
|
||||
auto votes1 (conflict->election);
|
||||
ASSERT_NE (nullptr, votes1);
|
||||
ASSERT_EQ (1, votes1->last_votes.size ());
|
||||
lock.unlock ();
|
||||
{
|
||||
auto transaction (node1.store.tx_begin_read ());
|
||||
ASSERT_TRUE (node1.store.block_exists (transaction, publish1.block->hash ()));
|
||||
}
|
||||
{
|
||||
auto transaction (node2.store.tx_begin_read ());
|
||||
ASSERT_TRUE (node2.store.block_exists (transaction, publish2.block->hash ()));
|
||||
ASSERT_TRUE (node2.store.block_exists (transaction, publish3.block->hash ()));
|
||||
}
|
||||
system.deadline_set (10s);
|
||||
auto done (false);
|
||||
while (!done)
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
done = node2.ledger.block_exists (publish1.block->hash ());
|
||||
}
|
||||
auto transaction1 (node1.store.tx_begin_read ());
|
||||
auto transaction2 (node2.store.tx_begin_read ());
|
||||
lock.lock ();
|
||||
auto winner (*votes1->tally ().begin ());
|
||||
auto winner (*election1->tally ().begin ());
|
||||
ASSERT_EQ (*publish1.block, *winner.second);
|
||||
ASSERT_EQ (nano::genesis_amount - 100, winner.first);
|
||||
ASSERT_TRUE (node1.store.block_exists (transaction1, publish1.block->hash ()));
|
||||
ASSERT_TRUE (node2.store.block_exists (transaction2, publish1.block->hash ()));
|
||||
ASSERT_FALSE (node2.store.block_exists (transaction2, publish2.block->hash ()));
|
||||
ASSERT_FALSE (node2.store.block_exists (transaction2, publish3.block->hash ()));
|
||||
ASSERT_TRUE (node1.ledger.block_exists (publish1.block->hash ()));
|
||||
ASSERT_TRUE (node2.ledger.block_exists (publish1.block->hash ()));
|
||||
ASSERT_FALSE (node2.ledger.block_exists (publish2.block->hash ()));
|
||||
ASSERT_FALSE (node2.ledger.block_exists (publish3.block->hash ()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1397,11 +1339,8 @@ TEST (node, fork_open)
|
|||
auto channel1 (node1.network.udp_channels.create (node1.network.endpoint ()));
|
||||
node1.network.process_message (publish1, channel1);
|
||||
node1.block_processor.flush ();
|
||||
{
|
||||
auto election = node1.active.election (publish1.block->qualified_root ());
|
||||
nano::lock_guard<std::mutex> guard (node1.active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node1.active.election (publish1.block->qualified_root ());
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (3s, node1.active.empty () && node1.block_confirmed (publish1.block->hash ()));
|
||||
nano::open_block_builder builder;
|
||||
auto open1 = builder.make_block ()
|
||||
|
|
@ -1426,13 +1365,10 @@ TEST (node, fork_open)
|
|||
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
|
||||
node1.network.process_message (publish3, channel1);
|
||||
node1.block_processor.flush ();
|
||||
{
|
||||
auto election = node1.active.election (publish3.block->qualified_root ());
|
||||
nano::lock_guard<std::mutex> guard (node1.active.mutex);
|
||||
ASSERT_EQ (2, election->blocks.size ());
|
||||
ASSERT_EQ (publish2.block->hash (), election->status.winner->hash ());
|
||||
ASSERT_FALSE (election->confirmed ());
|
||||
}
|
||||
election = node1.active.election (publish3.block->qualified_root ());
|
||||
ASSERT_EQ (2, election->blocks ().size ());
|
||||
ASSERT_EQ (publish2.block->hash (), election->winner ()->hash ());
|
||||
ASSERT_FALSE (election->confirmed ());
|
||||
ASSERT_TRUE (node1.block (publish2.block->hash ()));
|
||||
ASSERT_FALSE (node1.block (publish3.block->hash ()));
|
||||
}
|
||||
|
|
@ -1492,13 +1428,9 @@ TEST (node, fork_open_flip)
|
|||
node1.block_processor.flush ();
|
||||
node2.process_active (open1);
|
||||
node2.block_processor.flush ();
|
||||
nano::unique_lock<std::mutex> lock (node2.active.mutex);
|
||||
auto conflict (node2.active.roots.find (open1->qualified_root ()));
|
||||
ASSERT_NE (node2.active.roots.end (), conflict);
|
||||
auto votes1 (conflict->election);
|
||||
ASSERT_NE (nullptr, votes1);
|
||||
ASSERT_EQ (1, votes1->last_votes.size ());
|
||||
lock.unlock ();
|
||||
auto election1 (node2.active.election (open1->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election1);
|
||||
ASSERT_EQ (1, election1->votes ().size ());
|
||||
ASSERT_TRUE (node1.block (open1->hash ()) != nullptr);
|
||||
ASSERT_TRUE (node2.block (open2->hash ()) != nullptr);
|
||||
// Node2 should eventually settle on open1
|
||||
|
|
@ -1506,8 +1438,8 @@ TEST (node, fork_open_flip)
|
|||
node2.block_processor.flush ();
|
||||
auto transaction1 (node1.store.tx_begin_read ());
|
||||
auto transaction2 (node2.store.tx_begin_read ());
|
||||
lock.lock ();
|
||||
auto winner (*votes1->tally ().begin ());
|
||||
nano::lock_guard<std::mutex> guard (node1.active.mutex);
|
||||
auto winner (*election1->tally ().begin ());
|
||||
ASSERT_EQ (*open1, *winner.second);
|
||||
ASSERT_EQ (nano::genesis_amount - 1, winner.first);
|
||||
ASSERT_TRUE (node1.store.block_exists (transaction1, open1->hash ()));
|
||||
|
|
@ -1810,10 +1742,7 @@ TEST (node, broadcast_elected)
|
|||
node->block_confirm (block);
|
||||
auto election (node->active.election (block->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election);
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (5s, 4 == node->ledger.cache.cemented_count)
|
||||
}
|
||||
|
||||
|
|
@ -1880,12 +1809,9 @@ TEST (node, rep_self_vote)
|
|||
ASSERT_EQ (nano::process_result::progress, node0->process (open_big).code);
|
||||
// Confirm both blocks, allowing voting on the upcoming block
|
||||
node0->block_confirm (node0->block (open_big.hash ()));
|
||||
{
|
||||
auto election = node0->active.election (open_big.qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node0->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node0->active.election (open_big.qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
system.wallet (0)->insert_adhoc (rep_big.prv);
|
||||
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
|
||||
|
|
@ -1901,9 +1827,8 @@ TEST (node, rep_self_vote)
|
|||
auto & active (node0->active);
|
||||
auto election1 = active.insert (block0);
|
||||
// Wait until representatives are activated & make vote
|
||||
ASSERT_TIMELY (1s, election1.election->last_votes_size () == 3);
|
||||
nano::unique_lock<std::mutex> lock (active.mutex);
|
||||
auto & rep_votes (election1.election->last_votes);
|
||||
ASSERT_TIMELY (1s, election1.election->votes ().size () == 3);
|
||||
auto rep_votes (election1.election->votes ());
|
||||
ASSERT_NE (rep_votes.end (), rep_votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (rep_votes.end (), rep_votes.find (rep_big.pub));
|
||||
}
|
||||
|
|
@ -2012,12 +1937,9 @@ TEST (node, bootstrap_fork_open)
|
|||
for (auto node : system.nodes)
|
||||
{
|
||||
node->block_confirm (node->block (node->latest (nano::dev_genesis_key.pub)));
|
||||
{
|
||||
auto election = node->active.election (send0.qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node->active.election (send0.qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (2s, node->active.empty ());
|
||||
}
|
||||
ASSERT_TIMELY (3s, node0->block_confirmed (send0.hash ()));
|
||||
|
|
@ -2541,12 +2463,9 @@ TEST (node, block_confirm)
|
|||
ASSERT_TRUE (node2.ledger.block_exists (send1_copy->hash ()));
|
||||
// Confirm send1 on node2 so it can vote for send2
|
||||
node2.block_confirm (send1_copy);
|
||||
{
|
||||
auto election = node2.active.election (send1_copy->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node2.active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node2.active.election (send1_copy->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (3s, node2.block_confirmed (send1_copy->hash ()) && node2.active.empty ());
|
||||
system.wallet (1)->insert_adhoc (nano::dev_genesis_key.prv);
|
||||
auto send2 (std::make_shared<nano::state_block> (nano::dev_genesis_key.pub, send1->hash (), nano::dev_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio * 2, key.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *node1.work_generate_blocking (send1->hash ())));
|
||||
|
|
@ -2631,11 +2550,10 @@ TEST (node, confirm_quorum)
|
|||
ASSERT_EQ (nano::process_result::progress, node1.process (*send1).code);
|
||||
system.wallet (0)->send_action (nano::dev_genesis_key.pub, nano::dev_genesis_key.pub, new_balance.number ());
|
||||
ASSERT_TIMELY (10s, !node1.active.empty ());
|
||||
nano::lock_guard<std::mutex> guard (node1.active.mutex);
|
||||
auto info (node1.active.roots.find (nano::qualified_root (send1->hash (), send1->hash ())));
|
||||
ASSERT_NE (node1.active.roots.end (), info);
|
||||
ASSERT_FALSE (info->election->confirmed ());
|
||||
ASSERT_EQ (1, info->election->last_votes.size ());
|
||||
auto election (node1.active.election (nano::qualified_root (send1->hash (), send1->hash ())));
|
||||
ASSERT_NE (nullptr, election);
|
||||
ASSERT_FALSE (election->confirmed ());
|
||||
ASSERT_EQ (1, election->votes ().size ());
|
||||
ASSERT_EQ (0, node1.balance (nano::dev_genesis_key.pub));
|
||||
}
|
||||
|
||||
|
|
@ -2682,12 +2600,9 @@ TEST (node, local_votes_cache)
|
|||
}
|
||||
// Confirm blocks to allow voting
|
||||
node.block_confirm (send2);
|
||||
{
|
||||
auto election = node.active.election (send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node.active.election (send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (3s, node.ledger.cache.cemented_count == 3);
|
||||
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
|
||||
nano::confirm_req message1 (send1);
|
||||
|
|
@ -3066,12 +2981,9 @@ TEST (node, epoch_conflict_confirm)
|
|||
ASSERT_EQ (nano::process_result::progress, node1->process (*open).code);
|
||||
// Confirm block in node1 to allow generating votes
|
||||
node1->block_confirm (open);
|
||||
{
|
||||
auto election (node1->active.election (open->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node1->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election (node1->active.election (open->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (3s, node1->block_confirmed (open->hash ()));
|
||||
{
|
||||
nano::block_post_events events;
|
||||
|
|
@ -3181,31 +3093,14 @@ TEST (node, fork_election_invalid_block_signature)
|
|||
.build_shared ();
|
||||
auto channel1 (node1.network.udp_channels.create (node1.network.endpoint ()));
|
||||
node1.network.process_message (nano::publish (send1), channel1);
|
||||
system.deadline_set (5s);
|
||||
std::shared_ptr<nano::election> election;
|
||||
while (election == nullptr)
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
nano::lock_guard<std::mutex> lock (node1.active.mutex);
|
||||
auto existing = node1.active.blocks.find (send1->hash ());
|
||||
if (existing != node1.active.blocks.end ())
|
||||
{
|
||||
election = existing->second;
|
||||
}
|
||||
}
|
||||
nano::unique_lock<std::mutex> lock (node1.active.mutex);
|
||||
ASSERT_EQ (1, election->blocks.size ());
|
||||
lock.unlock ();
|
||||
ASSERT_TIMELY (5s, node1.active.active (send1->qualified_root ()));
|
||||
auto election (node1.active.election (send1->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election);
|
||||
ASSERT_EQ (1, election->blocks ().size ());
|
||||
node1.network.process_message (nano::publish (send3), channel1);
|
||||
node1.network.process_message (nano::publish (send2), channel1);
|
||||
lock.lock ();
|
||||
while (election->blocks.size () == 1)
|
||||
{
|
||||
lock.unlock ();
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
lock.lock ();
|
||||
}
|
||||
ASSERT_EQ (election->blocks[send2->hash ()]->block_signature (), send2->block_signature ());
|
||||
ASSERT_TIMELY (3s, election->blocks ().size () > 1);
|
||||
ASSERT_EQ (election->blocks ()[send2->hash ()]->block_signature (), send2->block_signature ());
|
||||
}
|
||||
|
||||
TEST (node, block_processor_signatures)
|
||||
|
|
@ -3977,33 +3872,31 @@ TEST (node, rollback_vote_self)
|
|||
ASSERT_EQ (nano::process_result::progress, node.process (*open).code);
|
||||
// Confirm blocks to allow voting
|
||||
node.block_confirm (open);
|
||||
{
|
||||
auto election = node.active.election (open->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node.active.election (open->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (5s, node.ledger.cache.cemented_count == 3);
|
||||
ASSERT_EQ (weight, node.weight (key.pub));
|
||||
node.process_active (send2);
|
||||
node.process_active (fork);
|
||||
node.block_processor.flush ();
|
||||
auto election = node.active.election (send2->qualified_root ());
|
||||
election = node.active.election (send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
ASSERT_EQ (2, election->blocks.size ());
|
||||
ASSERT_EQ (2, election->blocks ().size ());
|
||||
// Insert genesis key in the wallet
|
||||
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
|
||||
{
|
||||
// The write guard prevents the block processor from performing the rollback
|
||||
auto write_guard = node.write_database_queue.wait (nano::writer::testing);
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
ASSERT_EQ (1, election->last_votes.size ());
|
||||
ASSERT_EQ (1, election->votes ().size ());
|
||||
nano::unique_lock<std::mutex> lock (node.active.mutex);
|
||||
// Vote with key to switch the winner
|
||||
election->vote (key.pub, 0, fork->hash ());
|
||||
ASSERT_EQ (2, election->last_votes.size ());
|
||||
lock.unlock ();
|
||||
ASSERT_EQ (2, election->votes ().size ());
|
||||
// The winner changed
|
||||
ASSERT_EQ (election->status.winner, fork);
|
||||
ASSERT_EQ (election->winner (), fork);
|
||||
}
|
||||
// Even without the rollback being finished, the aggregator must reply with a vote for the new winner, not the old one
|
||||
ASSERT_TRUE (node.history.votes (send2->root (), send2->hash ()).empty ());
|
||||
|
|
@ -4017,9 +3910,10 @@ TEST (node, rollback_vote_self)
|
|||
// Going out of the scope allows the rollback to complete
|
||||
}
|
||||
// A vote is eventually generated from the local representative
|
||||
ASSERT_TIMELY (5s, 3 == election->last_votes_size ());
|
||||
auto vote (election->last_votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (election->last_votes.end (), vote);
|
||||
ASSERT_TIMELY (5s, 3 == election->votes ().size ());
|
||||
auto votes (election->votes ());
|
||||
auto vote (votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (votes.end (), vote);
|
||||
ASSERT_EQ (fork->hash (), vote->second.hash);
|
||||
}
|
||||
|
||||
|
|
@ -4488,10 +4382,7 @@ TEST (node, deferred_dependent_elections)
|
|||
ASSERT_FALSE (node.active.active (send2->qualified_root ()));
|
||||
|
||||
// Confirming send1 will automatically start elections for the dependents
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
election_send1->confirm_once ();
|
||||
}
|
||||
election_send1->force_confirm ();
|
||||
ASSERT_TIMELY (2s, node.block_confirmed (send1->hash ()));
|
||||
ASSERT_TIMELY (2s, node.active.active (open->qualified_root ()) && node.active.active (send2->qualified_root ()));
|
||||
auto election_open = node.active.election (open->qualified_root ());
|
||||
|
|
@ -4502,10 +4393,7 @@ TEST (node, deferred_dependent_elections)
|
|||
// Confirm one of the dependents of the receive but not the other, to ensure both have to be confirmed to start an election on processing
|
||||
ASSERT_EQ (nano::process_result::progress, node.process (*receive).code);
|
||||
ASSERT_FALSE (node.active.active (receive->qualified_root ()));
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
election_open->confirm_once ();
|
||||
}
|
||||
election_open->force_confirm ();
|
||||
ASSERT_TIMELY (2s, node.block_confirmed (open->hash ()));
|
||||
ASSERT_FALSE (node.ledger.dependents_confirmed (node.store.tx_begin_read (), *receive));
|
||||
std::this_thread::sleep_for (500ms);
|
||||
|
|
@ -4524,10 +4412,7 @@ TEST (node, deferred_dependent_elections)
|
|||
ASSERT_FALSE (node.active.active (receive->qualified_root ()));
|
||||
|
||||
// Confirming the other dependency allows starting an election from a fork
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
election_send2->confirm_once ();
|
||||
}
|
||||
election_send2->force_confirm ();
|
||||
ASSERT_TIMELY (2s, node.block_confirmed (send2->hash ()));
|
||||
ASSERT_TIMELY (2s, node.active.active (receive->qualified_root ()));
|
||||
node.active.erase (*receive);
|
||||
|
|
|
|||
|
|
@ -185,12 +185,9 @@ TEST (request_aggregator, split)
|
|||
}
|
||||
// Confirm all blocks
|
||||
node.block_confirm (blocks.back ());
|
||||
{
|
||||
auto election (node.active.election (blocks.back ()->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election (node.active.election (blocks.back ()->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (5s, max_vbh + 2 == node.ledger.cache.cemented_count);
|
||||
ASSERT_EQ (max_vbh + 1, request.size ());
|
||||
auto channel (node.network.udp_channels.create (node.network.endpoint ()));
|
||||
|
|
@ -364,12 +361,9 @@ TEST (request_aggregator, cannot_vote)
|
|||
|
||||
// Confirm send1
|
||||
node.block_confirm (send1);
|
||||
{
|
||||
auto election (node.active.election (send1->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election (node.active.election (send1->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (3s, node.ledger.dependents_confirmed (node.store.tx_begin_read (), *send2));
|
||||
node.aggregator.add (channel, request);
|
||||
ASSERT_EQ (1, node.aggregator.size ());
|
||||
|
|
|
|||
|
|
@ -80,13 +80,13 @@ TEST (vote_processor, invalid_signature)
|
|||
genesis.open->sideband_set (nano::block_sideband (nano::genesis_account, 0, nano::genesis_amount, 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false, false, false, nano::epoch::epoch_0));
|
||||
auto election (node.active.insert (genesis.open));
|
||||
ASSERT_TRUE (election.election && election.inserted);
|
||||
ASSERT_EQ (1, election.election->last_votes.size ());
|
||||
ASSERT_EQ (1, election.election->votes ().size ());
|
||||
node.vote_processor.vote (vote_invalid, channel);
|
||||
node.vote_processor.flush ();
|
||||
ASSERT_EQ (1, election.election->last_votes.size ());
|
||||
ASSERT_EQ (1, election.election->votes ().size ());
|
||||
node.vote_processor.vote (vote, channel);
|
||||
node.vote_processor.flush ();
|
||||
ASSERT_EQ (2, election.election->last_votes.size ());
|
||||
ASSERT_EQ (2, election.election->votes ().size ());
|
||||
}
|
||||
|
||||
TEST (vote_processor, no_capacity)
|
||||
|
|
@ -213,8 +213,9 @@ TEST (vote_processor, no_broadcast_local)
|
|||
// Make sure the vote was processed
|
||||
auto election (node.active.election (send->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election);
|
||||
auto existing (election->last_votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (election->last_votes.end (), existing);
|
||||
auto votes (election->votes ());
|
||||
auto existing (votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (votes.end (), existing);
|
||||
ASSERT_EQ (vote->sequence, existing->second.sequence);
|
||||
// Ensure the vote, from a local representative, was not broadcast on processing - it should be flooded on generation instead
|
||||
ASSERT_EQ (0, node.stats.count (nano::stat::type::message, nano::stat::detail::confirm_ack, nano::stat::dir::out));
|
||||
|
|
@ -245,8 +246,9 @@ TEST (vote_processor, no_broadcast_local)
|
|||
// Make sure the vote was processed
|
||||
auto election2 (node.active.election (send2->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election2);
|
||||
auto existing2 (election2->last_votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (election2->last_votes.end (), existing2);
|
||||
auto votes2 (election2->votes ());
|
||||
auto existing2 (votes2.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (votes2.end (), existing2);
|
||||
ASSERT_EQ (vote2->sequence, existing2->second.sequence);
|
||||
// Ensure the vote was broadcast
|
||||
ASSERT_EQ (1, node.stats.count (nano::stat::type::message, nano::stat::detail::confirm_ack, nano::stat::dir::out));
|
||||
|
|
@ -278,8 +280,9 @@ TEST (vote_processor, no_broadcast_local)
|
|||
// Make sure the vote was processed
|
||||
auto election3 (node.active.election (open->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election3);
|
||||
auto existing3 (election3->last_votes.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (election3->last_votes.end (), existing3);
|
||||
auto votes3 (election3->votes ());
|
||||
auto existing3 (votes3.find (nano::dev_genesis_key.pub));
|
||||
ASSERT_NE (votes3.end (), existing3);
|
||||
ASSERT_EQ (vote3->sequence, existing3->second.sequence);
|
||||
// Ensure the vote wass not broadcasst
|
||||
ASSERT_EQ (1, node.stats.count (nano::stat::type::message, nano::stat::detail::confirm_ack, nano::stat::dir::out));
|
||||
|
|
|
|||
|
|
@ -1251,11 +1251,10 @@ TEST (work_watcher, confirm_while_generating)
|
|||
notified = true;
|
||||
});
|
||||
// Confirm the block
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
ASSERT_EQ (1, node.active.roots.size ());
|
||||
node.active.roots.begin ()->election->confirm_once ();
|
||||
}
|
||||
ASSERT_EQ (1, node.active.size ());
|
||||
auto election (node.active.election (block1->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
ASSERT_TIMELY (5s, node.block_confirmed (block1->hash ()));
|
||||
ASSERT_EQ (0, node.work.size ());
|
||||
ASSERT_TRUE (notified);
|
||||
|
|
@ -1485,10 +1484,7 @@ TEST (wallet, search_pending)
|
|||
wallet.store.erase (node.wallets.tx_begin_write (), nano::genesis_account);
|
||||
|
||||
// Now confirm the election
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (5s, node.block_confirmed (send->hash ()) && node.active.empty ());
|
||||
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ void nano::active_transactions::request_confirm (nano::unique_lock<std::mutex> &
|
|||
--optimistic_elections_count;
|
||||
}
|
||||
|
||||
election_l->cleanup ();
|
||||
cleanup_election (election_l->cleanup_info ());
|
||||
i = sorted_roots_l.erase (i);
|
||||
}
|
||||
else
|
||||
|
|
@ -348,6 +348,37 @@ void nano::active_transactions::request_confirm (nano::unique_lock<std::mutex> &
|
|||
}
|
||||
}
|
||||
|
||||
void nano::active_transactions::cleanup_election (nano::election_cleanup_info const & info_a)
|
||||
{
|
||||
debug_assert (!mutex.try_lock ());
|
||||
|
||||
for (auto const & [hash, block] : info_a.blocks)
|
||||
{
|
||||
auto erased (blocks.erase (hash));
|
||||
(void)erased;
|
||||
debug_assert (erased == 1);
|
||||
erase_inactive_votes_cache (hash);
|
||||
// Notify observers about dropped elections & blocks lost confirmed elections
|
||||
if (!info_a.confirmed || hash != info_a.winner)
|
||||
{
|
||||
node.observers.active_stopped.notify (hash);
|
||||
}
|
||||
}
|
||||
|
||||
if (!info_a.confirmed)
|
||||
{
|
||||
recently_dropped.add (info_a.root);
|
||||
|
||||
// Clear network filter in another thread
|
||||
node.worker.push_task ([node_l = node.shared (), blocks_l = std::move (info_a.blocks)]() {
|
||||
for (auto const & block : blocks_l)
|
||||
{
|
||||
node_l->network.publish_filter.clear (block.second);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void nano::active_transactions::add_expired_optimistic_election (nano::election const & election_a)
|
||||
{
|
||||
auto account = election_a.status.winner->account ();
|
||||
|
|
@ -1013,8 +1044,8 @@ double nano::active_transactions::normalized_multiplier (nano::block const & blo
|
|||
{
|
||||
auto election (*root_it_a);
|
||||
debug_assert (election != roots.end ());
|
||||
auto find_block (election->election->blocks.find (block_a.hash ()));
|
||||
if (find_block != election->election->blocks.end () && find_block->second->has_sideband ())
|
||||
auto find_block (election->election->last_blocks.find (block_a.hash ()));
|
||||
if (find_block != election->election->last_blocks.end () && find_block->second->has_sideband ())
|
||||
{
|
||||
threshold = nano::work_threshold (block_a.work_version (), find_block->second->sideband ().details);
|
||||
}
|
||||
|
|
@ -1113,18 +1144,6 @@ double nano::active_transactions::active_multiplier ()
|
|||
return trended_active_multiplier.load ();
|
||||
}
|
||||
|
||||
// List of active blocks in elections
|
||||
std::deque<std::shared_ptr<nano::block>> nano::active_transactions::list_blocks ()
|
||||
{
|
||||
std::deque<std::shared_ptr<nano::block>> result;
|
||||
nano::lock_guard<std::mutex> lock (mutex);
|
||||
for (auto & root : roots)
|
||||
{
|
||||
result.push_back (root.election->status.winner);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::deque<nano::election_status> nano::active_transactions::list_recently_cemented ()
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (mutex);
|
||||
|
|
@ -1161,7 +1180,7 @@ void nano::active_transactions::erase (nano::block const & block_a)
|
|||
auto root_it (roots.get<tag_root> ().find (block_a.qualified_root ()));
|
||||
if (root_it != roots.get<tag_root> ().end ())
|
||||
{
|
||||
root_it->election->cleanup ();
|
||||
cleanup_election (root_it->election->cleanup_info ());
|
||||
roots.get<tag_root> ().erase (root_it);
|
||||
lock.unlock ();
|
||||
node.logger.try_log (boost::str (boost::format ("Election erased for block block %1% root %2%") % block_a.hash ().to_string () % block_a.root ().to_string ()));
|
||||
|
|
|
|||
|
|
@ -195,7 +195,6 @@ public:
|
|||
uint64_t limited_active_difficulty (nano::block const &);
|
||||
uint64_t limited_active_difficulty (nano::work_version const, uint64_t const);
|
||||
double active_multiplier ();
|
||||
std::deque<std::shared_ptr<nano::block>> list_blocks ();
|
||||
void erase (nano::block const &);
|
||||
bool empty ();
|
||||
size_t size ();
|
||||
|
|
@ -245,6 +244,8 @@ private:
|
|||
bool update_difficulty_impl (roots_iterator const &, nano::block const &);
|
||||
void request_loop ();
|
||||
void request_confirm (nano::unique_lock<std::mutex> &);
|
||||
// Erase all blocks from active and, if not confirmed, clear digests from network filters
|
||||
void cleanup_election (nano::election_cleanup_info const &);
|
||||
nano::condition_variable condition;
|
||||
bool started{ false };
|
||||
std::atomic<bool> stopped{ false };
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@
|
|||
|
||||
using namespace std::chrono;
|
||||
|
||||
int constexpr nano::election::passive_duration_factor;
|
||||
int constexpr nano::election::active_request_count_min;
|
||||
int constexpr nano::election::confirmed_duration_factor;
|
||||
|
||||
std::chrono::milliseconds nano::election::base_latency () const
|
||||
{
|
||||
return node.network_params.network.is_dev_network () ? 25ms : 1000ms;
|
||||
|
|
@ -25,14 +21,14 @@ nano::election_vote_result::election_vote_result (bool replay_a, bool processed_
|
|||
nano::election::election (nano::node & node_a, std::shared_ptr<nano::block> block_a, std::function<void(std::shared_ptr<nano::block>)> const & confirmation_action_a, bool prioritized_a, nano::election_behavior election_behavior_a) :
|
||||
confirmation_action (confirmation_action_a),
|
||||
prioritized_m (prioritized_a),
|
||||
election_behavior (election_behavior_a),
|
||||
behavior (election_behavior_a),
|
||||
node (node_a),
|
||||
status ({ block_a, 0, std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::system_clock::now ().time_since_epoch ()), std::chrono::duration_values<std::chrono::milliseconds>::zero (), 0, 1, 0, nano::election_status_type::ongoing }),
|
||||
height (block_a->sideband ().height),
|
||||
root (block_a->root ())
|
||||
{
|
||||
last_votes.emplace (node.network_params.random.not_an_account, nano::vote_info{ std::chrono::steady_clock::now (), 0, block_a->hash () });
|
||||
blocks.emplace (block_a->hash (), block_a);
|
||||
last_blocks.emplace (block_a->hash (), block_a);
|
||||
}
|
||||
|
||||
void nano::election::confirm_once (nano::election_status_type type_a)
|
||||
|
|
@ -45,7 +41,7 @@ void nano::election::confirm_once (nano::election_status_type type_a)
|
|||
status.election_end = std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::system_clock::now ().time_since_epoch ());
|
||||
status.election_duration = std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::steady_clock::now () - election_start);
|
||||
status.confirmation_request_count = confirmation_request_count;
|
||||
status.block_count = nano::narrow_cast<decltype (status.block_count)> (blocks.size ());
|
||||
status.block_count = nano::narrow_cast<decltype (status.block_count)> (last_blocks.size ());
|
||||
status.voter_count = nano::narrow_cast<decltype (status.voter_count)> (last_votes.size ());
|
||||
status.type = type_a;
|
||||
auto status_l (status);
|
||||
|
|
@ -251,16 +247,16 @@ bool nano::election::have_quorum (nano::tally_t const & tally_a, nano::uint128_t
|
|||
nano::tally_t nano::election::tally ()
|
||||
{
|
||||
std::unordered_map<nano::block_hash, nano::uint128_t> block_weights;
|
||||
for (auto vote_info : last_votes)
|
||||
for (auto const & [account, info] : last_votes)
|
||||
{
|
||||
block_weights[vote_info.second.hash] += node.ledger.weight (vote_info.first);
|
||||
block_weights[info.hash] += node.ledger.weight (account);
|
||||
}
|
||||
last_tally = block_weights;
|
||||
nano::tally_t result;
|
||||
for (auto item : block_weights)
|
||||
{
|
||||
auto block (blocks.find (item.first));
|
||||
if (block != blocks.end ())
|
||||
auto block (last_blocks.find (item.first));
|
||||
if (block != last_blocks.end ())
|
||||
{
|
||||
result.emplace (item.second, block->second);
|
||||
}
|
||||
|
|
@ -274,9 +270,9 @@ void nano::election::confirm_if_quorum ()
|
|||
debug_assert (!tally_l.empty ());
|
||||
auto winner (tally_l.begin ());
|
||||
auto block_l (winner->second);
|
||||
auto winner_hash_l (block_l->hash ());
|
||||
auto const & winner_hash_l (block_l->hash ());
|
||||
status.tally = winner->first;
|
||||
auto status_winner_hash_l (status.winner->hash ());
|
||||
auto const & status_winner_hash_l (status.winner->hash ());
|
||||
nano::uint128_t sum (0);
|
||||
for (auto & i : tally_l)
|
||||
{
|
||||
|
|
@ -290,7 +286,7 @@ void nano::election::confirm_if_quorum ()
|
|||
}
|
||||
if (have_quorum (tally_l, sum))
|
||||
{
|
||||
if (node.config.logging.vote_logging () || (node.config.logging.election_fork_tally_logging () && blocks.size () > 1))
|
||||
if (node.config.logging.vote_logging () || (node.config.logging.election_fork_tally_logging () && last_blocks.size () > 1))
|
||||
{
|
||||
log_votes (tally_l);
|
||||
}
|
||||
|
|
@ -376,7 +372,7 @@ bool nano::election::publish (std::shared_ptr<nano::block> block_a)
|
|||
{
|
||||
// Do not insert new blocks if already confirmed
|
||||
auto result (confirmed ());
|
||||
if (!result && blocks.size () >= 10)
|
||||
if (!result && last_blocks.size () >= 10)
|
||||
{
|
||||
if (last_tally[block_a->hash ()] < node.online_reps.online_stake () / 10)
|
||||
{
|
||||
|
|
@ -385,10 +381,10 @@ bool nano::election::publish (std::shared_ptr<nano::block> block_a)
|
|||
}
|
||||
if (!result)
|
||||
{
|
||||
auto existing = blocks.find (block_a->hash ());
|
||||
if (existing == blocks.end ())
|
||||
auto existing = last_blocks.find (block_a->hash ());
|
||||
if (existing == last_blocks.end ())
|
||||
{
|
||||
blocks.emplace (std::make_pair (block_a->hash (), block_a));
|
||||
last_blocks.emplace (std::make_pair (block_a->hash (), block_a));
|
||||
if (!insert_inactive_votes_cache (block_a->hash ()))
|
||||
{
|
||||
// Even if no votes were in cache, they could be in the election
|
||||
|
|
@ -409,42 +405,15 @@ bool nano::election::publish (std::shared_ptr<nano::block> block_a)
|
|||
return result;
|
||||
}
|
||||
|
||||
size_t nano::election::last_votes_size ()
|
||||
nano::election_cleanup_info nano::election::cleanup_info () const
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (node.active.mutex);
|
||||
return last_votes.size ();
|
||||
}
|
||||
|
||||
void nano::election::cleanup ()
|
||||
{
|
||||
bool unconfirmed (!confirmed ());
|
||||
auto winner_root (status.winner->qualified_root ());
|
||||
auto winner_hash (status.winner->hash ());
|
||||
for (auto const & block : blocks)
|
||||
{
|
||||
auto & hash (block.first);
|
||||
auto erased (node.active.blocks.erase (hash));
|
||||
(void)erased;
|
||||
debug_assert (erased == 1);
|
||||
node.active.erase_inactive_votes_cache (hash);
|
||||
// Notify observers about dropped elections & blocks lost confirmed elections
|
||||
if (unconfirmed || hash != winner_hash)
|
||||
{
|
||||
node.observers.active_stopped.notify (hash);
|
||||
}
|
||||
}
|
||||
if (unconfirmed)
|
||||
{
|
||||
node.active.recently_dropped.add (winner_root);
|
||||
|
||||
// Clear network filter in another thread
|
||||
node.worker.push_task ([node_l = node.shared (), blocks_l = std::move (blocks)]() {
|
||||
for (auto const & block : blocks_l)
|
||||
{
|
||||
node_l->network.publish_filter.clear (block.second);
|
||||
}
|
||||
});
|
||||
}
|
||||
debug_assert (!node.active.mutex.try_lock ());
|
||||
return nano::election_cleanup_info{
|
||||
confirmed (),
|
||||
status.winner->qualified_root (),
|
||||
status.winner->hash (),
|
||||
last_blocks
|
||||
};
|
||||
}
|
||||
|
||||
size_t nano::election::insert_inactive_votes_cache (nano::block_hash const & hash_a)
|
||||
|
|
@ -478,7 +447,7 @@ bool nano::election::prioritized () const
|
|||
|
||||
bool nano::election::optimistic () const
|
||||
{
|
||||
return election_behavior == nano::election_behavior::optimistic;
|
||||
return behavior == nano::election_behavior::optimistic;
|
||||
}
|
||||
|
||||
void nano::election::prioritize_election (nano::vote_generator_session & generator_session_a)
|
||||
|
|
@ -489,6 +458,12 @@ void nano::election::prioritize_election (nano::vote_generator_session & generat
|
|||
generator_session_a.add (root, status.winner->hash ());
|
||||
}
|
||||
|
||||
std::shared_ptr<nano::block> nano::election::winner ()
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
return status.winner;
|
||||
}
|
||||
|
||||
void nano::election::generate_votes ()
|
||||
{
|
||||
debug_assert (!node.active.mutex.try_lock ());
|
||||
|
|
@ -512,3 +487,24 @@ void nano::election::remove_votes (nano::block_hash const & hash_a)
|
|||
node.history.erase (root);
|
||||
}
|
||||
}
|
||||
|
||||
void nano::election::force_confirm (nano::election_status_type type_a)
|
||||
{
|
||||
release_assert (node.network_params.network.is_dev_network ());
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
confirm_once (type_a);
|
||||
}
|
||||
|
||||
std::unordered_map<nano::block_hash, std::shared_ptr<nano::block>> nano::election::blocks ()
|
||||
{
|
||||
debug_assert (node.network_params.network.is_dev_network ());
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
return last_blocks;
|
||||
}
|
||||
|
||||
std::unordered_map<nano::account, nano::vote_info> nano::election::votes ()
|
||||
{
|
||||
debug_assert (node.network_params.network.is_dev_network ());
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
return last_votes;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ namespace nano
|
|||
{
|
||||
class channel;
|
||||
class confirmation_solicitor;
|
||||
class json_handler;
|
||||
class node;
|
||||
class vote_generator_session;
|
||||
class vote_info final
|
||||
|
|
@ -35,6 +36,13 @@ enum class election_behavior
|
|||
normal,
|
||||
optimistic
|
||||
};
|
||||
struct election_cleanup_info final
|
||||
{
|
||||
bool confirmed;
|
||||
nano::qualified_root root;
|
||||
nano::block_hash winner;
|
||||
std::unordered_map<nano::block_hash, std::shared_ptr<nano::block>> blocks;
|
||||
};
|
||||
|
||||
class election final : public std::enable_shared_from_this<nano::election>
|
||||
{
|
||||
|
|
@ -52,9 +60,9 @@ private: // State management
|
|||
expired_confirmed,
|
||||
expired_unconfirmed
|
||||
};
|
||||
static int constexpr passive_duration_factor = 5;
|
||||
static int constexpr active_request_count_min = 2;
|
||||
static int constexpr confirmed_duration_factor = 5;
|
||||
static unsigned constexpr passive_duration_factor = 5;
|
||||
static unsigned constexpr active_request_count_min = 2;
|
||||
static unsigned constexpr confirmed_duration_factor = 5;
|
||||
std::atomic<nano::election::state_t> state_m = { state_t::passive };
|
||||
|
||||
// These time points must be protected by this mutex
|
||||
|
|
@ -65,54 +73,73 @@ private: // State management
|
|||
|
||||
bool valid_change (nano::election::state_t, nano::election::state_t) const;
|
||||
bool state_change (nano::election::state_t, nano::election::state_t);
|
||||
void broadcast_block (nano::confirmation_solicitor &);
|
||||
void send_confirm_req (nano::confirmation_solicitor &);
|
||||
// Calculate votes for local representatives
|
||||
void generate_votes ();
|
||||
void remove_votes (nano::block_hash const &);
|
||||
std::atomic<bool> prioritized_m = { false };
|
||||
|
||||
public:
|
||||
election (nano::node &, std::shared_ptr<nano::block>, std::function<void(std::shared_ptr<nano::block>)> const &, bool, nano::election_behavior);
|
||||
nano::election_vote_result vote (nano::account, uint64_t, nano::block_hash);
|
||||
nano::tally_t tally ();
|
||||
// Check if we have vote quorum
|
||||
bool have_quorum (nano::tally_t const &, nano::uint128_t) const;
|
||||
void confirm_once (nano::election_status_type = nano::election_status_type::active_confirmed_quorum);
|
||||
// Confirm this block if quorum is met
|
||||
void confirm_if_quorum ();
|
||||
void log_votes (nano::tally_t const &, std::string const & = "") const;
|
||||
bool publish (std::shared_ptr<nano::block> block_a);
|
||||
size_t last_votes_size ();
|
||||
size_t insert_inactive_votes_cache (nano::block_hash const &);
|
||||
bool prioritized () const;
|
||||
bool optimistic () const;
|
||||
void prioritize_election (nano::vote_generator_session &);
|
||||
// Erase all blocks from active and, if not confirmed, clear digests from network filters
|
||||
void cleanup ();
|
||||
|
||||
public: // State transitions
|
||||
bool transition_time (nano::confirmation_solicitor &);
|
||||
void transition_active ();
|
||||
|
||||
private:
|
||||
void transition_active_impl ();
|
||||
|
||||
public:
|
||||
public: // Status
|
||||
bool confirmed () const;
|
||||
bool failed () const;
|
||||
nano::election_behavior election_behavior{ nano::election_behavior::normal };
|
||||
nano::node & node;
|
||||
std::unordered_map<nano::account, nano::vote_info> last_votes;
|
||||
std::unordered_map<nano::block_hash, std::shared_ptr<nano::block>> blocks;
|
||||
std::chrono::steady_clock::time_point election_start = { std::chrono::steady_clock::now () };
|
||||
bool prioritized () const;
|
||||
bool optimistic () const;
|
||||
std::shared_ptr<nano::block> winner ();
|
||||
|
||||
void log_votes (nano::tally_t const &, std::string const & = "") const;
|
||||
nano::tally_t tally ();
|
||||
bool have_quorum (nano::tally_t const &, nano::uint128_t) const;
|
||||
|
||||
nano::election_status status;
|
||||
unsigned confirmation_request_count{ 0 };
|
||||
std::unordered_map<nano::block_hash, nano::uint128_t> last_tally;
|
||||
std::chrono::seconds late_blocks_delay{ 5 };
|
||||
|
||||
public: // Interface
|
||||
election (nano::node &, std::shared_ptr<nano::block>, std::function<void(std::shared_ptr<nano::block>)> const &, bool, nano::election_behavior);
|
||||
nano::election_vote_result vote (nano::account, uint64_t, nano::block_hash);
|
||||
bool publish (std::shared_ptr<nano::block> block_a);
|
||||
size_t insert_inactive_votes_cache (nano::block_hash const &);
|
||||
// Confirm this block if quorum is met
|
||||
void confirm_if_quorum ();
|
||||
void prioritize_election (nano::vote_generator_session &);
|
||||
nano::election_cleanup_info cleanup_info () const;
|
||||
|
||||
public: // Information
|
||||
uint64_t const height;
|
||||
nano::root const root;
|
||||
|
||||
private:
|
||||
void transition_active_impl ();
|
||||
void confirm_once (nano::election_status_type = nano::election_status_type::active_confirmed_quorum);
|
||||
void broadcast_block (nano::confirmation_solicitor &);
|
||||
void send_confirm_req (nano::confirmation_solicitor &);
|
||||
// Calculate votes for local representatives
|
||||
void generate_votes ();
|
||||
void remove_votes (nano::block_hash const &);
|
||||
|
||||
private:
|
||||
std::unordered_map<nano::block_hash, std::shared_ptr<nano::block>> last_blocks;
|
||||
std::unordered_map<nano::account, nano::vote_info> last_votes;
|
||||
std::unordered_map<nano::block_hash, nano::uint128_t> last_tally;
|
||||
|
||||
nano::election_behavior const behavior{ nano::election_behavior::normal };
|
||||
std::chrono::steady_clock::time_point const election_start = { std::chrono::steady_clock::now () };
|
||||
|
||||
nano::node & node;
|
||||
|
||||
static std::chrono::seconds constexpr late_blocks_delay{ 5 };
|
||||
|
||||
friend class active_transactions;
|
||||
friend class confirmation_solicitor;
|
||||
friend class json_handler;
|
||||
|
||||
public: // Only used in tests
|
||||
void force_confirm (nano::election_status_type = nano::election_status_type::active_confirmed_quorum);
|
||||
std::unordered_map<nano::account, nano::vote_info> votes ();
|
||||
std::unordered_map<nano::block_hash, std::shared_ptr<nano::block>> blocks ();
|
||||
|
||||
friend class confirmation_solicitor_different_hash_Test;
|
||||
friend class confirmation_solicitor_bypass_max_requests_cap_Test;
|
||||
friend class votes_add_existing_Test;
|
||||
friend class votes_add_old_Test;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6726,12 +6726,9 @@ TEST (rpc, block_confirmed)
|
|||
node->process_active (send);
|
||||
node->block_processor.flush ();
|
||||
node->block_confirm (send);
|
||||
{
|
||||
auto election = node->active.election (send->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
}
|
||||
auto election = node->active.election (send->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
// Wait until the confirmation height has been set
|
||||
ASSERT_TIMELY (10s, node->ledger.block_confirmed (node->store.tx_begin_read (), send->hash ()) && !node->confirmation_height_processor.is_processing_block (send->hash ()));
|
||||
|
|
@ -7722,12 +7719,9 @@ TEST (rpc, confirmation_active)
|
|||
node1.process_active (send2);
|
||||
nano::blocks_confirm (node1, { send1, send2 });
|
||||
ASSERT_EQ (2, node1.active.size ());
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node1.active.mutex);
|
||||
auto info (node1.active.roots.find (send1->qualified_root ()));
|
||||
ASSERT_NE (node1.active.roots.end (), info);
|
||||
info->election->confirm_once ();
|
||||
}
|
||||
auto election (node1.active.election (send1->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
boost::property_tree::ptree request;
|
||||
request.put ("action", "confirmation_active");
|
||||
|
|
|
|||
|
|
@ -224,8 +224,10 @@ TEST (node, fork_storm)
|
|||
}
|
||||
else
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (node_a->active.mutex);
|
||||
if (node_a->active.roots.begin ()->election->last_votes_size () == 1)
|
||||
nano::unique_lock<std::mutex> lock (node_a->active.mutex);
|
||||
auto election = node_a->active.roots.begin ()->election;
|
||||
lock.unlock ();
|
||||
if (election->votes ().size () == 1)
|
||||
{
|
||||
++single;
|
||||
}
|
||||
|
|
@ -490,8 +492,7 @@ TEST (confirmation_height, many_accounts_single_confirmation)
|
|||
auto election_insertion_result (node->active.insert (block));
|
||||
ASSERT_TRUE (election_insertion_result.inserted);
|
||||
ASSERT_NE (nullptr, election_insertion_result.election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election_insertion_result.election->confirm_once ();
|
||||
election_insertion_result.election->force_confirm ();
|
||||
}
|
||||
|
||||
ASSERT_TIMELY (120s, node->ledger.block_confirmed (node->store.tx_begin_read (), last_open_hash));
|
||||
|
|
@ -559,8 +560,7 @@ TEST (confirmation_height, many_accounts_many_confirmations)
|
|||
auto election_insertion_result (node->active.insert (open_block));
|
||||
ASSERT_TRUE (election_insertion_result.inserted);
|
||||
ASSERT_NE (nullptr, election_insertion_result.election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election_insertion_result.election->confirm_once ();
|
||||
election_insertion_result.election->force_confirm ();
|
||||
}
|
||||
|
||||
auto const num_blocks_to_confirm = (num_accounts - 1) * 2;
|
||||
|
|
@ -647,8 +647,7 @@ TEST (confirmation_height, long_chains)
|
|||
auto election_insertion_result (node->active.insert (receive1));
|
||||
ASSERT_TRUE (election_insertion_result.inserted);
|
||||
ASSERT_NE (nullptr, election_insertion_result.election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election_insertion_result.election->confirm_once ();
|
||||
election_insertion_result.election->force_confirm ();
|
||||
}
|
||||
|
||||
ASSERT_TIMELY (30s, node->ledger.block_confirmed (node->store.tx_begin_read (), receive1->hash ()));
|
||||
|
|
@ -845,8 +844,7 @@ TEST (confirmation_height, many_accounts_send_receive_self)
|
|||
node->block_confirm (open_block);
|
||||
auto election = node->active.election (open_block->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
nano::lock_guard<std::mutex> guard (node->active.mutex);
|
||||
election->confirm_once ();
|
||||
election->force_confirm ();
|
||||
}
|
||||
|
||||
system.deadline_set (100s);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue