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:
Guilherme Lawless 2020-09-22 09:17:48 +01:00 committed by GitHub
commit 1e7be31727
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 464 additions and 663 deletions

View file

@ -55,7 +55,7 @@ TEST (active_transactions, confirm_active)
// At least one confirmation request // At least one confirmation request
ASSERT_GT (election->confirmation_request_count, 0u); ASSERT_GT (election->confirmation_request_count, 0u);
// Blocks were cleared (except for not_an_account) // 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 // should not drop wallet created transactions
ASSERT_TIMELY (5s, node.active.size () == 6); ASSERT_TIMELY (5s, node.active.size () == 6);
ASSERT_EQ (0, node.active.recently_dropped.size ()); 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); auto election = node.active.election (block->qualified_root ());
if (!node.active.roots.empty ()) ASSERT_NE (nullptr, election);
{ election->force_confirm ();
node.active.roots.begin ()->election->confirm_once ();
}
} }
ASSERT_TIMELY (5s, node.active.empty ());
nano::state_block_builder builder; nano::state_block_builder builder;
auto open1 = builder.make_block () auto open1 = builder.make_block ()
.account (key1.pub) .account (key1.pub)
@ -260,38 +259,28 @@ TEST (active_transactions, inactive_votes_cache_existing_vote)
node.block_processor.add (open); node.block_processor.add (open);
node.block_processor.flush (); node.block_processor.flush ();
ASSERT_TIMELY (5s, node.active.size () == 1); ASSERT_TIMELY (5s, node.active.size () == 1);
std::shared_ptr<nano::election> election; auto election (node.active.election (send->qualified_root ()));
{ ASSERT_NE (nullptr, 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;
}
ASSERT_GT (node.weight (key.pub), node.minimum_principal_weight ()); ASSERT_GT (node.weight (key.pub), node.minimum_principal_weight ());
// Insert vote // Insert vote
auto vote1 (std::make_shared<nano::vote> (key.pub, key.prv, 1, std::vector<nano::block_hash> (1, send->hash ()))); 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)); 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); system.deadline_set (5s);
bool done (false); ASSERT_TIMELY (5s, election->votes ().size () == 2)
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_EQ (1, node.stats.count (nano::stat::type::election, nano::stat::detail::vote_new)); 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->votes ()[key.pub]);
auto last_vote1 (election->last_votes[key.pub]);
ASSERT_EQ (send->hash (), last_vote1.hash); ASSERT_EQ (send->hash (), last_vote1.hash);
ASSERT_EQ (1, last_vote1.sequence); ASSERT_EQ (1, last_vote1.sequence);
// Attempt to change vote with inactive_votes_cache // Attempt to change vote with inactive_votes_cache
{
nano::lock_guard<std::mutex> active_guard (node.active.mutex);
node.active.add_inactive_votes_cache (send->hash (), key.pub); node.active.add_inactive_votes_cache (send->hash (), key.pub);
ASSERT_EQ (1, node.active.find_inactive_votes_cache (send->hash ()).voters.size ()); ASSERT_EQ (1, node.active.find_inactive_votes_cache (send->hash ()).voters.size ());
election->insert_inactive_votes_cache (send->hash ()); election->insert_inactive_votes_cache (send->hash ());
}
// Check that election data is not changed // Check that election data is not changed
ASSERT_EQ (2, election->last_votes.size ()); ASSERT_EQ (2, election->votes ().size ());
auto last_vote2 (election->last_votes[key.pub]); auto last_vote2 (election->votes ()[key.pub]);
ASSERT_EQ (last_vote1.hash, last_vote2.hash); ASSERT_EQ (last_vote1.hash, last_vote2.hash);
ASSERT_EQ (last_vote1.sequence, last_vote2.sequence); ASSERT_EQ (last_vote1.sequence, last_vote2.sequence);
ASSERT_EQ (last_vote1.time, last_vote2.time); 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 ()); ASSERT_EQ (1, node.active.inactive_votes_cache_size ());
// Start election // Start election
node.active.insert (send1); node.active.insert (send1);
{ auto election = node.active.insert (send1).election;
nano::lock_guard<std::mutex> active_guard (node.active.mutex); ASSERT_EQ (3, election->votes ().size ()); // 2 votes and 1 default not_an_acount
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
}
ASSERT_EQ (2, node.stats.count (nano::stat::type::election, nano::stat::detail::vote_cached)); 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 // Now simulate dropping the election, which performs a cleanup in the background using the node worker
ASSERT_FALSE (election->confirmed ()); ASSERT_FALSE (election->confirmed ());
{ node.active.erase (*block);
nano::lock_guard<std::mutex> guard (node.active.mutex);
election->cleanup ();
}
// Push a worker task to ensure the cleanup is already performed // Push a worker task to ensure the cleanup is already performed
std::atomic<bool> flag{ false }; std::atomic<bool> flag{ false };
@ -1056,12 +1038,9 @@ TEST (active_transactions, election_difficulty_update_fork)
for (auto block : { open1, send2 }) for (auto block : { open1, send2 })
{ {
node.block_confirm (block); node.block_confirm (block);
{
auto election = node.active.election (block->qualified_root ()); auto election = node.active.election (block->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node.active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (2s, node.block_confirmed (block->hash ())); ASSERT_TIMELY (2s, node.block_confirmed (block->hash ()));
node.active.erase (*block); node.active.erase (*block);
} }
@ -1324,25 +1303,19 @@ TEST (active_transactions, activate_account_chain)
auto result = node.active.activate (nano::dev_genesis_key.pub); auto result = node.active.activate (nano::dev_genesis_key.pub);
ASSERT_TRUE (result.inserted); ASSERT_TRUE (result.inserted);
ASSERT_EQ (1, node.active.size ()); 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); auto result2 = node.active.activate (nano::dev_genesis_key.pub);
ASSERT_FALSE (result2.inserted); ASSERT_FALSE (result2.inserted);
ASSERT_EQ (result2.election, result.election); ASSERT_EQ (result2.election, result.election);
{ result.election->force_confirm ();
nano::lock_guard<std::mutex> guard (node.active.mutex);
result.election->confirm_once ();
}
ASSERT_TIMELY (3s, node.block_confirmed (send->hash ())); ASSERT_TIMELY (3s, node.block_confirmed (send->hash ()));
// On cementing, the next election is started // On cementing, the next election is started
ASSERT_TIMELY (3s, node.active.active (send2->qualified_root ())); ASSERT_TIMELY (3s, node.active.active (send2->qualified_root ()));
auto result3 = node.active.activate (nano::dev_genesis_key.pub); auto result3 = node.active.activate (nano::dev_genesis_key.pub);
ASSERT_FALSE (result3.inserted); ASSERT_FALSE (result3.inserted);
ASSERT_NE (nullptr, result3.election); ASSERT_NE (nullptr, result3.election);
ASSERT_EQ (1, result3.election->blocks.count (send2->hash ())); ASSERT_EQ (1, result3.election->blocks ().count (send2->hash ()));
{ result3.election->force_confirm ();
nano::lock_guard<std::mutex> guard (node.active.mutex);
result3.election->confirm_once ();
}
ASSERT_TIMELY (3s, node.block_confirmed (send2->hash ())); ASSERT_TIMELY (3s, node.block_confirmed (send2->hash ()));
// On cementing, the next election is started // On cementing, the next election is started
ASSERT_TIMELY (3s, node.active.active (open->qualified_root ())); 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); auto result4 = node.active.activate (nano::dev_genesis_key.pub);
ASSERT_FALSE (result4.inserted); ASSERT_FALSE (result4.inserted);
ASSERT_NE (nullptr, result4.election); 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); auto result5 = node.active.activate (key.pub);
ASSERT_FALSE (result5.inserted); ASSERT_FALSE (result5.inserted);
ASSERT_NE (nullptr, result5.election); ASSERT_NE (nullptr, result5.election);
ASSERT_EQ (1, result5.election->blocks.count (open->hash ())); ASSERT_EQ (1, result5.election->blocks ().count (open->hash ()));
{ result5.election->force_confirm ();
nano::lock_guard<std::mutex> guard (node.active.mutex);
result5.election->confirm_once ();
}
ASSERT_TIMELY (3s, node.block_confirmed (open->hash ())); ASSERT_TIMELY (3s, node.block_confirmed (open->hash ()));
// Until send3 is also confirmed, the receive block should not activate // Until send3 is also confirmed, the receive block should not activate
std::this_thread::sleep_for (200ms); std::this_thread::sleep_for (200ms);
auto result6 = node.active.activate (key.pub); auto result6 = node.active.activate (key.pub);
ASSERT_FALSE (result6.inserted); ASSERT_FALSE (result6.inserted);
ASSERT_EQ (nullptr, result6.election); ASSERT_EQ (nullptr, result6.election);
{ result4.election->force_confirm ();
nano::lock_guard<std::mutex> guard (node.active.mutex);
result4.election->confirm_once ();
}
ASSERT_TIMELY (3s, node.block_confirmed (send3->hash ())); ASSERT_TIMELY (3s, node.block_confirmed (send3->hash ()));
ASSERT_TIMELY (3s, node.active.active (receive->qualified_root ())); 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); ASSERT_EQ (nano::process_result::progress, node.process (*open).code);
node.block_confirm (send2); node.block_confirm (send2);
{
auto election = node.active.election (send2->qualified_root ()); auto election = node.active.election (send2->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node.active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (3s, !node.confirmation_height_processor.is_processing_added_block (send2->hash ())); ASSERT_TIMELY (3s, !node.confirmation_height_processor.is_processing_added_block (send2->hash ()));
ASSERT_TRUE (node.block_confirmed (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 (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 (node.active.expired_optimistic_election_infos_size, node.active.expired_optimistic_election_infos.size ());
{
ASSERT_EQ (1, node.active.size ()); ASSERT_EQ (1, node.active.size ());
auto election = node.active.election (send->qualified_root ()); auto election = node.active.election (send->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node.active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (3s, node.block_confirmed (send->hash ()) && !node.confirmation_height_processor.is_processing_added_block (send->hash ())); 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 ()); ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ());
// Confirm it // Confirm it
{ election = node.active.election (send2->qualified_root ());
auto election = node.active.election (send2->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node.active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (3s, node.block_confirmed (send2->hash ())); 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 ()); ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ());
node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count); node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count);
{ election = node.active.election (open->qualified_root ());
auto election = node.active.election (open->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node.active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (3s, node.block_confirmed (open->hash ())); ASSERT_TIMELY (3s, node.block_confirmed (open->hash ()));

View file

@ -879,12 +879,9 @@ TEST (bootstrap_processor, bootstrap_fork)
ASSERT_EQ (nano::process_result::progress, node0->process (*send).code); ASSERT_EQ (nano::process_result::progress, node0->process (*send).code);
// Confirm send block to vote later // Confirm send block to vote later
node0->block_confirm (send); node0->block_confirm (send);
{
auto election = node0->active.election (send->qualified_root ()); auto election = node0->active.election (send->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node0->active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (2s, node0->block_confirmed (send->hash ())); ASSERT_TIMELY (2s, node0->block_confirmed (send->hash ()));
node0->active.erase (*send); node0->active.erase (*send);
auto open_work (*system.work.generate (key.pub)); auto open_work (*system.work.generate (key.pub));

View file

@ -151,12 +151,9 @@ TEST (confirmation_height, multiple_accounts)
node->process_active (receive3); node->process_active (receive3);
node->block_processor.flush (); node->block_processor.flush ();
node->block_confirm (receive3); node->block_confirm (receive3);
{
auto election = node->active.election (receive3->qualified_root ()); auto election = node->active.election (receive3->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 10); 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->process_active (receive4);
node->block_processor.flush (); node->block_processor.flush ();
node->block_confirm (receive4); node->block_confirm (receive4);
{
auto election = node->active.election (receive4->qualified_root ()); auto election = node->active.election (receive4->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 10); 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); add_callback_stats (*node);
node->block_confirm (receive3); node->block_confirm (receive3);
{
auto election = node->active.election (receive3->qualified_root ()); auto election = node->active.election (receive3->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 6); 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); add_callback_stats (*node);
node->block_confirm (state_send2); node->block_confirm (state_send2);
{
auto election = node->active.election (state_send2->qualified_root ()); auto election = node->active.election (state_send2->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 15); 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 (); node1->block_processor.flush ();
node2->network.process_message (publish1, channel2); node2->network.process_message (publish1, channel2);
node2->block_processor.flush (); node2->block_processor.flush ();
nano::unique_lock<std::mutex> lock (node2->active.mutex); auto election (node2->active.election (nano::qualified_root (genesis.hash (), genesis.hash ())));
auto conflict (node2->active.roots.find (nano::qualified_root (genesis.hash (), genesis.hash ()))); ASSERT_NE (nullptr, election);
ASSERT_NE (node2->active.roots.end (), conflict); ASSERT_EQ (1, election->votes ().size ());
auto votes1 (conflict->election);
ASSERT_NE (nullptr, votes1);
ASSERT_EQ (1, votes1->last_votes.size ());
lock.unlock ();
// Force blocks to be cemented on both nodes // Force blocks to be cemented on both nodes
{ {
auto transaction (node1->store.tx_begin_write ()); 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 transaction1 (node1->store.tx_begin_read ());
auto transaction2 (node2->store.tx_begin_read ()); auto transaction2 (node2->store.tx_begin_read ());
lock.lock (); nano::unique_lock<std::mutex> lock (node2->active.mutex);
auto winner (*votes1->tally ().begin ()); auto winner (*election->tally ().begin ());
ASSERT_EQ (*publish1.block, *winner.second); ASSERT_EQ (*publish1.block, *winner.second);
ASSERT_EQ (nano::genesis_amount - 100, winner.first); ASSERT_EQ (nano::genesis_amount - 100, winner.first);
ASSERT_TRUE (node1->store.block_exists (transaction1, publish1.block->hash ())); 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); auto write_guard = node->write_database_queue.wait (nano::writer::testing);
// Confirm send1 // Confirm send1
{
auto election = node->active.election (send1->qualified_root ()); auto election = node->active.election (send1->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (10s, node->active.size () == 0); ASSERT_TIMELY (10s, node->active.size () == 0);
ASSERT_EQ (0, node->active.list_recently_cemented ().size ()); ASSERT_EQ (0, node->active.list_recently_cemented ().size ());
{ {
@ -1104,12 +1085,9 @@ TEST (confirmation_height, dependent_election)
node->block_confirm (send1); node->block_confirm (send1);
// Start an election and confirm it // Start an election and confirm it
node->block_confirm (send2); node->block_confirm (send2);
{
auto election = node->active.election (send2->qualified_root ()); auto election = node->active.election (send2->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 3); 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); add_callback_stats (*node, &observer_order, &mutex);
node->block_confirm (open1); node->block_confirm (open1);
{
auto election = node->active.election (open1->qualified_root ()); auto election = node->active.election (open1->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 10); 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 (); auto transaction = node->store.tx_begin_read ();
@ -1279,12 +1254,9 @@ TEST (confirmation_height, cemented_gap_below_no_cache)
add_callback_stats (*node); add_callback_stats (*node);
node->block_confirm (open1); node->block_confirm (open1);
{
auto election = node->active.election (open1->qualified_root ()); auto election = node->active.election (open1->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 6); 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 (); auto transaction = node->store.tx_begin_read ();
@ -1329,23 +1301,17 @@ TEST (confirmation_height, election_winner_details_clearing)
add_callback_stats (*node); add_callback_stats (*node);
node->block_confirm (send1); node->block_confirm (send1);
{
auto election = node->active.election (send1->qualified_root ()); auto election = node->active.election (send1->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 2); 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 ()); ASSERT_EQ (0, node->active.election_winner_details_size ());
node->block_confirm (send); node->block_confirm (send);
{ election = node->active.election (send->qualified_root ());
auto election = node->active.election (send->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election->force_confirm ();
election->confirm_once ();
}
// Wait until this block is confirmed // Wait until this block is confirmed
ASSERT_TIMELY (10s, node->active.election_winner_details_size () == 1 || node->confirmation_height_processor.current ().is_zero ()); 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)); 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); node->block_confirm (send2);
{ election = node->active.election (send2->qualified_root ());
auto election = node->active.election (send2->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 3); ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 3);

View file

@ -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)); 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) TEST (confirmation_solicitor, different_hash)
{ {
nano::system system; nano::system system;
@ -73,15 +75,12 @@ TEST (confirmation_solicitor, different_hash)
ASSERT_TIMELY (3s, node2.network.size () == 1); 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))); 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 ({}); 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)); auto election (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal));
// Add a vote for something else, not the winner // Add a vote for something else, not the winner
election->last_votes[representative.account] = { std::chrono::steady_clock::now (), 1, 1 }; election->last_votes[representative.account] = { std::chrono::steady_clock::now (), 1, 1 };
// Ensure the request and broadcast goes through // Ensure the request and broadcast goes through
ASSERT_FALSE (solicitor.add (*election)); ASSERT_FALSE (solicitor.add (*election));
ASSERT_FALSE (solicitor.broadcast (*election)); ASSERT_FALSE (solicitor.broadcast (*election));
}
// One publish through directed broadcasting and another through random flooding // 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)); ASSERT_EQ (2, node2.stats.count (nano::stat::type::message, nano::stat::detail::publish, nano::stat::dir::out));
solicitor.flush (); solicitor.flush ();
@ -112,32 +111,26 @@ TEST (confirmation_solicitor, bypass_max_requests_cap)
ASSERT_TIMELY (3s, node2.network.size () == 1); 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))); 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 ({}); 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)); auto election (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal));
// Add a vote for something else, not the winner // Add a vote for something else, not the winner
for (auto const & rep : representatives) for (auto const & rep : representatives)
{ {
nano::lock_guard<std::mutex> guard (node1.active.mutex);
election->last_votes[rep.account] = { std::chrono::steady_clock::now (), 1, 1 }; election->last_votes[rep.account] = { std::chrono::steady_clock::now (), 1, 1 };
} }
ASSERT_FALSE (solicitor.add (*election)); ASSERT_FALSE (solicitor.add (*election));
ASSERT_FALSE (solicitor.broadcast (*election)); ASSERT_FALSE (solicitor.broadcast (*election));
}
solicitor.flush (); 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 // 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)); ASSERT_EQ (max_representatives + 1, node2.stats.count (nano::stat::type::message, nano::stat::detail::confirm_req, nano::stat::dir::out));
solicitor.prepare (representatives); solicitor.prepare (representatives);
{ auto election2 (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal));
nano::lock_guard<std::mutex> guard (node2.active.mutex); ASSERT_FALSE (solicitor.add (*election2));
auto election (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal)); ASSERT_FALSE (solicitor.broadcast (*election2));
// Erase all votes
election->last_votes.clear ();
ASSERT_FALSE (solicitor.add (*election));
ASSERT_FALSE (solicitor.broadcast (*election));
}
solicitor.flush (); solicitor.flush ();
// All requests but one went through, due to the cap // 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)); ASSERT_EQ (2 * max_representatives + 1, node2.stats.count (nano::stat::type::message, nano::stat::detail::confirm_req, nano::stat::dir::out));
} }
}

View file

@ -20,11 +20,8 @@ TEST (conflicts, start_stop)
ASSERT_EQ (0, node1.active.size ()); ASSERT_EQ (0, node1.active.size ());
auto election1 = node1.active.insert (send1); auto election1 = node1.active.insert (send1);
ASSERT_EQ (1, node1.active.size ()); ASSERT_EQ (1, node1.active.size ());
{
nano::lock_guard<std::mutex> guard (node1.active.mutex);
ASSERT_NE (nullptr, election1.election); ASSERT_NE (nullptr, election1.election);
ASSERT_EQ (1, election1.election->last_votes.size ()); ASSERT_EQ (1, election1.election->votes ().size ());
}
} }
TEST (conflicts, add_existing) TEST (conflicts, add_existing)
@ -44,13 +41,10 @@ TEST (conflicts, add_existing)
ASSERT_EQ (1, node1.active.size ()); ASSERT_EQ (1, node1.active.size ());
auto vote1 (std::make_shared<nano::vote> (key2.pub, key2.prv, 0, send2)); auto vote1 (std::make_shared<nano::vote> (key2.pub, key2.prv, 0, send2));
node1.active.vote (vote1); 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_NE (nullptr, election1.election);
ASSERT_EQ (2, election1.election->last_votes.size ()); ASSERT_EQ (2, election1.election->votes ().size ());
ASSERT_NE (election1.election->last_votes.end (), election1.election->last_votes.find (key2.pub)); auto votes (election1.election->votes ());
} ASSERT_NE (votes.end (), votes.find (key2.pub));
} }
TEST (conflicts, add_two) TEST (conflicts, add_two)

View file

@ -73,12 +73,9 @@ TEST (gap_cache, gap_bootstrap)
ASSERT_EQ (nano::genesis_amount, node2.balance (nano::genesis_account)); ASSERT_EQ (nano::genesis_amount, node2.balance (nano::genesis_account));
// Confirm send block, allowing voting on the upcoming block // Confirm send block, allowing voting on the upcoming block
node1.block_confirm (send); node1.block_confirm (send);
{
auto election = node1.active.election (send->qualified_root ()); auto election = node1.active.election (send->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node1.active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (2s, node1.block_confirmed (send->hash ())); ASSERT_TIMELY (2s, node1.block_confirmed (send->hash ()));
node1.active.erase (*send); node1.active.erase (*send);
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv); system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);

View file

@ -767,10 +767,7 @@ TEST (votes, check_signature)
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code); ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code);
} }
auto election1 = node1.active.insert (send1); auto election1 = node1.active.insert (send1);
{ ASSERT_EQ (1, election1.election->votes ().size ());
nano::lock_guard<std::mutex> lock (node1.active.mutex);
ASSERT_EQ (1, election1.election->last_votes.size ());
}
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send1)); auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send1));
vote1->signature.bytes[0] ^= 1; 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))); 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 ()); auto transaction (node1.store.tx_begin_write ());
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code); ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code);
auto election1 = node1.active.insert (send1); auto election1 = node1.active.insert (send1);
nano::unique_lock<std::mutex> lock (node1.active.mutex); ASSERT_EQ (1, election1.election->votes ().size ());
ASSERT_EQ (1, election1.election->last_votes.size ());
lock.unlock ();
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send1)); auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send1));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1)); 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)); 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)); ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2));
lock.lock (); ASSERT_EQ (2, election1.election->votes ().size ());
ASSERT_EQ (2, election1.election->last_votes.size ()); auto votes1 (election1.election->votes ());
auto existing1 (election1.election->last_votes.find (nano::dev_genesis_key.pub)); auto existing1 (votes1.find (nano::dev_genesis_key.pub));
ASSERT_NE (election1.election->last_votes.end (), existing1); ASSERT_NE (votes1.end (), existing1);
ASSERT_EQ (send1->hash (), existing1->second.hash); ASSERT_EQ (send1->hash (), existing1->second.hash);
nano::lock_guard<std::mutex> guard (node1.active.mutex);
auto winner (*election1.election->tally ().begin ()); auto winner (*election1.election->tally ().begin ());
ASSERT_EQ (*send1, *winner.second); ASSERT_EQ (*send1, *winner.second);
ASSERT_EQ (nano::genesis_amount - 100, winner.first); ASSERT_EQ (nano::genesis_amount - 100, winner.first);
@ -818,24 +814,23 @@ TEST (votes, add_two)
auto transaction (node1.store.tx_begin_write ()); auto transaction (node1.store.tx_begin_write ());
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code); ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code);
auto election1 = node1.active.insert (send1); auto election1 = node1.active.insert (send1);
nano::unique_lock<std::mutex> lock (node1.active.mutex);
lock.unlock ();
nano::keypair key2; 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 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)); auto vote2 (std::make_shared<nano::vote> (key2.pub, key2.prv, 1, send2));
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2)); 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)); 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)); ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
lock.lock (); ASSERT_EQ (3, election1.election->votes ().size ());
ASSERT_EQ (3, election1.election->last_votes.size ()); auto votes1 (election1.election->votes ());
ASSERT_NE (election1.election->last_votes.end (), election1.election->last_votes.find (nano::dev_genesis_key.pub)); ASSERT_NE (votes1.end (), votes1.find (nano::dev_genesis_key.pub));
ASSERT_EQ (send1->hash (), election1.election->last_votes[nano::dev_genesis_key.pub].hash); ASSERT_EQ (send1->hash (), votes1[nano::dev_genesis_key.pub].hash);
ASSERT_NE (election1.election->last_votes.end (), election1.election->last_votes.find (key2.pub)); ASSERT_NE (votes1.end (), votes1.find (key2.pub));
ASSERT_EQ (send2->hash (), election1.election->last_votes[key2.pub].hash); ASSERT_EQ (send2->hash (), votes1[key2.pub].hash);
auto winner (*election1.election->tally ().begin ()); ASSERT_EQ (*send1, *election1.election->winner ());
ASSERT_EQ (*send1, *winner.second);
} }
namespace nano
{
// Higher sequence numbers change the vote // Higher sequence numbers change the vote
TEST (votes, add_existing) TEST (votes, add_existing)
{ {
@ -857,33 +852,30 @@ TEST (votes, add_existing)
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1)); ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
// Block is already processed from vote // Block is already processed from vote
ASSERT_TRUE (node1.active.publish (send1)); ASSERT_TRUE (node1.active.publish (send1));
nano::unique_lock<std::mutex> lock (node1.active.mutex); ASSERT_EQ (1, election1.election->votes ()[nano::dev_genesis_key.pub].sequence);
ASSERT_EQ (1, election1.election->last_votes[nano::dev_genesis_key.pub].sequence);
nano::keypair key2; 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)); 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); node1.work_generate_blocking (*send2);
auto vote2 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 2, 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 // 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); election1.election->last_votes[nano::dev_genesis_key.pub].time = std::chrono::steady_clock::now () - std::chrono::seconds (20);
lock.unlock (); lock.unlock ();
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2)); ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2));
ASSERT_FALSE (node1.active.publish (send2)); ASSERT_FALSE (node1.active.publish (send2));
lock.lock (); ASSERT_EQ (2, election1.election->votes ()[nano::dev_genesis_key.pub].sequence);
ASSERT_EQ (2, election1.election->last_votes[nano::dev_genesis_key.pub].sequence);
// Also resend the old vote, and see if we respect the sequence number // 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); election1.election->last_votes[nano::dev_genesis_key.pub].time = std::chrono::steady_clock::now () - std::chrono::seconds (20);
lock.unlock (); lock.unlock ();
ASSERT_EQ (nano::vote_code::replay, node1.active.vote (vote1)); 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 (); lock.lock ();
ASSERT_EQ (2, election1.election->last_votes[nano::dev_genesis_key.pub].sequence); ASSERT_EQ (*send2, *election1.election->tally ().begin ()->second);
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);
}
} }
// Lower sequence numbers are ignored // 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); 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); node1.vote_processor.vote_blocking (vote2, channel);
ASSERT_EQ (2, election1.election->last_votes_size ()); ASSERT_EQ (2, election1.election->votes ().size ());
nano::lock_guard<std::mutex> lock (node1.active.mutex); auto votes (election1.election->votes ());
ASSERT_NE (election1.election->last_votes.end (), election1.election->last_votes.find (nano::dev_genesis_key.pub)); ASSERT_NE (votes.end (), votes.find (nano::dev_genesis_key.pub));
ASSERT_EQ (send1->hash (), election1.election->last_votes[nano::dev_genesis_key.pub].hash); ASSERT_EQ (send1->hash (), votes[nano::dev_genesis_key.pub].hash);
auto winner (*election1.election->tally ().begin ()); ASSERT_EQ (*send1, *election1.election->winner ());
ASSERT_EQ (*send1, *winner.second); }
} }
// Lower sequence numbers are accepted for different accounts // Lower sequence numbers are accepted for different accounts
@ -936,28 +928,27 @@ TEST (votes, add_old_different_account)
ASSERT_NE (nullptr, election1); ASSERT_NE (nullptr, election1);
auto election2 = node1.active.election (send2->qualified_root ()); auto election2 = node1.active.election (send2->qualified_root ());
ASSERT_NE (nullptr, election2); ASSERT_NE (nullptr, election2);
ASSERT_EQ (1, election1->last_votes_size ()); ASSERT_EQ (1, election1->votes ().size ());
ASSERT_EQ (1, election2->last_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 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 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)); auto vote_result1 (node1.vote_processor.vote_blocking (vote1, channel));
ASSERT_EQ (nano::vote_code::vote, vote_result1); ASSERT_EQ (nano::vote_code::vote, vote_result1);
ASSERT_EQ (2, election1->last_votes_size ()); ASSERT_EQ (2, election1->votes ().size ());
ASSERT_EQ (1, election2->last_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 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)); auto vote_result2 (node1.vote_processor.vote_blocking (vote2, channel));
ASSERT_EQ (nano::vote_code::vote, vote_result2); ASSERT_EQ (nano::vote_code::vote, vote_result2);
ASSERT_EQ (2, election1->last_votes_size ()); ASSERT_EQ (2, election1->votes ().size ());
ASSERT_EQ (2, election2->last_votes_size ()); ASSERT_EQ (2, election2->votes ().size ());
nano::unique_lock<std::mutex> lock (node1.active.mutex); auto votes1 (election1->votes ());
ASSERT_NE (election1->last_votes.end (), election1->last_votes.find (nano::dev_genesis_key.pub)); auto votes2 (election2->votes ());
ASSERT_NE (election2->last_votes.end (), election2->last_votes.find (nano::dev_genesis_key.pub)); ASSERT_NE (votes1.end (), votes1.find (nano::dev_genesis_key.pub));
ASSERT_EQ (send1->hash (), election1->last_votes[nano::dev_genesis_key.pub].hash); ASSERT_NE (votes2.end (), votes2.find (nano::dev_genesis_key.pub));
ASSERT_EQ (send2->hash (), election2->last_votes[nano::dev_genesis_key.pub].hash); ASSERT_EQ (send1->hash (), votes1[nano::dev_genesis_key.pub].hash);
auto winner1 (*election1->tally ().begin ()); ASSERT_EQ (send2->hash (), votes2[nano::dev_genesis_key.pub].hash);
ASSERT_EQ (*send1, *winner1.second); ASSERT_EQ (*send1, *election1->winner ());
auto winner2 (*election2->tally ().begin ()); ASSERT_EQ (*send2, *election2->winner ());
ASSERT_EQ (*send2, *winner2.second);
} }
// The voting cooldown is respected // The voting cooldown is respected
@ -980,12 +971,11 @@ TEST (votes, add_cooldown)
node1.work_generate_blocking (*send2); node1.work_generate_blocking (*send2);
auto vote2 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 2, 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); node1.vote_processor.vote_blocking (vote2, channel);
nano::unique_lock<std::mutex> lock (node1.active.mutex); ASSERT_EQ (2, election1.election->votes ().size ());
ASSERT_EQ (2, election1.election->last_votes.size ()); auto votes (election1.election->votes ());
ASSERT_NE (election1.election->last_votes.end (), election1.election->last_votes.find (nano::dev_genesis_key.pub)); ASSERT_NE (votes.end (), votes.find (nano::dev_genesis_key.pub));
ASSERT_EQ (send1->hash (), election1.election->last_votes[nano::dev_genesis_key.pub].hash); ASSERT_EQ (send1->hash (), votes[nano::dev_genesis_key.pub].hash);
auto winner (*election1.election->tally ().begin ()); ASSERT_EQ (*send1, *election1.election->winner ());
ASSERT_EQ (*send1, *winner.second);
} }
// Query for block successor // Query for block successor
@ -2718,15 +2708,14 @@ TEST (ledger, block_hash_account_conflict)
ASSERT_NE (nullptr, election3); ASSERT_NE (nullptr, election3);
auto election4 = node1.active.election (open_epoch1->qualified_root ()); auto election4 = node1.active.election (open_epoch1->qualified_root ());
ASSERT_NE (nullptr, election4); ASSERT_NE (nullptr, election4);
nano::lock_guard<std::mutex> lock (node1.active.mutex); auto winner1 (election1->winner ());
auto winner1 (*election1->tally ().begin ()); auto winner2 (election2->winner ());
auto winner2 (*election2->tally ().begin ()); auto winner3 (election3->winner ());
auto winner3 (*election3->tally ().begin ()); auto winner4 (election4->winner ());
auto winner4 (*election4->tally ().begin ()); ASSERT_EQ (*send1, *winner1);
ASSERT_EQ (*send1, *winner1.second); ASSERT_EQ (*receive1, *winner2);
ASSERT_EQ (*receive1, *winner2.second); ASSERT_EQ (*send2, *winner3);
ASSERT_EQ (*send2, *winner3.second); ASSERT_EQ (*open_epoch1, *winner4);
ASSERT_EQ (*open_epoch1, *winner4.second);
} }
TEST (ledger, could_fit) TEST (ledger, could_fit)

View file

@ -256,13 +256,10 @@ TEST (node, node_receive_quorum)
.build_shared (); .build_shared ();
node1.process_active (send); node1.process_active (send);
ASSERT_TIMELY (10s, node1.ledger.block_exists (send->hash ())); ASSERT_TIMELY (10s, node1.ledger.block_exists (send->hash ()));
{ auto election (node1.active.election (nano::qualified_root (previous, previous)));
nano::lock_guard<std::mutex> guard (node1.active.mutex); ASSERT_NE (nullptr, election);
auto info (node1.active.roots.find (nano::qualified_root (previous, previous))); ASSERT_FALSE (election->confirmed ());
ASSERT_NE (node1.active.roots.end (), info); ASSERT_EQ (1, election->votes ().size ());
ASSERT_FALSE (info->election->confirmed ());
ASSERT_EQ (1, info->election->last_votes.size ());
}
nano::system system2; nano::system system2;
system2.add_node (node_flags); system2.add_node (node_flags);
@ -1023,25 +1020,17 @@ TEST (node, fork_publish)
node1.process_active (send1); node1.process_active (send1);
node1.block_processor.flush (); node1.block_processor.flush ();
ASSERT_EQ (1, node1.active.size ()); ASSERT_EQ (1, node1.active.size ());
nano::unique_lock<std::mutex> lock (node1.active.mutex); auto election (node1.active.election (send1->qualified_root ()));
auto existing (node1.active.roots.find (send1->qualified_root ())); ASSERT_NE (nullptr, election);
ASSERT_NE (node1.active.roots.end (), existing);
auto election (existing->election);
lock.unlock ();
system.deadline_set (1s);
// Wait until the genesis rep activated & makes vote // Wait until the genesis rep activated & makes vote
while (election->last_votes_size () != 2) ASSERT_TIMELY (1s, election->votes ().size () == 2);
{
node1.vote_processor.flush ();
ASSERT_NO_ERROR (system.poll ());
}
node1.process_active (send2); node1.process_active (send2);
node1.block_processor.flush (); node1.block_processor.flush ();
lock.lock (); auto votes1 (election->votes ());
auto existing1 (election->last_votes.find (nano::dev_genesis_key.pub)); auto existing1 (votes1.find (nano::dev_genesis_key.pub));
ASSERT_NE (election->last_votes.end (), existing1); ASSERT_NE (votes1.end (), existing1);
ASSERT_EQ (send1->hash (), existing1->second.hash); 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 ()); auto winner (*election->tally ().begin ());
ASSERT_EQ (*send1, *winner.second); ASSERT_EQ (*send1, *winner.second);
ASSERT_EQ (nano::genesis_amount - 100, winner.first); 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); ASSERT_EQ (nano::process_result::fork, node.process_local (send2).code);
auto election (node.active.election (send1->qualified_root ())); auto election (node.active.election (send1->qualified_root ()));
ASSERT_NE (election, nullptr); ASSERT_NE (election, nullptr);
{ auto blocks (election->blocks ());
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 (send1->hash ()));
ASSERT_NE (blocks.end (), blocks.find (send2->hash ())); ASSERT_NE (blocks.end (), blocks.find (send2->hash ()));
ASSERT_NE (election->status.winner, send1); ASSERT_NE (election->winner (), send1);
ASSERT_NE (election->status.winner, send2); ASSERT_NE (election->winner (), send2);
}
} }
TEST (node, fork_keep) TEST (node, fork_keep)
@ -1122,26 +1108,18 @@ TEST (node, fork_keep)
node1.block_processor.flush (); node1.block_processor.flush ();
node2.process_active (send2); node2.process_active (send2);
node2.block_processor.flush (); node2.block_processor.flush ();
nano::unique_lock<std::mutex> lock (node2.active.mutex); auto election1 (node2.active.election (nano::qualified_root (genesis.hash (), genesis.hash ())));
auto conflict (node2.active.roots.find (nano::qualified_root (genesis.hash (), genesis.hash ()))); ASSERT_NE (nullptr, election1);
ASSERT_NE (node2.active.roots.end (), conflict); ASSERT_EQ (1, election1->votes ().size ());
auto votes1 (conflict->election); ASSERT_TRUE (node1.ledger.block_exists (send1->hash ()));
ASSERT_NE (nullptr, votes1); ASSERT_TRUE (node2.ledger.block_exists (send1->hash ()));
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 ()));
}
// Wait until the genesis rep makes a vote // 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 transaction0 (node1.store.tx_begin_read ());
auto transaction1 (node2.store.tx_begin_read ()); auto transaction1 (node2.store.tx_begin_read ());
// The vote should be in agreement with what we already have. // The vote should be in agreement with what we already have.
lock.lock (); nano::lock_guard<std::mutex> guard (node2.active.mutex);
auto winner (*votes1->tally ().begin ()); auto winner (*election1->tally ().begin ());
ASSERT_EQ (*send1, *winner.second); ASSERT_EQ (*send1, *winner.second);
ASSERT_EQ (nano::genesis_amount - 100, winner.first); ASSERT_EQ (nano::genesis_amount - 100, winner.first);
ASSERT_TRUE (node1.store.block_exists (transaction0, send1->hash ())); ASSERT_TRUE (node1.store.block_exists (transaction0, send1->hash ()));
@ -1187,37 +1165,19 @@ TEST (node, fork_flip)
node1.block_processor.flush (); node1.block_processor.flush ();
node2.network.process_message (publish1, channel2); node2.network.process_message (publish1, channel2);
node2.block_processor.flush (); 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); nano::unique_lock<std::mutex> lock (node2.active.mutex);
auto conflict (node2.active.roots.find (nano::qualified_root (genesis.hash (), genesis.hash ()))); auto winner (*election1->tally ().begin ());
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 ());
ASSERT_EQ (*publish1.block, *winner.second); ASSERT_EQ (*publish1.block, *winner.second);
ASSERT_EQ (nano::genesis_amount - 100, winner.first); ASSERT_EQ (nano::genesis_amount - 100, winner.first);
ASSERT_TRUE (node1.store.block_exists (transaction1, publish1.block->hash ())); ASSERT_TRUE (node1.ledger.block_exists (publish1.block->hash ()));
ASSERT_TRUE (node2.store.block_exists (transaction2, publish1.block->hash ())); ASSERT_TRUE (node2.ledger.block_exists (publish1.block->hash ()));
ASSERT_FALSE (node2.store.block_exists (transaction2, publish2.block->hash ())); ASSERT_FALSE (node2.ledger.block_exists (publish2.block->hash ()));
} }
TEST (node, fork_multi_flip) TEST (node, fork_multi_flip)
@ -1280,39 +1240,21 @@ TEST (node, fork_multi_flip)
node1.block_processor.flush (); node1.block_processor.flush ();
node2.network.process_message (publish1, node2.network.udp_channels.create (node2.network.endpoint ())); node2.network.process_message (publish1, node2.network.udp_channels.create (node2.network.endpoint ()));
node2.block_processor.flush (); 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); nano::unique_lock<std::mutex> lock (node2.active.mutex);
auto conflict (node2.active.roots.find (nano::qualified_root (genesis.hash (), genesis.hash ()))); auto winner (*election1->tally ().begin ());
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 ());
ASSERT_EQ (*publish1.block, *winner.second); ASSERT_EQ (*publish1.block, *winner.second);
ASSERT_EQ (nano::genesis_amount - 100, winner.first); ASSERT_EQ (nano::genesis_amount - 100, winner.first);
ASSERT_TRUE (node1.store.block_exists (transaction1, publish1.block->hash ())); ASSERT_TRUE (node1.ledger.block_exists (publish1.block->hash ()));
ASSERT_TRUE (node2.store.block_exists (transaction2, publish1.block->hash ())); ASSERT_TRUE (node2.ledger.block_exists (publish1.block->hash ()));
ASSERT_FALSE (node2.store.block_exists (transaction2, publish2.block->hash ())); ASSERT_FALSE (node2.ledger.block_exists (publish2.block->hash ()));
ASSERT_FALSE (node2.store.block_exists (transaction2, publish3.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 ())); auto channel1 (node1.network.udp_channels.create (node1.network.endpoint ()));
node1.network.process_message (publish1, channel1); node1.network.process_message (publish1, channel1);
node1.block_processor.flush (); node1.block_processor.flush ();
{
auto election = node1.active.election (publish1.block->qualified_root ()); auto election = node1.active.election (publish1.block->qualified_root ());
nano::lock_guard<std::mutex> guard (node1.active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (3s, node1.active.empty () && node1.block_confirmed (publish1.block->hash ())); ASSERT_TIMELY (3s, node1.active.empty () && node1.block_confirmed (publish1.block->hash ()));
nano::open_block_builder builder; nano::open_block_builder builder;
auto open1 = builder.make_block () auto open1 = builder.make_block ()
@ -1426,13 +1365,10 @@ TEST (node, fork_open)
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv); system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
node1.network.process_message (publish3, channel1); node1.network.process_message (publish3, channel1);
node1.block_processor.flush (); node1.block_processor.flush ();
{ election = node1.active.election (publish3.block->qualified_root ());
auto election = node1.active.election (publish3.block->qualified_root ()); ASSERT_EQ (2, election->blocks ().size ());
nano::lock_guard<std::mutex> guard (node1.active.mutex); ASSERT_EQ (publish2.block->hash (), election->winner ()->hash ());
ASSERT_EQ (2, election->blocks.size ());
ASSERT_EQ (publish2.block->hash (), election->status.winner->hash ());
ASSERT_FALSE (election->confirmed ()); ASSERT_FALSE (election->confirmed ());
}
ASSERT_TRUE (node1.block (publish2.block->hash ())); ASSERT_TRUE (node1.block (publish2.block->hash ()));
ASSERT_FALSE (node1.block (publish3.block->hash ())); ASSERT_FALSE (node1.block (publish3.block->hash ()));
} }
@ -1492,13 +1428,9 @@ TEST (node, fork_open_flip)
node1.block_processor.flush (); node1.block_processor.flush ();
node2.process_active (open1); node2.process_active (open1);
node2.block_processor.flush (); node2.block_processor.flush ();
nano::unique_lock<std::mutex> lock (node2.active.mutex); auto election1 (node2.active.election (open1->qualified_root ()));
auto conflict (node2.active.roots.find (open1->qualified_root ())); ASSERT_NE (nullptr, election1);
ASSERT_NE (node2.active.roots.end (), conflict); ASSERT_EQ (1, election1->votes ().size ());
auto votes1 (conflict->election);
ASSERT_NE (nullptr, votes1);
ASSERT_EQ (1, votes1->last_votes.size ());
lock.unlock ();
ASSERT_TRUE (node1.block (open1->hash ()) != nullptr); ASSERT_TRUE (node1.block (open1->hash ()) != nullptr);
ASSERT_TRUE (node2.block (open2->hash ()) != nullptr); ASSERT_TRUE (node2.block (open2->hash ()) != nullptr);
// Node2 should eventually settle on open1 // Node2 should eventually settle on open1
@ -1506,8 +1438,8 @@ TEST (node, fork_open_flip)
node2.block_processor.flush (); node2.block_processor.flush ();
auto transaction1 (node1.store.tx_begin_read ()); auto transaction1 (node1.store.tx_begin_read ());
auto transaction2 (node2.store.tx_begin_read ()); auto transaction2 (node2.store.tx_begin_read ());
lock.lock (); nano::lock_guard<std::mutex> guard (node1.active.mutex);
auto winner (*votes1->tally ().begin ()); auto winner (*election1->tally ().begin ());
ASSERT_EQ (*open1, *winner.second); ASSERT_EQ (*open1, *winner.second);
ASSERT_EQ (nano::genesis_amount - 1, winner.first); ASSERT_EQ (nano::genesis_amount - 1, winner.first);
ASSERT_TRUE (node1.store.block_exists (transaction1, open1->hash ())); ASSERT_TRUE (node1.store.block_exists (transaction1, open1->hash ()));
@ -1810,10 +1742,7 @@ TEST (node, broadcast_elected)
node->block_confirm (block); node->block_confirm (block);
auto election (node->active.election (block->qualified_root ())); auto election (node->active.election (block->qualified_root ()));
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
{ election->force_confirm ();
nano::lock_guard<std::mutex> guard (node->active.mutex);
election->confirm_once ();
}
ASSERT_TIMELY (5s, 4 == node->ledger.cache.cemented_count) 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); ASSERT_EQ (nano::process_result::progress, node0->process (open_big).code);
// Confirm both blocks, allowing voting on the upcoming block // Confirm both blocks, allowing voting on the upcoming block
node0->block_confirm (node0->block (open_big.hash ())); node0->block_confirm (node0->block (open_big.hash ()));
{
auto election = node0->active.election (open_big.qualified_root ()); auto election = node0->active.election (open_big.qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node0->active.mutex); election->force_confirm ();
election->confirm_once ();
}
system.wallet (0)->insert_adhoc (rep_big.prv); system.wallet (0)->insert_adhoc (rep_big.prv);
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.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 & active (node0->active);
auto election1 = active.insert (block0); auto election1 = active.insert (block0);
// Wait until representatives are activated & make vote // Wait until representatives are activated & make vote
ASSERT_TIMELY (1s, election1.election->last_votes_size () == 3); ASSERT_TIMELY (1s, election1.election->votes ().size () == 3);
nano::unique_lock<std::mutex> lock (active.mutex); auto rep_votes (election1.election->votes ());
auto & rep_votes (election1.election->last_votes);
ASSERT_NE (rep_votes.end (), rep_votes.find (nano::dev_genesis_key.pub)); ASSERT_NE (rep_votes.end (), rep_votes.find (nano::dev_genesis_key.pub));
ASSERT_NE (rep_votes.end (), rep_votes.find (rep_big.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) for (auto node : system.nodes)
{ {
node->block_confirm (node->block (node->latest (nano::dev_genesis_key.pub))); node->block_confirm (node->block (node->latest (nano::dev_genesis_key.pub)));
{
auto election = node->active.election (send0.qualified_root ()); auto election = node->active.election (send0.qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (2s, node->active.empty ()); ASSERT_TIMELY (2s, node->active.empty ());
} }
ASSERT_TIMELY (3s, node0->block_confirmed (send0.hash ())); 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 ())); ASSERT_TRUE (node2.ledger.block_exists (send1_copy->hash ()));
// Confirm send1 on node2 so it can vote for send2 // Confirm send1 on node2 so it can vote for send2
node2.block_confirm (send1_copy); node2.block_confirm (send1_copy);
{
auto election = node2.active.election (send1_copy->qualified_root ()); auto election = node2.active.election (send1_copy->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node2.active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (3s, node2.block_confirmed (send1_copy->hash ()) && node2.active.empty ()); ASSERT_TIMELY (3s, node2.block_confirmed (send1_copy->hash ()) && node2.active.empty ());
system.wallet (1)->insert_adhoc (nano::dev_genesis_key.prv); 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 ()))); 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); 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 ()); system.wallet (0)->send_action (nano::dev_genesis_key.pub, nano::dev_genesis_key.pub, new_balance.number ());
ASSERT_TIMELY (10s, !node1.active.empty ()); ASSERT_TIMELY (10s, !node1.active.empty ());
nano::lock_guard<std::mutex> guard (node1.active.mutex); auto election (node1.active.election (nano::qualified_root (send1->hash (), send1->hash ())));
auto info (node1.active.roots.find (nano::qualified_root (send1->hash (), send1->hash ()))); ASSERT_NE (nullptr, election);
ASSERT_NE (node1.active.roots.end (), info); ASSERT_FALSE (election->confirmed ());
ASSERT_FALSE (info->election->confirmed ()); ASSERT_EQ (1, election->votes ().size ());
ASSERT_EQ (1, info->election->last_votes.size ());
ASSERT_EQ (0, node1.balance (nano::dev_genesis_key.pub)); ASSERT_EQ (0, node1.balance (nano::dev_genesis_key.pub));
} }
@ -2682,12 +2600,9 @@ TEST (node, local_votes_cache)
} }
// Confirm blocks to allow voting // Confirm blocks to allow voting
node.block_confirm (send2); node.block_confirm (send2);
{
auto election = node.active.election (send2->qualified_root ()); auto election = node.active.election (send2->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node.active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (3s, node.ledger.cache.cemented_count == 3); ASSERT_TIMELY (3s, node.ledger.cache.cemented_count == 3);
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv); system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
nano::confirm_req message1 (send1); nano::confirm_req message1 (send1);
@ -3066,12 +2981,9 @@ TEST (node, epoch_conflict_confirm)
ASSERT_EQ (nano::process_result::progress, node1->process (*open).code); ASSERT_EQ (nano::process_result::progress, node1->process (*open).code);
// Confirm block in node1 to allow generating votes // Confirm block in node1 to allow generating votes
node1->block_confirm (open); node1->block_confirm (open);
{
auto election (node1->active.election (open->qualified_root ())); auto election (node1->active.election (open->qualified_root ()));
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node1->active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (3s, node1->block_confirmed (open->hash ())); ASSERT_TIMELY (3s, node1->block_confirmed (open->hash ()));
{ {
nano::block_post_events events; nano::block_post_events events;
@ -3181,31 +3093,14 @@ TEST (node, fork_election_invalid_block_signature)
.build_shared (); .build_shared ();
auto channel1 (node1.network.udp_channels.create (node1.network.endpoint ())); auto channel1 (node1.network.udp_channels.create (node1.network.endpoint ()));
node1.network.process_message (nano::publish (send1), channel1); node1.network.process_message (nano::publish (send1), channel1);
system.deadline_set (5s); ASSERT_TIMELY (5s, node1.active.active (send1->qualified_root ()));
std::shared_ptr<nano::election> election; auto election (node1.active.election (send1->qualified_root ()));
while (election == nullptr) ASSERT_NE (nullptr, election);
{ ASSERT_EQ (1, election->blocks ().size ());
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 ();
node1.network.process_message (nano::publish (send3), channel1); node1.network.process_message (nano::publish (send3), channel1);
node1.network.process_message (nano::publish (send2), channel1); node1.network.process_message (nano::publish (send2), channel1);
lock.lock (); ASSERT_TIMELY (3s, election->blocks ().size () > 1);
while (election->blocks.size () == 1) ASSERT_EQ (election->blocks ()[send2->hash ()]->block_signature (), send2->block_signature ());
{
lock.unlock ();
ASSERT_NO_ERROR (system.poll ());
lock.lock ();
}
ASSERT_EQ (election->blocks[send2->hash ()]->block_signature (), send2->block_signature ());
} }
TEST (node, block_processor_signatures) TEST (node, block_processor_signatures)
@ -3977,33 +3872,31 @@ TEST (node, rollback_vote_self)
ASSERT_EQ (nano::process_result::progress, node.process (*open).code); ASSERT_EQ (nano::process_result::progress, node.process (*open).code);
// Confirm blocks to allow voting // Confirm blocks to allow voting
node.block_confirm (open); node.block_confirm (open);
{
auto election = node.active.election (open->qualified_root ()); auto election = node.active.election (open->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node.active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (5s, node.ledger.cache.cemented_count == 3); ASSERT_TIMELY (5s, node.ledger.cache.cemented_count == 3);
ASSERT_EQ (weight, node.weight (key.pub)); ASSERT_EQ (weight, node.weight (key.pub));
node.process_active (send2); node.process_active (send2);
node.process_active (fork); node.process_active (fork);
node.block_processor.flush (); node.block_processor.flush ();
auto election = node.active.election (send2->qualified_root ()); election = node.active.election (send2->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
ASSERT_EQ (2, election->blocks.size ()); ASSERT_EQ (2, election->blocks ().size ());
// Insert genesis key in the wallet // Insert genesis key in the wallet
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv); system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
{ {
// The write guard prevents the block processor from performing the rollback // The write guard prevents the block processor from performing the rollback
auto write_guard = node.write_database_queue.wait (nano::writer::testing); auto write_guard = node.write_database_queue.wait (nano::writer::testing);
{ {
nano::lock_guard<std::mutex> guard (node.active.mutex); ASSERT_EQ (1, election->votes ().size ());
ASSERT_EQ (1, election->last_votes.size ()); nano::unique_lock<std::mutex> lock (node.active.mutex);
// Vote with key to switch the winner // Vote with key to switch the winner
election->vote (key.pub, 0, fork->hash ()); 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 // 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 // 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 ()); 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 // Going out of the scope allows the rollback to complete
} }
// A vote is eventually generated from the local representative // A vote is eventually generated from the local representative
ASSERT_TIMELY (5s, 3 == election->last_votes_size ()); ASSERT_TIMELY (5s, 3 == election->votes ().size ());
auto vote (election->last_votes.find (nano::dev_genesis_key.pub)); auto votes (election->votes ());
ASSERT_NE (election->last_votes.end (), vote); auto vote (votes.find (nano::dev_genesis_key.pub));
ASSERT_NE (votes.end (), vote);
ASSERT_EQ (fork->hash (), vote->second.hash); ASSERT_EQ (fork->hash (), vote->second.hash);
} }
@ -4488,10 +4382,7 @@ TEST (node, deferred_dependent_elections)
ASSERT_FALSE (node.active.active (send2->qualified_root ())); ASSERT_FALSE (node.active.active (send2->qualified_root ()));
// Confirming send1 will automatically start elections for the dependents // Confirming send1 will automatically start elections for the dependents
{ election_send1->force_confirm ();
nano::lock_guard<std::mutex> guard (node.active.mutex);
election_send1->confirm_once ();
}
ASSERT_TIMELY (2s, node.block_confirmed (send1->hash ())); ASSERT_TIMELY (2s, node.block_confirmed (send1->hash ()));
ASSERT_TIMELY (2s, node.active.active (open->qualified_root ()) && node.active.active (send2->qualified_root ())); ASSERT_TIMELY (2s, node.active.active (open->qualified_root ()) && node.active.active (send2->qualified_root ()));
auto election_open = node.active.election (open->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 // 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_EQ (nano::process_result::progress, node.process (*receive).code);
ASSERT_FALSE (node.active.active (receive->qualified_root ())); ASSERT_FALSE (node.active.active (receive->qualified_root ()));
{ election_open->force_confirm ();
nano::lock_guard<std::mutex> guard (node.active.mutex);
election_open->confirm_once ();
}
ASSERT_TIMELY (2s, node.block_confirmed (open->hash ())); ASSERT_TIMELY (2s, node.block_confirmed (open->hash ()));
ASSERT_FALSE (node.ledger.dependents_confirmed (node.store.tx_begin_read (), *receive)); ASSERT_FALSE (node.ledger.dependents_confirmed (node.store.tx_begin_read (), *receive));
std::this_thread::sleep_for (500ms); std::this_thread::sleep_for (500ms);
@ -4524,10 +4412,7 @@ TEST (node, deferred_dependent_elections)
ASSERT_FALSE (node.active.active (receive->qualified_root ())); ASSERT_FALSE (node.active.active (receive->qualified_root ()));
// Confirming the other dependency allows starting an election from a fork // Confirming the other dependency allows starting an election from a fork
{ election_send2->force_confirm ();
nano::lock_guard<std::mutex> guard (node.active.mutex);
election_send2->confirm_once ();
}
ASSERT_TIMELY (2s, node.block_confirmed (send2->hash ())); ASSERT_TIMELY (2s, node.block_confirmed (send2->hash ()));
ASSERT_TIMELY (2s, node.active.active (receive->qualified_root ())); ASSERT_TIMELY (2s, node.active.active (receive->qualified_root ()));
node.active.erase (*receive); node.active.erase (*receive);

View file

@ -185,12 +185,9 @@ TEST (request_aggregator, split)
} }
// Confirm all blocks // Confirm all blocks
node.block_confirm (blocks.back ()); node.block_confirm (blocks.back ());
{
auto election (node.active.election (blocks.back ()->qualified_root ())); auto election (node.active.election (blocks.back ()->qualified_root ()));
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node.active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (5s, max_vbh + 2 == node.ledger.cache.cemented_count); ASSERT_TIMELY (5s, max_vbh + 2 == node.ledger.cache.cemented_count);
ASSERT_EQ (max_vbh + 1, request.size ()); ASSERT_EQ (max_vbh + 1, request.size ());
auto channel (node.network.udp_channels.create (node.network.endpoint ())); auto channel (node.network.udp_channels.create (node.network.endpoint ()));
@ -364,12 +361,9 @@ TEST (request_aggregator, cannot_vote)
// Confirm send1 // Confirm send1
node.block_confirm (send1); node.block_confirm (send1);
{
auto election (node.active.election (send1->qualified_root ())); auto election (node.active.election (send1->qualified_root ()));
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node.active.mutex); election->force_confirm ();
election->confirm_once ();
}
ASSERT_TIMELY (3s, node.ledger.dependents_confirmed (node.store.tx_begin_read (), *send2)); ASSERT_TIMELY (3s, node.ledger.dependents_confirmed (node.store.tx_begin_read (), *send2));
node.aggregator.add (channel, request); node.aggregator.add (channel, request);
ASSERT_EQ (1, node.aggregator.size ()); ASSERT_EQ (1, node.aggregator.size ());

View file

@ -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)); 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)); auto election (node.active.insert (genesis.open));
ASSERT_TRUE (election.election && election.inserted); 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.vote (vote_invalid, channel);
node.vote_processor.flush (); 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.vote (vote, channel);
node.vote_processor.flush (); node.vote_processor.flush ();
ASSERT_EQ (2, election.election->last_votes.size ()); ASSERT_EQ (2, election.election->votes ().size ());
} }
TEST (vote_processor, no_capacity) TEST (vote_processor, no_capacity)
@ -213,8 +213,9 @@ TEST (vote_processor, no_broadcast_local)
// Make sure the vote was processed // Make sure the vote was processed
auto election (node.active.election (send->qualified_root ())); auto election (node.active.election (send->qualified_root ()));
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
auto existing (election->last_votes.find (nano::dev_genesis_key.pub)); auto votes (election->votes ());
ASSERT_NE (election->last_votes.end (), existing); auto existing (votes.find (nano::dev_genesis_key.pub));
ASSERT_NE (votes.end (), existing);
ASSERT_EQ (vote->sequence, existing->second.sequence); 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 // 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)); 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 // Make sure the vote was processed
auto election2 (node.active.election (send2->qualified_root ())); auto election2 (node.active.election (send2->qualified_root ()));
ASSERT_NE (nullptr, election2); ASSERT_NE (nullptr, election2);
auto existing2 (election2->last_votes.find (nano::dev_genesis_key.pub)); auto votes2 (election2->votes ());
ASSERT_NE (election2->last_votes.end (), existing2); auto existing2 (votes2.find (nano::dev_genesis_key.pub));
ASSERT_NE (votes2.end (), existing2);
ASSERT_EQ (vote2->sequence, existing2->second.sequence); ASSERT_EQ (vote2->sequence, existing2->second.sequence);
// Ensure the vote was broadcast // Ensure the vote was broadcast
ASSERT_EQ (1, node.stats.count (nano::stat::type::message, nano::stat::detail::confirm_ack, nano::stat::dir::out)); 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 // Make sure the vote was processed
auto election3 (node.active.election (open->qualified_root ())); auto election3 (node.active.election (open->qualified_root ()));
ASSERT_NE (nullptr, election3); ASSERT_NE (nullptr, election3);
auto existing3 (election3->last_votes.find (nano::dev_genesis_key.pub)); auto votes3 (election3->votes ());
ASSERT_NE (election3->last_votes.end (), existing3); auto existing3 (votes3.find (nano::dev_genesis_key.pub));
ASSERT_NE (votes3.end (), existing3);
ASSERT_EQ (vote3->sequence, existing3->second.sequence); ASSERT_EQ (vote3->sequence, existing3->second.sequence);
// Ensure the vote wass not broadcasst // 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)); ASSERT_EQ (1, node.stats.count (nano::stat::type::message, nano::stat::detail::confirm_ack, nano::stat::dir::out));

View file

@ -1251,11 +1251,10 @@ TEST (work_watcher, confirm_while_generating)
notified = true; notified = true;
}); });
// Confirm the block // Confirm the block
{ ASSERT_EQ (1, node.active.size ());
nano::lock_guard<std::mutex> guard (node.active.mutex); auto election (node.active.election (block1->qualified_root ()));
ASSERT_EQ (1, node.active.roots.size ()); ASSERT_NE (nullptr, election);
node.active.roots.begin ()->election->confirm_once (); election->force_confirm ();
}
ASSERT_TIMELY (5s, node.block_confirmed (block1->hash ())); ASSERT_TIMELY (5s, node.block_confirmed (block1->hash ()));
ASSERT_EQ (0, node.work.size ()); ASSERT_EQ (0, node.work.size ());
ASSERT_TRUE (notified); ASSERT_TRUE (notified);
@ -1485,10 +1484,7 @@ TEST (wallet, search_pending)
wallet.store.erase (node.wallets.tx_begin_write (), nano::genesis_account); wallet.store.erase (node.wallets.tx_begin_write (), nano::genesis_account);
// Now confirm the election // Now confirm the election
{ election->force_confirm ();
nano::lock_guard<std::mutex> guard (node.active.mutex);
election->confirm_once ();
}
ASSERT_TIMELY (5s, node.block_confirmed (send->hash ()) && node.active.empty ()); ASSERT_TIMELY (5s, node.block_confirmed (send->hash ()) && node.active.empty ());

View file

@ -324,7 +324,7 @@ void nano::active_transactions::request_confirm (nano::unique_lock<std::mutex> &
--optimistic_elections_count; --optimistic_elections_count;
} }
election_l->cleanup (); cleanup_election (election_l->cleanup_info ());
i = sorted_roots_l.erase (i); i = sorted_roots_l.erase (i);
} }
else 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) void nano::active_transactions::add_expired_optimistic_election (nano::election const & election_a)
{ {
auto account = election_a.status.winner->account (); 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); auto election (*root_it_a);
debug_assert (election != roots.end ()); debug_assert (election != roots.end ());
auto find_block (election->election->blocks.find (block_a.hash ())); auto find_block (election->election->last_blocks.find (block_a.hash ()));
if (find_block != election->election->blocks.end () && find_block->second->has_sideband ()) 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); 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 (); 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 () std::deque<nano::election_status> nano::active_transactions::list_recently_cemented ()
{ {
nano::lock_guard<std::mutex> lock (mutex); 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 ())); auto root_it (roots.get<tag_root> ().find (block_a.qualified_root ()));
if (root_it != roots.get<tag_root> ().end ()) 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); roots.get<tag_root> ().erase (root_it);
lock.unlock (); 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 ())); 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 ()));

View file

@ -195,7 +195,6 @@ public:
uint64_t limited_active_difficulty (nano::block const &); uint64_t limited_active_difficulty (nano::block const &);
uint64_t limited_active_difficulty (nano::work_version const, uint64_t const); uint64_t limited_active_difficulty (nano::work_version const, uint64_t const);
double active_multiplier (); double active_multiplier ();
std::deque<std::shared_ptr<nano::block>> list_blocks ();
void erase (nano::block const &); void erase (nano::block const &);
bool empty (); bool empty ();
size_t size (); size_t size ();
@ -245,6 +244,8 @@ private:
bool update_difficulty_impl (roots_iterator const &, nano::block const &); bool update_difficulty_impl (roots_iterator const &, nano::block const &);
void request_loop (); void request_loop ();
void request_confirm (nano::unique_lock<std::mutex> &); 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; nano::condition_variable condition;
bool started{ false }; bool started{ false };
std::atomic<bool> stopped{ false }; std::atomic<bool> stopped{ false };

View file

@ -7,10 +7,6 @@
using namespace std::chrono; 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 std::chrono::milliseconds nano::election::base_latency () const
{ {
return node.network_params.network.is_dev_network () ? 25ms : 1000ms; 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) : 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), confirmation_action (confirmation_action_a),
prioritized_m (prioritized_a), prioritized_m (prioritized_a),
election_behavior (election_behavior_a), behavior (election_behavior_a),
node (node_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 }), 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), height (block_a->sideband ().height),
root (block_a->root ()) 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 () }); 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) 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_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.election_duration = std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::steady_clock::now () - election_start);
status.confirmation_request_count = confirmation_request_count; 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.voter_count = nano::narrow_cast<decltype (status.voter_count)> (last_votes.size ());
status.type = type_a; status.type = type_a;
auto status_l (status); 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 () nano::tally_t nano::election::tally ()
{ {
std::unordered_map<nano::block_hash, nano::uint128_t> block_weights; 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; last_tally = block_weights;
nano::tally_t result; nano::tally_t result;
for (auto item : block_weights) for (auto item : block_weights)
{ {
auto block (blocks.find (item.first)); auto block (last_blocks.find (item.first));
if (block != blocks.end ()) if (block != last_blocks.end ())
{ {
result.emplace (item.second, block->second); result.emplace (item.second, block->second);
} }
@ -274,9 +270,9 @@ void nano::election::confirm_if_quorum ()
debug_assert (!tally_l.empty ()); debug_assert (!tally_l.empty ());
auto winner (tally_l.begin ()); auto winner (tally_l.begin ());
auto block_l (winner->second); auto block_l (winner->second);
auto winner_hash_l (block_l->hash ()); auto const & winner_hash_l (block_l->hash ());
status.tally = winner->first; 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); nano::uint128_t sum (0);
for (auto & i : tally_l) for (auto & i : tally_l)
{ {
@ -290,7 +286,7 @@ void nano::election::confirm_if_quorum ()
} }
if (have_quorum (tally_l, sum)) 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); 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 // Do not insert new blocks if already confirmed
auto result (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) 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) if (!result)
{ {
auto existing = blocks.find (block_a->hash ()); auto existing = last_blocks.find (block_a->hash ());
if (existing == blocks.end ()) 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 ())) if (!insert_inactive_votes_cache (block_a->hash ()))
{ {
// Even if no votes were in cache, they could be in the election // 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; 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); debug_assert (!node.active.mutex.try_lock ());
return last_votes.size (); return nano::election_cleanup_info{
} confirmed (),
status.winner->qualified_root (),
void nano::election::cleanup () status.winner->hash (),
{ last_blocks
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);
}
});
}
} }
size_t nano::election::insert_inactive_votes_cache (nano::block_hash const & hash_a) 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 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) 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 ()); 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 () void nano::election::generate_votes ()
{ {
debug_assert (!node.active.mutex.try_lock ()); 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); 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;
}

View file

@ -13,6 +13,7 @@ namespace nano
{ {
class channel; class channel;
class confirmation_solicitor; class confirmation_solicitor;
class json_handler;
class node; class node;
class vote_generator_session; class vote_generator_session;
class vote_info final class vote_info final
@ -35,6 +36,13 @@ enum class election_behavior
normal, normal,
optimistic 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> class election final : public std::enable_shared_from_this<nano::election>
{ {
@ -52,9 +60,9 @@ private: // State management
expired_confirmed, expired_confirmed,
expired_unconfirmed expired_unconfirmed
}; };
static int constexpr passive_duration_factor = 5; static unsigned constexpr passive_duration_factor = 5;
static int constexpr active_request_count_min = 2; static unsigned constexpr active_request_count_min = 2;
static int constexpr confirmed_duration_factor = 5; static unsigned constexpr confirmed_duration_factor = 5;
std::atomic<nano::election::state_t> state_m = { state_t::passive }; std::atomic<nano::election::state_t> state_m = { state_t::passive };
// These time points must be protected by this mutex // 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 valid_change (nano::election::state_t, nano::election::state_t) const;
bool state_change (nano::election::state_t, nano::election::state_t); 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 }; 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 public: // State transitions
bool transition_time (nano::confirmation_solicitor &); bool transition_time (nano::confirmation_solicitor &);
void transition_active (); void transition_active ();
private: public: // Status
void transition_active_impl ();
public:
bool confirmed () const; bool confirmed () const;
bool failed () const; bool failed () const;
nano::election_behavior election_behavior{ nano::election_behavior::normal }; bool prioritized () const;
nano::node & node; bool optimistic () const;
std::unordered_map<nano::account, nano::vote_info> last_votes; std::shared_ptr<nano::block> winner ();
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 () }; 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; nano::election_status status;
unsigned confirmation_request_count{ 0 }; 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; uint64_t const height;
nano::root const root; 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 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;
}; };
} }

View file

@ -6726,12 +6726,9 @@ TEST (rpc, block_confirmed)
node->process_active (send); node->process_active (send);
node->block_processor.flush (); node->block_processor.flush ();
node->block_confirm (send); node->block_confirm (send);
{
auto election = node->active.election (send->qualified_root ()); auto election = node->active.election (send->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election->force_confirm ();
election->confirm_once ();
}
// Wait until the confirmation height has been set // 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 ())); 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); node1.process_active (send2);
nano::blocks_confirm (node1, { send1, send2 }); nano::blocks_confirm (node1, { send1, send2 });
ASSERT_EQ (2, node1.active.size ()); ASSERT_EQ (2, node1.active.size ());
{ auto election (node1.active.election (send1->qualified_root ()));
nano::lock_guard<std::mutex> guard (node1.active.mutex); ASSERT_NE (nullptr, election);
auto info (node1.active.roots.find (send1->qualified_root ())); election->force_confirm ();
ASSERT_NE (node1.active.roots.end (), info);
info->election->confirm_once ();
}
boost::property_tree::ptree request; boost::property_tree::ptree request;
request.put ("action", "confirmation_active"); request.put ("action", "confirmation_active");

View file

@ -224,8 +224,10 @@ TEST (node, fork_storm)
} }
else else
{ {
nano::lock_guard<std::mutex> lock (node_a->active.mutex); nano::unique_lock<std::mutex> lock (node_a->active.mutex);
if (node_a->active.roots.begin ()->election->last_votes_size () == 1) auto election = node_a->active.roots.begin ()->election;
lock.unlock ();
if (election->votes ().size () == 1)
{ {
++single; ++single;
} }
@ -490,8 +492,7 @@ TEST (confirmation_height, many_accounts_single_confirmation)
auto election_insertion_result (node->active.insert (block)); auto election_insertion_result (node->active.insert (block));
ASSERT_TRUE (election_insertion_result.inserted); ASSERT_TRUE (election_insertion_result.inserted);
ASSERT_NE (nullptr, election_insertion_result.election); ASSERT_NE (nullptr, election_insertion_result.election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election_insertion_result.election->force_confirm ();
election_insertion_result.election->confirm_once ();
} }
ASSERT_TIMELY (120s, node->ledger.block_confirmed (node->store.tx_begin_read (), last_open_hash)); 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)); auto election_insertion_result (node->active.insert (open_block));
ASSERT_TRUE (election_insertion_result.inserted); ASSERT_TRUE (election_insertion_result.inserted);
ASSERT_NE (nullptr, election_insertion_result.election); ASSERT_NE (nullptr, election_insertion_result.election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election_insertion_result.election->force_confirm ();
election_insertion_result.election->confirm_once ();
} }
auto const num_blocks_to_confirm = (num_accounts - 1) * 2; 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)); auto election_insertion_result (node->active.insert (receive1));
ASSERT_TRUE (election_insertion_result.inserted); ASSERT_TRUE (election_insertion_result.inserted);
ASSERT_NE (nullptr, election_insertion_result.election); ASSERT_NE (nullptr, election_insertion_result.election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election_insertion_result.election->force_confirm ();
election_insertion_result.election->confirm_once ();
} }
ASSERT_TIMELY (30s, node->ledger.block_confirmed (node->store.tx_begin_read (), receive1->hash ())); 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); node->block_confirm (open_block);
auto election = node->active.election (open_block->qualified_root ()); auto election = node->active.election (open_block->qualified_root ());
ASSERT_NE (nullptr, election); ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node->active.mutex); election->force_confirm ();
election->confirm_once ();
} }
system.deadline_set (100s); system.deadline_set (100s);