Remove dead code from active_transactions (#3868)
This commit is contained in:
parent
82c4c10f7e
commit
f9d9b75ca7
8 changed files with 11 additions and 1213 deletions
|
|
@ -1200,150 +1200,6 @@ TEST (active_transactions, activate_inactive)
|
|||
ASSERT_FALSE (node.active.active (open->qualified_root ()) || node.block_confirmed_or_being_confirmed (node.store.tx_begin_read (), open->hash ()));
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
TEST (active_transactions, pessimistic_elections)
|
||||
{
|
||||
nano::system system;
|
||||
nano::node_flags flags;
|
||||
nano::node_config config (nano::get_available_port (), system.logging);
|
||||
config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
|
||||
auto & node = *system.add_node (config, flags);
|
||||
|
||||
nano::keypair key;
|
||||
nano::state_block_builder builder;
|
||||
auto send = builder.make_block ()
|
||||
.account (nano::dev::genesis_key.pub)
|
||||
.previous (nano::dev::genesis->hash ())
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.link (nano::dev::genesis_key.pub)
|
||||
.balance (nano::dev::constants.genesis_amount - 1)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*system.work.generate (nano::dev::genesis->hash ()))
|
||||
.build_shared ();
|
||||
|
||||
ASSERT_EQ (nano::process_result::progress, node.process (*send).code);
|
||||
|
||||
auto send2 = builder.make_block ()
|
||||
.account (nano::dev::genesis_key.pub)
|
||||
.previous (send->hash ())
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.link (key.pub)
|
||||
.balance (nano::dev::constants.genesis_amount - 2)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*system.work.generate (send->hash ()))
|
||||
.build ();
|
||||
|
||||
ASSERT_EQ (nano::process_result::progress, node.process (*send2).code);
|
||||
|
||||
auto open = builder.make_block ()
|
||||
.account (key.pub)
|
||||
.previous (0)
|
||||
.representative (key.pub)
|
||||
.link (send2->hash ())
|
||||
.balance (1)
|
||||
.sign (key.prv, key.pub)
|
||||
.work (*system.work.generate (key.pub))
|
||||
.build_shared ();
|
||||
|
||||
ASSERT_EQ (nano::process_result::progress, node.process (*open).code);
|
||||
|
||||
// This should only cement the first block in genesis account
|
||||
uint64_t election_count = 0;
|
||||
// Make dummy election with winner.
|
||||
{
|
||||
nano::election election1 (
|
||||
node, send, [] (auto const &) {}, [] (auto const &) {}, nano::election_behavior::normal);
|
||||
nano::election election2 (
|
||||
node, open, [] (auto const &) {}, [] (auto const &) {}, nano::election_behavior::normal);
|
||||
node.active.add_expired_optimistic_election (election1);
|
||||
node.active.add_expired_optimistic_election (election2);
|
||||
}
|
||||
node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count);
|
||||
ASSERT_EQ (1, election_count);
|
||||
ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ());
|
||||
ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ());
|
||||
auto election_started_it = node.active.expired_optimistic_election_infos.get<nano::active_transactions::tag_election_started> ().begin ();
|
||||
ASSERT_EQ (election_started_it->account, nano::dev::genesis->account ());
|
||||
ASSERT_EQ (election_started_it->election_started, true);
|
||||
ASSERT_EQ ((++election_started_it)->election_started, false);
|
||||
|
||||
// No new elections should get started yet
|
||||
node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count);
|
||||
ASSERT_EQ (1, election_count);
|
||||
ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ());
|
||||
ASSERT_EQ (node.active.expired_optimistic_election_infos_size, node.active.expired_optimistic_election_infos.size ());
|
||||
|
||||
ASSERT_EQ (1, node.active.size ());
|
||||
auto election = node.active.election (send->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (3s, node.block_confirmed (send->hash ()) && !node.confirmation_height_processor.is_processing_added_block (send->hash ()));
|
||||
|
||||
nano::confirmation_height_info genesis_confirmation_height_info;
|
||||
nano::confirmation_height_info key1_confirmation_height_info;
|
||||
{
|
||||
auto transaction = node.store.tx_begin_read ();
|
||||
node.store.confirmation_height.get (transaction, nano::dev::genesis->account (), genesis_confirmation_height_info);
|
||||
ASSERT_EQ (2, genesis_confirmation_height_info.height);
|
||||
node.store.confirmation_height.get (transaction, key.pub, key1_confirmation_height_info);
|
||||
ASSERT_EQ (0, key1_confirmation_height_info.height);
|
||||
}
|
||||
|
||||
// Activation of cemented frontier successor should get started after the first pessimistic block is confirmed
|
||||
ASSERT_TIMELY (10s, node.active.active (send2->qualified_root ()));
|
||||
|
||||
node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count);
|
||||
ASSERT_EQ (1, election_count);
|
||||
ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ());
|
||||
|
||||
// Confirm it
|
||||
election = node.active.election (send2->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (3s, node.block_confirmed (send2->hash ()));
|
||||
|
||||
{
|
||||
auto transaction = node.store.tx_begin_read ();
|
||||
node.store.confirmation_height.get (transaction, nano::dev::genesis->account (), genesis_confirmation_height_info);
|
||||
ASSERT_EQ (3, genesis_confirmation_height_info.height);
|
||||
node.store.confirmation_height.get (transaction, key.pub, key1_confirmation_height_info);
|
||||
ASSERT_EQ (0, key1_confirmation_height_info.height);
|
||||
}
|
||||
|
||||
// Wait until activation of destination account is done.
|
||||
ASSERT_TIMELY (10s, node.active.active (open->qualified_root ()));
|
||||
|
||||
// Election count should not increase, but the elections should be marked as started for that account afterwards
|
||||
ASSERT_EQ (election_started_it->election_started, false);
|
||||
node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count);
|
||||
ASSERT_EQ (1, election_count);
|
||||
ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ());
|
||||
node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count);
|
||||
|
||||
election = node.active.election (open->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
|
||||
ASSERT_TIMELY (3s, node.block_confirmed (open->hash ()));
|
||||
|
||||
{
|
||||
auto transaction = node.store.tx_begin_read ();
|
||||
node.store.confirmation_height.get (transaction, nano::dev::genesis->account (), genesis_confirmation_height_info);
|
||||
ASSERT_EQ (3, genesis_confirmation_height_info.height);
|
||||
node.store.confirmation_height.get (transaction, key.pub, key1_confirmation_height_info);
|
||||
ASSERT_EQ (1, key1_confirmation_height_info.height);
|
||||
}
|
||||
|
||||
// Sanity check that calling it again on a fully cemented chain has no adverse effects.
|
||||
node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count);
|
||||
ASSERT_EQ (1, election_count);
|
||||
ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ());
|
||||
}
|
||||
}
|
||||
|
||||
TEST (active_transactions, list_active)
|
||||
{
|
||||
nano::system system (1);
|
||||
|
|
|
|||
|
|
@ -6,371 +6,6 @@
|
|||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace nano
|
||||
{
|
||||
TEST (frontiers_confirmation, prioritize_frontiers)
|
||||
{
|
||||
nano::system system;
|
||||
// Prevent frontiers being confirmed as it will affect the priorization checking
|
||||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
|
||||
auto node = system.add_node (node_config);
|
||||
|
||||
nano::keypair key1;
|
||||
nano::keypair key2;
|
||||
nano::keypair key3;
|
||||
nano::keypair key4;
|
||||
nano::block_builder builder;
|
||||
nano::block_hash latest1 (node->latest (nano::dev::genesis_key.pub));
|
||||
|
||||
// Send different numbers of blocks all accounts
|
||||
auto send1 = builder
|
||||
.send ()
|
||||
.previous (latest1)
|
||||
.destination (key1.pub)
|
||||
.balance (node->config.online_weight_minimum.number () + 10000)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*system.work.generate (latest1))
|
||||
.build ();
|
||||
auto send2 = builder
|
||||
.send ()
|
||||
.previous (send1->hash ())
|
||||
.destination (key1.pub)
|
||||
.balance (node->config.online_weight_minimum.number () + 8500)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*system.work.generate (send1->hash ()))
|
||||
.build ();
|
||||
auto send3 = builder
|
||||
.send ()
|
||||
.previous (send2->hash ())
|
||||
.destination (key1.pub)
|
||||
.balance (node->config.online_weight_minimum.number () + 8000)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*system.work.generate (send2->hash ()))
|
||||
.build ();
|
||||
auto send4 = builder
|
||||
.send ()
|
||||
.previous (send3->hash ())
|
||||
.destination (key2.pub)
|
||||
.balance (node->config.online_weight_minimum.number () + 7500)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*system.work.generate (send3->hash ()))
|
||||
.build ();
|
||||
auto send5 = builder
|
||||
.send ()
|
||||
.previous (send4->hash ())
|
||||
.destination (key3.pub)
|
||||
.balance (node->config.online_weight_minimum.number () + 6500)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*system.work.generate (send4->hash ()))
|
||||
.build ();
|
||||
auto send6 = builder
|
||||
.send ()
|
||||
.previous (send5->hash ())
|
||||
.destination (key4.pub)
|
||||
.balance (node->config.online_weight_minimum.number () + 6000)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*system.work.generate (send5->hash ()))
|
||||
.build ();
|
||||
|
||||
// Open all accounts and add other sends to get different uncemented counts (as well as some which are the same)
|
||||
auto open1 = builder
|
||||
.open ()
|
||||
.source (send1->hash ())
|
||||
.representative (nano::dev::genesis->account ())
|
||||
.account (key1.pub)
|
||||
.sign (key1.prv, key1.pub)
|
||||
.work (*system.work.generate (key1.pub))
|
||||
.build ();
|
||||
auto send7 = builder
|
||||
.send ()
|
||||
.previous (open1->hash ())
|
||||
.destination (nano::dev::genesis_key.pub)
|
||||
.balance (500)
|
||||
.sign (key1.prv, key1.pub)
|
||||
.work (*system.work.generate (open1->hash ()))
|
||||
.build ();
|
||||
|
||||
auto open2 = builder
|
||||
.open ()
|
||||
.source (send4->hash ())
|
||||
.representative (nano::dev::genesis->account ())
|
||||
.account (key2.pub)
|
||||
.sign (key2.prv, key2.pub)
|
||||
.work (*system.work.generate (key2.pub))
|
||||
.build ();
|
||||
|
||||
auto open3 = builder
|
||||
.open ()
|
||||
.source (send5->hash ())
|
||||
.representative (nano::dev::genesis->account ())
|
||||
.account (key3.pub)
|
||||
.sign (key3.prv, key3.pub)
|
||||
.work (*system.work.generate (key3.pub))
|
||||
.build ();
|
||||
auto send8 = builder
|
||||
.send ()
|
||||
.previous (open3->hash ())
|
||||
.destination (nano::dev::genesis_key.pub)
|
||||
.balance (500)
|
||||
.sign (key3.prv, key3.pub)
|
||||
.work (*system.work.generate (open3->hash ()))
|
||||
.build ();
|
||||
auto send9 = builder
|
||||
.send ()
|
||||
.previous (send8->hash ())
|
||||
.destination (nano::dev::genesis_key.pub)
|
||||
.balance (200)
|
||||
.sign (key3.prv, key3.pub)
|
||||
.work (*system.work.generate (send8->hash ()))
|
||||
.build ();
|
||||
|
||||
auto open4 = builder
|
||||
.open ()
|
||||
.source (send6->hash ())
|
||||
.representative (nano::dev::genesis->account ())
|
||||
.account (key4.pub)
|
||||
.sign (key4.prv, key4.pub)
|
||||
.work (*system.work.generate (key4.pub))
|
||||
.build ();
|
||||
auto send10 = builder
|
||||
.send ()
|
||||
.previous (open4->hash ())
|
||||
.destination (nano::dev::genesis_key.pub)
|
||||
.balance (500)
|
||||
.sign (key4.prv, key4.pub)
|
||||
.work (*system.work.generate (open4->hash ()))
|
||||
.build ();
|
||||
auto send11 = builder
|
||||
.send ()
|
||||
.previous (send10->hash ())
|
||||
.destination (nano::dev::genesis_key.pub)
|
||||
.balance (200)
|
||||
.sign (key4.prv, key4.pub)
|
||||
.work (*system.work.generate (send10->hash ()))
|
||||
.build ();
|
||||
|
||||
{
|
||||
auto transaction = node->store.tx_begin_write ();
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send1).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send2).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send3).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send4).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send5).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send6).code);
|
||||
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *open1).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send7).code);
|
||||
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *open2).code);
|
||||
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *open3).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send8).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send9).code);
|
||||
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *open4).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send10).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send11).code);
|
||||
}
|
||||
|
||||
auto transaction = node->store.tx_begin_read ();
|
||||
constexpr auto num_accounts = 5;
|
||||
auto priority_orders_match = [] (auto const & cementable_frontiers, auto const & desired_order) {
|
||||
return std::equal (desired_order.begin (), desired_order.end (), cementable_frontiers.template get<1> ().begin (), cementable_frontiers.template get<1> ().end (), [] (nano::account const & account, nano::cementable_account const & cementable_account) {
|
||||
return (account == cementable_account.account);
|
||||
});
|
||||
};
|
||||
{
|
||||
node->active.prioritize_frontiers_for_confirmation (transaction, std::chrono::seconds (1), std::chrono::seconds (1));
|
||||
ASSERT_EQ (node->active.priority_cementable_frontiers_size (), num_accounts);
|
||||
// Check the order of accounts is as expected (greatest number of uncemented blocks at the front). key3 and key4 have the same value, the order is unspecified so check both
|
||||
std::array<nano::account, num_accounts> desired_order_1{ nano::dev::genesis->account (), key3.pub, key4.pub, key1.pub, key2.pub };
|
||||
std::array<nano::account, num_accounts> desired_order_2{ nano::dev::genesis->account (), key4.pub, key3.pub, key1.pub, key2.pub };
|
||||
ASSERT_TRUE (priority_orders_match (node->active.priority_cementable_frontiers, desired_order_1) || priority_orders_match (node->active.priority_cementable_frontiers, desired_order_2));
|
||||
}
|
||||
|
||||
{
|
||||
// Add some to the local node wallets and check ordering of both containers
|
||||
system.wallet (0)->insert_adhoc (nano::dev::genesis_key.prv);
|
||||
system.wallet (0)->insert_adhoc (key1.prv);
|
||||
system.wallet (0)->insert_adhoc (key2.prv);
|
||||
node->active.prioritize_frontiers_for_confirmation (transaction, std::chrono::seconds (1), std::chrono::seconds (1));
|
||||
ASSERT_EQ (node->active.priority_cementable_frontiers_size (), num_accounts - 3);
|
||||
ASSERT_EQ (node->active.priority_wallet_cementable_frontiers_size (), num_accounts - 2);
|
||||
std::array<nano::account, 3> local_desired_order{ nano::dev::genesis->account (), key1.pub, key2.pub };
|
||||
ASSERT_TRUE (priority_orders_match (node->active.priority_wallet_cementable_frontiers, local_desired_order));
|
||||
std::array<nano::account, 2> desired_order_1{ key3.pub, key4.pub };
|
||||
std::array<nano::account, 2> desired_order_2{ key4.pub, key3.pub };
|
||||
ASSERT_TRUE (priority_orders_match (node->active.priority_cementable_frontiers, desired_order_1) || priority_orders_match (node->active.priority_cementable_frontiers, desired_order_2));
|
||||
}
|
||||
|
||||
{
|
||||
// Add the remainder of accounts to node wallets and check size/ordering is correct
|
||||
system.wallet (0)->insert_adhoc (key3.prv);
|
||||
system.wallet (0)->insert_adhoc (key4.prv);
|
||||
node->active.prioritize_frontiers_for_confirmation (transaction, std::chrono::seconds (1), std::chrono::seconds (1));
|
||||
ASSERT_EQ (node->active.priority_cementable_frontiers_size (), 0);
|
||||
ASSERT_EQ (node->active.priority_wallet_cementable_frontiers_size (), num_accounts);
|
||||
std::array<nano::account, num_accounts> desired_order_1{ nano::dev::genesis->account (), key3.pub, key4.pub, key1.pub, key2.pub };
|
||||
std::array<nano::account, num_accounts> desired_order_2{ nano::dev::genesis->account (), key4.pub, key3.pub, key1.pub, key2.pub };
|
||||
ASSERT_TRUE (priority_orders_match (node->active.priority_wallet_cementable_frontiers, desired_order_1) || priority_orders_match (node->active.priority_wallet_cementable_frontiers, desired_order_2));
|
||||
}
|
||||
|
||||
// Check that accounts which already exist have their order modified when the uncemented count changes.
|
||||
auto send12 = builder
|
||||
.send ()
|
||||
.previous (send9->hash ())
|
||||
.destination (nano::dev::genesis_key.pub)
|
||||
.balance (100)
|
||||
.sign (key3.prv, key3.pub)
|
||||
.work (*system.work.generate (send9->hash ()))
|
||||
.build ();
|
||||
auto send13 = builder
|
||||
.send ()
|
||||
.previous (send12->hash ())
|
||||
.destination (nano::dev::genesis_key.pub)
|
||||
.balance (90)
|
||||
.sign (key3.prv, key3.pub)
|
||||
.work (*system.work.generate (send12->hash ()))
|
||||
.build ();
|
||||
auto send14 = builder
|
||||
.send ()
|
||||
.previous (send13->hash ())
|
||||
.destination (nano::dev::genesis_key.pub)
|
||||
.balance (80)
|
||||
.sign (key3.prv, key3.pub)
|
||||
.work (*system.work.generate (send13->hash ()))
|
||||
.build ();
|
||||
auto send15 = builder
|
||||
.send ()
|
||||
.previous (send14->hash ())
|
||||
.destination (nano::dev::genesis_key.pub)
|
||||
.balance (70)
|
||||
.sign (key3.prv, key3.pub)
|
||||
.work (*system.work.generate (send14->hash ()))
|
||||
.build ();
|
||||
auto send16 = builder
|
||||
.send ()
|
||||
.previous (send15->hash ())
|
||||
.destination (nano::dev::genesis_key.pub)
|
||||
.balance (60)
|
||||
.sign (key3.prv, key3.pub)
|
||||
.work (*system.work.generate (send15->hash ()))
|
||||
.build ();
|
||||
auto send17 = builder
|
||||
.send ()
|
||||
.previous (send16->hash ())
|
||||
.destination (nano::dev::genesis_key.pub)
|
||||
.balance (50)
|
||||
.sign (key3.prv, key3.pub)
|
||||
.work (*system.work.generate (send16->hash ()))
|
||||
.build ();
|
||||
{
|
||||
auto transaction = node->store.tx_begin_write ();
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send12).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send13).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send14).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send15).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send16).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send17).code);
|
||||
}
|
||||
transaction.refresh ();
|
||||
node->active.prioritize_frontiers_for_confirmation (transaction, std::chrono::seconds (1), std::chrono::seconds (1));
|
||||
ASSERT_TRUE (priority_orders_match (node->active.priority_wallet_cementable_frontiers, std::array<nano::account, num_accounts>{ key3.pub, nano::dev::genesis->account (), key4.pub, key1.pub, key2.pub }));
|
||||
uint64_t election_count = 0;
|
||||
node->active.confirm_prioritized_frontiers (transaction, 100, election_count);
|
||||
|
||||
// Check that the active transactions roots contains the frontiers
|
||||
ASSERT_TIMELY (10s, node->active.size () == num_accounts);
|
||||
|
||||
std::array<nano::qualified_root, num_accounts> frontiers{ send17->qualified_root (), send6->qualified_root (), send7->qualified_root (), open2->qualified_root (), send11->qualified_root () };
|
||||
for (auto & frontier : frontiers)
|
||||
{
|
||||
ASSERT_TRUE (node->active.active (frontier));
|
||||
}
|
||||
}
|
||||
|
||||
TEST (frontiers_confirmation, prioritize_frontiers_max_optimistic_elections)
|
||||
{
|
||||
nano::system system;
|
||||
// Prevent frontiers being confirmed as it will affect the priorization checking
|
||||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
|
||||
auto node = system.add_node (node_config);
|
||||
|
||||
node->ledger.cache.cemented_count = node->ledger.bootstrap_weight_max_blocks - 1;
|
||||
auto max_optimistic_election_count_under_hardcoded_weight = node->active.max_optimistic ();
|
||||
node->ledger.cache.cemented_count = node->ledger.bootstrap_weight_max_blocks;
|
||||
auto max_optimistic_election_count = node->active.max_optimistic ();
|
||||
ASSERT_GT (max_optimistic_election_count_under_hardcoded_weight, max_optimistic_election_count);
|
||||
|
||||
for (auto i = 0; i < max_optimistic_election_count * 2; ++i)
|
||||
{
|
||||
auto transaction = node->store.tx_begin_write ();
|
||||
auto latest = node->latest (nano::dev::genesis->account ());
|
||||
nano::keypair key;
|
||||
nano::block_builder builder;
|
||||
auto send = builder
|
||||
.send ()
|
||||
.previous (latest)
|
||||
.destination (key.pub)
|
||||
.balance (node->config.online_weight_minimum.number () + 10000)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*system.work.generate (latest))
|
||||
.build ();
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send).code);
|
||||
auto open = builder
|
||||
.open ()
|
||||
.source (send->hash ())
|
||||
.representative (nano::dev::genesis->account ())
|
||||
.account (key.pub)
|
||||
.sign (key.prv, key.pub)
|
||||
.work (*system.work.generate (key.pub))
|
||||
.build ();
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *open).code);
|
||||
}
|
||||
|
||||
{
|
||||
nano::unique_lock<nano::mutex> lk (node->active.mutex);
|
||||
node->active.frontiers_confirmation (lk);
|
||||
}
|
||||
|
||||
ASSERT_EQ (max_optimistic_election_count, node->active.roots.size ());
|
||||
|
||||
nano::account next_frontier_account{ 2 };
|
||||
node->active.next_frontier_account = next_frontier_account;
|
||||
|
||||
// Call frontiers confirmation again and confirm that next_frontier_account hasn't changed
|
||||
{
|
||||
nano::unique_lock<nano::mutex> lk (node->active.mutex);
|
||||
node->active.frontiers_confirmation (lk);
|
||||
}
|
||||
|
||||
ASSERT_EQ (max_optimistic_election_count, node->active.roots.size ());
|
||||
ASSERT_EQ (next_frontier_account, node->active.next_frontier_account);
|
||||
}
|
||||
|
||||
TEST (frontiers_confirmation, expired_optimistic_elections_removal)
|
||||
{
|
||||
nano::system system;
|
||||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
|
||||
auto node = system.add_node (node_config);
|
||||
|
||||
// This should be removed on the next prioritization call
|
||||
node->active.expired_optimistic_election_infos.emplace (std::chrono::steady_clock::now () - (node->active.expired_optimistic_election_info_cutoff + 1min), nano::account (1));
|
||||
ASSERT_EQ (1, node->active.expired_optimistic_election_infos.size ());
|
||||
node->active.prioritize_frontiers_for_confirmation (node->store.tx_begin_read (), 0s, 0s);
|
||||
ASSERT_EQ (0, node->active.expired_optimistic_election_infos.size ());
|
||||
|
||||
// This should not be removed on the next prioritization call
|
||||
node->active.expired_optimistic_election_infos.emplace (std::chrono::steady_clock::now () - (node->active.expired_optimistic_election_info_cutoff - 1min), nano::account (1));
|
||||
ASSERT_EQ (1, node->active.expired_optimistic_election_infos.size ());
|
||||
node->active.prioritize_frontiers_for_confirmation (node->store.tx_begin_read (), 0s, 0s);
|
||||
ASSERT_EQ (1, node->active.expired_optimistic_election_infos.size ());
|
||||
}
|
||||
}
|
||||
|
||||
TEST (frontiers_confirmation, mode)
|
||||
{
|
||||
nano::keypair key;
|
||||
|
|
|
|||
|
|
@ -4139,10 +4139,14 @@ namespace nano
|
|||
TEST (node, deferred_dependent_elections)
|
||||
{
|
||||
nano::system system;
|
||||
nano::node_config node_config_1{ nano::get_available_port (), system.logging };
|
||||
node_config_1.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
|
||||
nano::node_config node_config_2{ nano::get_available_port (), system.logging };
|
||||
node_config_2.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
|
||||
nano::node_flags flags;
|
||||
flags.disable_request_loop = true;
|
||||
auto & node = *system.add_node (flags);
|
||||
auto & node2 = *system.add_node (flags); // node2 will be used to ensure all blocks are being propagated
|
||||
auto & node = *system.add_node (node_config_1, flags);
|
||||
auto & node2 = *system.add_node (node_config_2, flags); // node2 will be used to ensure all blocks are being propagated
|
||||
|
||||
nano::state_block_builder builder;
|
||||
nano::keypair key;
|
||||
|
|
@ -4185,6 +4189,7 @@ TEST (node, deferred_dependent_elections)
|
|||
.representative (nano::dev::genesis_key.pub) // was key.pub
|
||||
.sign (key.prv, key.pub)
|
||||
.build_shared ();
|
||||
|
||||
node.process_local (send1);
|
||||
node.block_processor.flush ();
|
||||
node.scheduler.flush ();
|
||||
|
|
@ -4224,14 +4229,6 @@ TEST (node, deferred_dependent_elections)
|
|||
node.scheduler.flush ();
|
||||
ASSERT_FALSE (node.active.active (open->qualified_root ()));
|
||||
|
||||
// Frontier confirmation also starts elections
|
||||
ASSERT_NO_ERROR (system.poll_until_true (5s, [&node, &send2] {
|
||||
nano::unique_lock<nano::mutex> lock{ node.active.mutex };
|
||||
node.active.frontiers_confirmation (lock);
|
||||
lock.unlock ();
|
||||
return node.active.election (send2->qualified_root ()) != nullptr;
|
||||
}));
|
||||
|
||||
// Drop both elections
|
||||
node.active.erase (*open);
|
||||
ASSERT_FALSE (node.active.active (open->qualified_root ()));
|
||||
|
|
|
|||
|
|
@ -14,10 +14,6 @@
|
|||
|
||||
using namespace std::chrono;
|
||||
|
||||
std::size_t constexpr nano::active_transactions::max_active_elections_frontier_insertion;
|
||||
|
||||
constexpr std::chrono::minutes nano::active_transactions::expired_optimistic_election_info_cutoff;
|
||||
|
||||
nano::active_transactions::active_transactions (nano::node & node_a, nano::confirmation_height_processor & confirmation_height_processor_a) :
|
||||
scheduler{ node_a.scheduler }, // Move dependencies requiring this circular reference
|
||||
confirmation_height_processor{ confirmation_height_processor_a },
|
||||
|
|
@ -49,118 +45,6 @@ nano::active_transactions::~active_transactions ()
|
|||
stop ();
|
||||
}
|
||||
|
||||
bool nano::active_transactions::insert_election_from_frontiers_confirmation (std::shared_ptr<nano::block> const & block_a, nano::account const & account_a, nano::uint128_t previous_balance_a, nano::election_behavior election_behavior_a)
|
||||
{
|
||||
bool inserted{ false };
|
||||
nano::unique_lock<nano::mutex> lock (mutex);
|
||||
if (roots.get<tag_root> ().find (block_a->qualified_root ()) == roots.get<tag_root> ().end ())
|
||||
{
|
||||
std::function<void (std::shared_ptr<nano::block> const &)> election_confirmation_cb;
|
||||
if (election_behavior_a == nano::election_behavior::optimistic)
|
||||
{
|
||||
election_confirmation_cb = [this] (std::shared_ptr<nano::block> const & block_a) {
|
||||
--optimistic_elections_count;
|
||||
};
|
||||
}
|
||||
|
||||
auto insert_result = insert_impl (lock, block_a, election_behavior_a, election_confirmation_cb);
|
||||
inserted = insert_result.inserted;
|
||||
if (inserted)
|
||||
{
|
||||
insert_result.election->transition_active ();
|
||||
if (insert_result.election->optimistic ())
|
||||
{
|
||||
++optimistic_elections_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
return inserted;
|
||||
}
|
||||
|
||||
nano::frontiers_confirmation_info nano::active_transactions::get_frontiers_confirmation_info ()
|
||||
{
|
||||
// Limit maximum count of elections to start
|
||||
auto rep_counts (node.wallets.reps ());
|
||||
bool representative (node.config.enable_voting && rep_counts.voting > 0);
|
||||
bool half_princpal_representative (representative && rep_counts.have_half_rep ());
|
||||
/* Check less frequently for regular nodes in auto mode */
|
||||
bool agressive_mode (half_princpal_representative || node.config.frontiers_confirmation == nano::frontiers_confirmation_mode::always);
|
||||
auto is_dev_network = node.network_params.network.is_dev_network ();
|
||||
auto roots_size = size ();
|
||||
auto check_time_exceeded = std::chrono::steady_clock::now () >= next_frontier_check;
|
||||
auto max_elections = max_active_elections_frontier_insertion;
|
||||
auto low_active_elections = roots_size < max_elections;
|
||||
bool wallets_check_required = (!skip_wallets || !priority_wallet_cementable_frontiers.empty ()) && !agressive_mode;
|
||||
// Minimise dropping real-time transactions, set the number of frontiers added to a factor of the maximum number of possible active elections
|
||||
auto max_active = node.config.active_elections_size / 20;
|
||||
if (roots_size <= max_active && (check_time_exceeded || wallets_check_required || (!is_dev_network && low_active_elections && agressive_mode)))
|
||||
{
|
||||
// When the number of active elections is low increase max number of elections for setting confirmation height.
|
||||
if (max_active > roots_size + max_elections)
|
||||
{
|
||||
max_elections = max_active - roots_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
max_elections = 0;
|
||||
}
|
||||
|
||||
return nano::frontiers_confirmation_info{ max_elections, agressive_mode };
|
||||
}
|
||||
|
||||
void nano::active_transactions::set_next_frontier_check (bool agressive_mode_a)
|
||||
{
|
||||
auto request_interval (std::chrono::milliseconds (node.network_params.network.request_interval_ms));
|
||||
auto rel_time_next_frontier_check = request_interval * (agressive_mode_a ? 20 : 60);
|
||||
// Decrease check time for dev network
|
||||
int dev_network_factor = node.network_params.network.is_dev_network () ? 1000 : 1;
|
||||
|
||||
next_frontier_check = steady_clock::now () + (rel_time_next_frontier_check / dev_network_factor);
|
||||
}
|
||||
|
||||
void nano::active_transactions::confirm_prioritized_frontiers (nano::transaction const & transaction_a, uint64_t max_elections_a, uint64_t & elections_count_a)
|
||||
{
|
||||
nano::unique_lock<nano::mutex> lk (mutex);
|
||||
auto start_elections_for_prioritized_frontiers = [&transaction_a, &elections_count_a, max_elections_a, &lk, this] (prioritize_num_uncemented & cementable_frontiers) {
|
||||
while (!cementable_frontiers.empty () && !this->stopped && elections_count_a < max_elections_a && optimistic_elections_count < max_optimistic ())
|
||||
{
|
||||
auto cementable_account_front_it = cementable_frontiers.get<tag_uncemented> ().begin ();
|
||||
auto cementable_account = *cementable_account_front_it;
|
||||
cementable_frontiers.get<tag_uncemented> ().erase (cementable_account_front_it);
|
||||
if (expired_optimistic_election_infos.get<tag_account> ().count (cementable_account.account) == 0)
|
||||
{
|
||||
lk.unlock ();
|
||||
nano::account_info info;
|
||||
auto error = this->node.store.account.get (transaction_a, cementable_account.account, info);
|
||||
if (!error)
|
||||
{
|
||||
if (!this->confirmation_height_processor.is_processing_block (info.head))
|
||||
{
|
||||
nano::confirmation_height_info confirmation_height_info;
|
||||
this->node.store.confirmation_height.get (transaction_a, cementable_account.account, confirmation_height_info);
|
||||
|
||||
if (info.block_count > confirmation_height_info.height)
|
||||
{
|
||||
auto block (this->node.store.block.get (transaction_a, info.head));
|
||||
auto previous_balance (this->node.ledger.balance (transaction_a, block->previous ()));
|
||||
auto inserted_election = this->insert_election_from_frontiers_confirmation (block, cementable_account.account, previous_balance, nano::election_behavior::optimistic);
|
||||
if (inserted_election)
|
||||
{
|
||||
++elections_count_a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lk.lock ();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
start_elections_for_prioritized_frontiers (priority_wallet_cementable_frontiers);
|
||||
start_elections_for_prioritized_frontiers (priority_cementable_frontiers);
|
||||
}
|
||||
|
||||
void nano::active_transactions::block_cemented_callback (std::shared_ptr<nano::block> const & block_a)
|
||||
{
|
||||
auto transaction = node.store.tx_begin_read ();
|
||||
|
|
@ -318,16 +202,6 @@ void nano::active_transactions::request_confirm (nano::unique_lock<nano::mutex>
|
|||
|
||||
if (election_l->transition_time (solicitor))
|
||||
{
|
||||
if (election_l->optimistic () && election_l->failed ())
|
||||
{
|
||||
if (election_l->confirmation_request_count != 0)
|
||||
{
|
||||
// Locks active mutex
|
||||
add_expired_optimistic_election (*election_l);
|
||||
}
|
||||
--optimistic_elections_count;
|
||||
}
|
||||
|
||||
// Locks active mutex, cleans up the election and erases it from the main container
|
||||
if (!confirmed_l)
|
||||
{
|
||||
|
|
@ -429,156 +303,6 @@ std::vector<std::shared_ptr<nano::election>> nano::active_transactions::list_act
|
|||
return result_l;
|
||||
}
|
||||
|
||||
void nano::active_transactions::add_expired_optimistic_election (nano::election const & election_a)
|
||||
{
|
||||
nano::lock_guard<nano::mutex> guard (mutex);
|
||||
auto account = election_a.status.winner->account ();
|
||||
if (account.is_zero ())
|
||||
{
|
||||
account = election_a.status.winner->sideband ().account;
|
||||
}
|
||||
|
||||
auto it = expired_optimistic_election_infos.get<tag_account> ().find (account);
|
||||
if (it != expired_optimistic_election_infos.get<tag_account> ().end ())
|
||||
{
|
||||
expired_optimistic_election_infos.get<tag_account> ().modify (it, [] (auto & expired_optimistic_election) {
|
||||
expired_optimistic_election.expired_time = std::chrono::steady_clock::now ();
|
||||
expired_optimistic_election.election_started = false;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
expired_optimistic_election_infos.emplace (std::chrono::steady_clock::now (), account);
|
||||
}
|
||||
|
||||
// Expire the oldest one if a maximum is reached
|
||||
auto const max_expired_optimistic_election_infos = 10000;
|
||||
if (expired_optimistic_election_infos.size () > max_expired_optimistic_election_infos)
|
||||
{
|
||||
expired_optimistic_election_infos.get<tag_expired_time> ().erase (expired_optimistic_election_infos.get<tag_expired_time> ().begin ());
|
||||
}
|
||||
expired_optimistic_election_infos_size = expired_optimistic_election_infos.size ();
|
||||
}
|
||||
|
||||
unsigned nano::active_transactions::max_optimistic ()
|
||||
{
|
||||
return node.ledger.cache.cemented_count < node.ledger.bootstrap_weight_max_blocks ? std::numeric_limits<unsigned>::max () : 50u;
|
||||
}
|
||||
|
||||
void nano::active_transactions::frontiers_confirmation (nano::unique_lock<nano::mutex> & lock_a)
|
||||
{
|
||||
// Spend some time prioritizing accounts with the most uncemented blocks to reduce voting traffic
|
||||
auto request_interval = std::chrono::milliseconds (node.network_params.network.request_interval_ms);
|
||||
// Spend longer searching ledger accounts when there is a low amount of elections going on
|
||||
auto low_active = roots.size () < 1000;
|
||||
auto time_to_spend_prioritizing_ledger_accounts = request_interval / (low_active ? 20 : 100);
|
||||
auto time_to_spend_prioritizing_wallet_accounts = request_interval / 250;
|
||||
auto time_to_spend_confirming_pessimistic_accounts = time_to_spend_prioritizing_ledger_accounts;
|
||||
lock_a.unlock ();
|
||||
auto transaction = node.store.tx_begin_read ();
|
||||
prioritize_frontiers_for_confirmation (transaction, node.network_params.network.is_dev_network () ? std::chrono::milliseconds (50) : time_to_spend_prioritizing_ledger_accounts, time_to_spend_prioritizing_wallet_accounts);
|
||||
auto frontiers_confirmation_info = get_frontiers_confirmation_info ();
|
||||
if (frontiers_confirmation_info.can_start_elections ())
|
||||
{
|
||||
uint64_t elections_count (0);
|
||||
confirm_prioritized_frontiers (transaction, frontiers_confirmation_info.max_elections, elections_count);
|
||||
confirm_expired_frontiers_pessimistically (transaction, frontiers_confirmation_info.max_elections, elections_count);
|
||||
set_next_frontier_check (frontiers_confirmation_info.aggressive_mode);
|
||||
}
|
||||
lock_a.lock ();
|
||||
}
|
||||
|
||||
/*
|
||||
* This function takes the expired_optimistic_election_infos generated from failed elections from frontiers confirmations and starts
|
||||
* confirming blocks at cemented height + 1 (cemented frontier successor) for an account only if all dependent blocks already
|
||||
* confirmed.
|
||||
*/
|
||||
void nano::active_transactions::confirm_expired_frontiers_pessimistically (nano::transaction const & transaction_a, uint64_t max_elections_a, uint64_t & elections_count_a)
|
||||
{
|
||||
auto i{ node.store.account.begin (transaction_a, next_frontier_account) };
|
||||
auto n{ node.store.account.end () };
|
||||
nano::timer<std::chrono::milliseconds> timer (nano::timer_state::started);
|
||||
nano::confirmation_height_info confirmation_height_info;
|
||||
|
||||
// Loop through any expired optimistic elections which have not been started yet. This tag stores already started ones first
|
||||
std::vector<nano::account> elections_started_for_account;
|
||||
for (auto i = expired_optimistic_election_infos.get<tag_election_started> ().lower_bound (false); i != expired_optimistic_election_infos.get<tag_election_started> ().end ();)
|
||||
{
|
||||
if (stopped || elections_count_a >= max_elections_a)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
auto const & account{ i->account };
|
||||
nano::account_info account_info;
|
||||
bool should_delete{ true };
|
||||
if (!node.store.account.get (transaction_a, account, account_info))
|
||||
{
|
||||
node.store.confirmation_height.get (transaction_a, account, confirmation_height_info);
|
||||
if (account_info.block_count > confirmation_height_info.height)
|
||||
{
|
||||
should_delete = false;
|
||||
std::shared_ptr<nano::block> previous_block;
|
||||
std::shared_ptr<nano::block> block;
|
||||
if (confirmation_height_info.height == 0)
|
||||
{
|
||||
block = node.store.block.get (transaction_a, account_info.open_block);
|
||||
}
|
||||
else
|
||||
{
|
||||
previous_block = node.store.block.get (transaction_a, confirmation_height_info.frontier);
|
||||
block = node.store.block.get (transaction_a, previous_block->sideband ().successor);
|
||||
}
|
||||
|
||||
if (block && !node.confirmation_height_processor.is_processing_block (block->hash ()) && node.ledger.dependents_confirmed (transaction_a, *block))
|
||||
{
|
||||
nano::uint128_t previous_balance{ 0 };
|
||||
if (previous_block && previous_block->balance ().is_zero ())
|
||||
{
|
||||
previous_balance = previous_block->sideband ().balance.number ();
|
||||
}
|
||||
|
||||
auto inserted_election = insert_election_from_frontiers_confirmation (block, account, previous_balance, nano::election_behavior::normal);
|
||||
if (inserted_election)
|
||||
{
|
||||
++elections_count_a;
|
||||
}
|
||||
elections_started_for_account.push_back (i->account);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (should_delete)
|
||||
{
|
||||
// This account is confirmed already or doesn't exist.
|
||||
i = expired_optimistic_election_infos.get<tag_election_started> ().erase (i);
|
||||
expired_optimistic_election_infos_size = expired_optimistic_election_infos.size ();
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const & account : elections_started_for_account)
|
||||
{
|
||||
auto it = expired_optimistic_election_infos.get<tag_account> ().find (account);
|
||||
debug_assert (it != expired_optimistic_election_infos.get<tag_account> ().end ());
|
||||
expired_optimistic_election_infos.get<tag_account> ().modify (it, [] (auto & expired_optimistic_election_info_a) {
|
||||
expired_optimistic_election_info_a.election_started = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool nano::active_transactions::should_do_frontiers_confirmation () const
|
||||
{
|
||||
auto pending_confirmation_height_size (confirmation_height_processor.awaiting_processing_size ());
|
||||
auto disabled_confirmation_mode = (node.config.frontiers_confirmation == nano::frontiers_confirmation_mode::disabled);
|
||||
auto conf_height_capacity_reached = pending_confirmation_height_size > confirmed_frontiers_max_pending_size;
|
||||
auto all_cemented = node.ledger.cache.block_count == node.ledger.cache.cemented_count;
|
||||
return (!disabled_confirmation_mode && !conf_height_capacity_reached && !all_cemented);
|
||||
}
|
||||
|
||||
void nano::active_transactions::request_loop ()
|
||||
{
|
||||
nano::unique_lock<nano::mutex> lock (mutex);
|
||||
|
|
@ -617,184 +341,6 @@ void nano::active_transactions::request_loop ()
|
|||
}
|
||||
}
|
||||
|
||||
bool nano::active_transactions::prioritize_account_for_confirmation (nano::active_transactions::prioritize_num_uncemented & cementable_frontiers_a, std::size_t & cementable_frontiers_size_a, nano::account const & account_a, nano::account_info const & info_a, uint64_t confirmation_height_a)
|
||||
{
|
||||
auto inserted_new{ false };
|
||||
if (info_a.block_count > confirmation_height_a && !confirmation_height_processor.is_processing_block (info_a.head))
|
||||
{
|
||||
auto num_uncemented = info_a.block_count - confirmation_height_a;
|
||||
nano::lock_guard<nano::mutex> guard (mutex);
|
||||
auto it = cementable_frontiers_a.get<tag_account> ().find (account_a);
|
||||
if (it != cementable_frontiers_a.get<tag_account> ().end ())
|
||||
{
|
||||
if (it->blocks_uncemented != num_uncemented)
|
||||
{
|
||||
// Account already exists and there is now a different uncemented block count so update it in the container
|
||||
cementable_frontiers_a.get<tag_account> ().modify (it, [num_uncemented] (nano::cementable_account & info) {
|
||||
info.blocks_uncemented = num_uncemented;
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_assert (cementable_frontiers_size_a <= max_priority_cementable_frontiers);
|
||||
if (cementable_frontiers_size_a == max_priority_cementable_frontiers)
|
||||
{
|
||||
// The maximum amount of frontiers stored has been reached. Check if the current frontier
|
||||
// has more uncemented blocks than the lowest uncemented frontier in the collection if so replace it.
|
||||
auto least_uncemented_frontier_it = cementable_frontiers_a.get<tag_uncemented> ().end ();
|
||||
--least_uncemented_frontier_it;
|
||||
if (num_uncemented > least_uncemented_frontier_it->blocks_uncemented)
|
||||
{
|
||||
cementable_frontiers_a.get<tag_uncemented> ().erase (least_uncemented_frontier_it);
|
||||
cementable_frontiers_a.get<tag_account> ().emplace (account_a, num_uncemented);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
inserted_new = true;
|
||||
cementable_frontiers_a.get<tag_account> ().emplace (account_a, num_uncemented);
|
||||
}
|
||||
}
|
||||
cementable_frontiers_size_a = cementable_frontiers_a.size ();
|
||||
}
|
||||
return inserted_new;
|
||||
}
|
||||
|
||||
void nano::active_transactions::prioritize_frontiers_for_confirmation (nano::transaction const & transaction_a, std::chrono::milliseconds ledger_account_traversal_max_time_a, std::chrono::milliseconds wallet_account_traversal_max_time_a)
|
||||
{
|
||||
// Don't try to prioritize when there are a large number of pending confirmation heights as blocks can be cemented in the meantime, making the prioritization less reliable
|
||||
if (confirmation_height_processor.awaiting_processing_size () < confirmed_frontiers_max_pending_size)
|
||||
{
|
||||
std::size_t priority_cementable_frontiers_size;
|
||||
std::size_t priority_wallet_cementable_frontiers_size;
|
||||
{
|
||||
nano::lock_guard<nano::mutex> guard (mutex);
|
||||
priority_cementable_frontiers_size = priority_cementable_frontiers.size ();
|
||||
priority_wallet_cementable_frontiers_size = priority_wallet_cementable_frontiers.size ();
|
||||
}
|
||||
|
||||
nano::timer<std::chrono::milliseconds> wallet_account_timer (nano::timer_state::started);
|
||||
// Remove any old expired optimistic elections so they are no longer excluded in subsequent checks
|
||||
auto expired_cutoff_it (expired_optimistic_election_infos.get<tag_expired_time> ().lower_bound (std::chrono::steady_clock::now () - expired_optimistic_election_info_cutoff));
|
||||
expired_optimistic_election_infos.get<tag_expired_time> ().erase (expired_optimistic_election_infos.get<tag_expired_time> ().begin (), expired_cutoff_it);
|
||||
expired_optimistic_election_infos_size = expired_optimistic_election_infos.size ();
|
||||
|
||||
auto num_new_inserted{ 0u };
|
||||
auto should_iterate = [this, &num_new_inserted] () {
|
||||
auto max_optimistic_l = max_optimistic ();
|
||||
return !stopped && (max_optimistic_l > optimistic_elections_count && max_optimistic_l - optimistic_elections_count > num_new_inserted);
|
||||
};
|
||||
|
||||
if (!skip_wallets)
|
||||
{
|
||||
// Prioritize wallet accounts first
|
||||
{
|
||||
nano::lock_guard<nano::mutex> lock (node.wallets.mutex);
|
||||
auto wallet_transaction (node.wallets.tx_begin_read ());
|
||||
auto const & items = node.wallets.items;
|
||||
if (items.empty ())
|
||||
{
|
||||
skip_wallets = true;
|
||||
}
|
||||
for (auto item_it = items.cbegin (); item_it != items.cend () && should_iterate (); ++item_it)
|
||||
{
|
||||
// Skip this wallet if it has been traversed already while there are others still awaiting
|
||||
if (wallet_ids_already_iterated.find (item_it->first) != wallet_ids_already_iterated.end ())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
nano::account_info info;
|
||||
auto & wallet (item_it->second);
|
||||
nano::lock_guard<std::recursive_mutex> wallet_lock (wallet->store.mutex);
|
||||
|
||||
auto & next_wallet_frontier_account = next_wallet_id_accounts.emplace (item_it->first, wallet_store::special_count).first->second;
|
||||
|
||||
auto i (wallet->store.begin (wallet_transaction, next_wallet_frontier_account));
|
||||
auto n (wallet->store.end ());
|
||||
for (; i != n && should_iterate (); ++i)
|
||||
{
|
||||
auto const & account (i->first);
|
||||
if (expired_optimistic_election_infos.get<tag_account> ().count (account) == 0 && !node.store.account.get (transaction_a, account, info))
|
||||
{
|
||||
nano::confirmation_height_info confirmation_height_info;
|
||||
node.store.confirmation_height.get (transaction_a, account, confirmation_height_info);
|
||||
// If it exists in normal priority collection delete from there.
|
||||
auto it = priority_cementable_frontiers.find (account);
|
||||
if (it != priority_cementable_frontiers.end ())
|
||||
{
|
||||
nano::lock_guard<nano::mutex> guard (mutex);
|
||||
priority_cementable_frontiers.erase (it);
|
||||
priority_cementable_frontiers_size = priority_cementable_frontiers.size ();
|
||||
}
|
||||
|
||||
auto insert_newed = prioritize_account_for_confirmation (priority_wallet_cementable_frontiers, priority_wallet_cementable_frontiers_size, account, info, confirmation_height_info.height);
|
||||
if (insert_newed)
|
||||
{
|
||||
++num_new_inserted;
|
||||
}
|
||||
|
||||
if (wallet_account_timer.since_start () >= wallet_account_traversal_max_time_a)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
next_wallet_frontier_account = account.number () + 1;
|
||||
}
|
||||
// Go back to the beginning when we have reached the end of the wallet accounts for this wallet
|
||||
if (i == n)
|
||||
{
|
||||
wallet_ids_already_iterated.emplace (item_it->first);
|
||||
next_wallet_id_accounts.at (item_it->first) = wallet_store::special_count;
|
||||
|
||||
// Skip wallet accounts when they have all been traversed
|
||||
if (std::next (item_it) == items.cend ())
|
||||
{
|
||||
wallet_ids_already_iterated.clear ();
|
||||
skip_wallets = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nano::timer<std::chrono::milliseconds> timer (nano::timer_state::started);
|
||||
auto i (node.store.account.begin (transaction_a, next_frontier_account));
|
||||
auto n (node.store.account.end ());
|
||||
for (; i != n && should_iterate (); ++i)
|
||||
{
|
||||
auto const & account (i->first);
|
||||
auto const & info (i->second);
|
||||
if (priority_wallet_cementable_frontiers.find (account) == priority_wallet_cementable_frontiers.end ())
|
||||
{
|
||||
if (expired_optimistic_election_infos.get<tag_account> ().count (account) == 0)
|
||||
{
|
||||
nano::confirmation_height_info confirmation_height_info;
|
||||
node.store.confirmation_height.get (transaction_a, account, confirmation_height_info);
|
||||
auto insert_newed = prioritize_account_for_confirmation (priority_cementable_frontiers, priority_cementable_frontiers_size, account, info, confirmation_height_info.height);
|
||||
if (insert_newed)
|
||||
{
|
||||
++num_new_inserted;
|
||||
}
|
||||
}
|
||||
}
|
||||
next_frontier_account = account.number () + 1;
|
||||
if (timer.since_start () >= ledger_account_traversal_max_time_a)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Go back to the beginning when we have reached the end of the accounts and start with wallet accounts next time
|
||||
if (i == n)
|
||||
{
|
||||
next_frontier_account = 0;
|
||||
skip_wallets = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nano::active_transactions::stop ()
|
||||
{
|
||||
nano::unique_lock<nano::mutex> lock (mutex);
|
||||
|
|
@ -830,14 +376,13 @@ nano::election_insertion_result nano::active_transactions::insert_impl (nano::un
|
|||
{
|
||||
result.inserted = true;
|
||||
auto hash (block_a->hash ());
|
||||
auto epoch (block_a->sideband ().details.epoch);
|
||||
result.election = nano::make_shared<nano::election> (
|
||||
node, block_a, confirmation_action_a, [&node = node] (auto const & rep_a) {
|
||||
// Representative is defined as online if replying to live votes or rep_crawler queries
|
||||
node.online_reps.observe (rep_a);
|
||||
},
|
||||
election_behavior_a);
|
||||
roots.get<tag_root> ().emplace (nano::active_transactions::conflict_info{ root, result.election, epoch, election_behavior_a });
|
||||
roots.get<tag_root> ().emplace (nano::active_transactions::conflict_info{ root, result.election });
|
||||
blocks.emplace (hash, result.election);
|
||||
// Increase hinted election counter while still holding lock
|
||||
if (election_behavior_a == election_behavior::hinted)
|
||||
|
|
@ -1126,18 +671,6 @@ boost::optional<nano::election_status_type> nano::active_transactions::confirm_b
|
|||
return status_type;
|
||||
}
|
||||
|
||||
std::size_t nano::active_transactions::priority_cementable_frontiers_size ()
|
||||
{
|
||||
nano::lock_guard<nano::mutex> guard (mutex);
|
||||
return priority_cementable_frontiers.size ();
|
||||
}
|
||||
|
||||
std::size_t nano::active_transactions::priority_wallet_cementable_frontiers_size ()
|
||||
{
|
||||
nano::lock_guard<nano::mutex> guard (mutex);
|
||||
return priority_wallet_cementable_frontiers.size ();
|
||||
}
|
||||
|
||||
std::size_t nano::active_transactions::inactive_votes_cache_size ()
|
||||
{
|
||||
nano::lock_guard<nano::mutex> guard (mutex);
|
||||
|
|
@ -1341,17 +874,6 @@ nano::cementable_account::cementable_account (nano::account const & account_a, s
|
|||
{
|
||||
}
|
||||
|
||||
nano::expired_optimistic_election_info::expired_optimistic_election_info (std::chrono::steady_clock::time_point expired_time_a, nano::account account_a) :
|
||||
expired_time (expired_time_a),
|
||||
account (account_a)
|
||||
{
|
||||
}
|
||||
|
||||
bool nano::frontiers_confirmation_info::can_start_elections () const
|
||||
{
|
||||
return max_elections > 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<nano::container_info_component> nano::collect_container_info (active_transactions & active_transactions, std::string const & name)
|
||||
{
|
||||
std::size_t roots_count;
|
||||
|
|
@ -1373,11 +895,7 @@ std::unique_ptr<nano::container_info_component> nano::collect_container_info (ac
|
|||
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "election_winner_details", active_transactions.election_winner_details_size (), sizeof (decltype (active_transactions.election_winner_details)::value_type) }));
|
||||
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "recently_confirmed", recently_confirmed_count, sizeof (decltype (active_transactions.recently_confirmed)::value_type) }));
|
||||
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "recently_cemented", recently_cemented_count, sizeof (decltype (active_transactions.recently_cemented)::value_type) }));
|
||||
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "priority_wallet_cementable_frontiers", active_transactions.priority_wallet_cementable_frontiers_size (), sizeof (nano::cementable_account) }));
|
||||
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "priority_cementable_frontiers", active_transactions.priority_cementable_frontiers_size (), sizeof (nano::cementable_account) }));
|
||||
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "expired_optimistic_election_infos", active_transactions.expired_optimistic_election_infos_size, sizeof (decltype (active_transactions.expired_optimistic_election_infos)::value_type) }));
|
||||
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "inactive_votes_cache", active_transactions.inactive_votes_cache_size (), sizeof (nano::gap_information) }));
|
||||
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "optimistic_elections_count", active_transactions.optimistic_elections_count, 0 })); // This isn't an extra container, is just to expose the count easily
|
||||
composite->add_component (collect_container_info (active_transactions.generator, "generator"));
|
||||
return composite;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,32 +46,6 @@ public:
|
|||
uint64_t blocks_uncemented{ 0 };
|
||||
};
|
||||
|
||||
class election_timepoint final
|
||||
{
|
||||
public:
|
||||
std::chrono::steady_clock::time_point time;
|
||||
nano::qualified_root root;
|
||||
};
|
||||
|
||||
class expired_optimistic_election_info final
|
||||
{
|
||||
public:
|
||||
expired_optimistic_election_info (std::chrono::steady_clock::time_point, nano::account);
|
||||
|
||||
std::chrono::steady_clock::time_point expired_time;
|
||||
nano::account account;
|
||||
bool election_started{ false };
|
||||
};
|
||||
|
||||
class frontiers_confirmation_info
|
||||
{
|
||||
public:
|
||||
bool can_start_elections () const;
|
||||
|
||||
std::size_t max_elections{ 0 };
|
||||
bool aggressive_mode{ false };
|
||||
};
|
||||
|
||||
class election_insertion_result final
|
||||
{
|
||||
public:
|
||||
|
|
@ -88,8 +62,6 @@ class active_transactions final
|
|||
public:
|
||||
nano::qualified_root root;
|
||||
std::shared_ptr<nano::election> election;
|
||||
nano::epoch epoch;
|
||||
nano::election_behavior election_behavior; // Used to prioritize portion of AEC for vote hinting
|
||||
};
|
||||
|
||||
friend class nano::election;
|
||||
|
|
@ -102,8 +74,6 @@ class active_transactions final
|
|||
class tag_uncemented {};
|
||||
class tag_arrival {};
|
||||
class tag_hash {};
|
||||
class tag_expired_time {};
|
||||
class tag_election_started {};
|
||||
// clang-format on
|
||||
|
||||
public:
|
||||
|
|
@ -159,8 +129,6 @@ public:
|
|||
nano::confirmation_height_processor & confirmation_height_processor;
|
||||
nano::node & node;
|
||||
mutable nano::mutex mutex{ mutex_identifier (mutexes::active) };
|
||||
std::size_t priority_cementable_frontiers_size ();
|
||||
std::size_t priority_wallet_cementable_frontiers_size ();
|
||||
std::size_t inactive_votes_cache_size ();
|
||||
std::size_t election_winner_details_size ();
|
||||
void add_election_winner_details (nano::block_hash const &, std::shared_ptr<nano::election> const &);
|
||||
|
|
@ -220,51 +188,10 @@ private:
|
|||
mi::hashed_unique<mi::tag<tag_hash>,
|
||||
mi::member<recent_confirmation, nano::block_hash, &recent_confirmation::second>>>>
|
||||
recently_confirmed;
|
||||
using prioritize_num_uncemented = boost::multi_index_container<nano::cementable_account,
|
||||
mi::indexed_by<
|
||||
mi::hashed_unique<mi::tag<tag_account>,
|
||||
mi::member<nano::cementable_account, nano::account, &nano::cementable_account::account>>,
|
||||
mi::ordered_non_unique<mi::tag<tag_uncemented>,
|
||||
mi::member<nano::cementable_account, uint64_t, &nano::cementable_account::blocks_uncemented>,
|
||||
std::greater<uint64_t>>>>;
|
||||
|
||||
boost::multi_index_container<nano::expired_optimistic_election_info,
|
||||
mi::indexed_by<
|
||||
mi::ordered_non_unique<mi::tag<tag_expired_time>,
|
||||
mi::member<expired_optimistic_election_info, std::chrono::steady_clock::time_point, &expired_optimistic_election_info::expired_time>>,
|
||||
mi::hashed_unique<mi::tag<tag_account>,
|
||||
mi::member<expired_optimistic_election_info, nano::account, &expired_optimistic_election_info::account>>,
|
||||
mi::ordered_non_unique<mi::tag<tag_election_started>,
|
||||
mi::member<expired_optimistic_election_info, bool, &expired_optimistic_election_info::election_started>, std::greater<bool>>>>
|
||||
expired_optimistic_election_infos;
|
||||
// clang-format on
|
||||
std::atomic<uint64_t> expired_optimistic_election_infos_size{ 0 };
|
||||
|
||||
int active_hinted_elections_count{ 0 };
|
||||
|
||||
// Frontiers confirmation
|
||||
nano::frontiers_confirmation_info get_frontiers_confirmation_info ();
|
||||
void confirm_prioritized_frontiers (nano::transaction const &, uint64_t, uint64_t &);
|
||||
void confirm_expired_frontiers_pessimistically (nano::transaction const &, uint64_t, uint64_t &);
|
||||
void frontiers_confirmation (nano::unique_lock<nano::mutex> &);
|
||||
bool insert_election_from_frontiers_confirmation (std::shared_ptr<nano::block> const &, nano::account const &, nano::uint128_t, nano::election_behavior);
|
||||
nano::account next_frontier_account{};
|
||||
std::chrono::steady_clock::time_point next_frontier_check{ std::chrono::steady_clock::now () };
|
||||
constexpr static std::size_t max_active_elections_frontier_insertion{ 1000 };
|
||||
prioritize_num_uncemented priority_wallet_cementable_frontiers;
|
||||
prioritize_num_uncemented priority_cementable_frontiers;
|
||||
std::unordered_set<nano::wallet_id> wallet_ids_already_iterated;
|
||||
std::unordered_map<nano::wallet_id, nano::account> next_wallet_id_accounts;
|
||||
bool skip_wallets{ false };
|
||||
std::atomic<unsigned> optimistic_elections_count{ 0 };
|
||||
void prioritize_frontiers_for_confirmation (nano::transaction const &, std::chrono::milliseconds, std::chrono::milliseconds);
|
||||
bool prioritize_account_for_confirmation (prioritize_num_uncemented &, std::size_t &, nano::account const &, nano::account_info const &, uint64_t);
|
||||
unsigned max_optimistic ();
|
||||
void set_next_frontier_check (bool);
|
||||
void add_expired_optimistic_election (nano::election const &);
|
||||
bool should_do_frontiers_confirmation () const;
|
||||
static std::size_t constexpr max_priority_cementable_frontiers{ 100000 };
|
||||
static std::size_t constexpr confirmed_frontiers_max_pending_size{ 10000 };
|
||||
static std::chrono::minutes constexpr expired_optimistic_election_info_cutoff{ 30 };
|
||||
ordered_cache inactive_votes_cache;
|
||||
nano::inactive_cache_status inactive_votes_bootstrap_check (nano::unique_lock<nano::mutex> &, std::vector<std::pair<nano::account, uint64_t>> const &, nano::block_hash const &, nano::inactive_cache_status const &);
|
||||
nano::inactive_cache_status inactive_votes_bootstrap_check (nano::unique_lock<nano::mutex> &, nano::account const &, nano::block_hash const &, nano::inactive_cache_status const &);
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ bool nano::election::state_change (nano::election::state_t expected_a, nano::ele
|
|||
|
||||
void nano::election::send_confirm_req (nano::confirmation_solicitor & solicitor_a)
|
||||
{
|
||||
if ((base_latency () * (optimistic () ? 10 : 5)) < (std::chrono::steady_clock::now () - last_req))
|
||||
if ((base_latency () * 5) < (std::chrono::steady_clock::now () - last_req))
|
||||
{
|
||||
nano::lock_guard<nano::mutex> guard (mutex);
|
||||
if (!solicitor_a.add (*this))
|
||||
|
|
@ -218,11 +218,10 @@ std::chrono::milliseconds nano::election::time_to_live ()
|
|||
{
|
||||
case election_behavior::normal:
|
||||
return std::chrono::milliseconds (5 * 60 * 1000);
|
||||
case election_behavior::optimistic:
|
||||
return std::chrono::milliseconds (node.network_params.network.is_dev_network () ? 500 : 60 * 1000);
|
||||
case election_behavior::hinted:
|
||||
return std::chrono::milliseconds (30 * 1000);
|
||||
}
|
||||
release_assert (false);
|
||||
}
|
||||
|
||||
bool nano::election::have_quorum (nano::tally_t const & tally_a) const
|
||||
|
|
@ -480,11 +479,6 @@ std::size_t nano::election::insert_inactive_votes_cache (nano::inactive_cache_in
|
|||
return cache_a.voters.size ();
|
||||
}
|
||||
|
||||
bool nano::election::optimistic () const
|
||||
{
|
||||
return behavior == nano::election_behavior::optimistic;
|
||||
}
|
||||
|
||||
nano::election_extended_status nano::election::current_status () const
|
||||
{
|
||||
nano::lock_guard<nano::mutex> guard (mutex);
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ public:
|
|||
enum class election_behavior
|
||||
{
|
||||
normal,
|
||||
optimistic,
|
||||
hinted
|
||||
};
|
||||
struct election_extended_status final
|
||||
|
|
@ -90,7 +89,6 @@ public: // State transitions
|
|||
public: // Status
|
||||
bool confirmed () const;
|
||||
bool failed () const;
|
||||
bool optimistic () const;
|
||||
nano::election_extended_status current_status () const;
|
||||
std::shared_ptr<nano::block> winner () const;
|
||||
std::atomic<unsigned> confirmation_request_count{ 0 };
|
||||
|
|
|
|||
|
|
@ -1352,133 +1352,6 @@ TEST (confirmation_height, many_accounts_send_receive_self_no_elections)
|
|||
ASSERT_EQ (cemented_count, ledger.cache.cemented_count);
|
||||
}
|
||||
|
||||
// Can take up to 1 hour (recommend modifying test work difficulty base level to speed this up)
|
||||
TEST (confirmation_height, prioritize_frontiers_overwrite)
|
||||
{
|
||||
nano::system system;
|
||||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
|
||||
auto node = system.add_node (node_config);
|
||||
system.wallet (0)->insert_adhoc (nano::dev::genesis_key.prv);
|
||||
|
||||
auto num_accounts = node->active.max_priority_cementable_frontiers * 2;
|
||||
nano::keypair last_keypair = nano::dev::genesis_key;
|
||||
auto last_open_hash = node->latest (nano::dev::genesis_key.pub);
|
||||
// Clear confirmation height so that the genesis account has the same amount of uncemented blocks as the other frontiers
|
||||
{
|
||||
auto transaction = node->store.tx_begin_write ();
|
||||
node->store.confirmation_height.clear (transaction);
|
||||
}
|
||||
|
||||
nano::block_builder builder;
|
||||
{
|
||||
auto transaction = node->store.tx_begin_write ();
|
||||
for (auto i = num_accounts - 1; i > 0; --i)
|
||||
{
|
||||
nano::keypair key;
|
||||
system.wallet (0)->insert_adhoc (key.prv);
|
||||
|
||||
auto send = builder
|
||||
.send ()
|
||||
.previous (last_open_hash)
|
||||
.destination (key.pub)
|
||||
.balance (nano::Gxrb_ratio - 1)
|
||||
.sign (last_keypair.prv, last_keypair.pub)
|
||||
.work (*system.work.generate (last_open_hash))
|
||||
.build ();
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send).code);
|
||||
auto open = builder
|
||||
.open ()
|
||||
.source (send->hash ())
|
||||
.representative (last_keypair.pub)
|
||||
.account (key.pub)
|
||||
.sign (key.prv, key.pub)
|
||||
.work (*system.work.generate (key.pub))
|
||||
.build ();
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *open).code);
|
||||
last_open_hash = open->hash ();
|
||||
last_keypair = key;
|
||||
}
|
||||
}
|
||||
|
||||
auto transaction = node->store.tx_begin_read ();
|
||||
{
|
||||
// Fill both priority frontier collections.
|
||||
node->active.prioritize_frontiers_for_confirmation (transaction, std::chrono::seconds (60), std::chrono::seconds (60));
|
||||
ASSERT_EQ (node->active.priority_cementable_frontiers_size () + node->active.priority_wallet_cementable_frontiers_size (), num_accounts);
|
||||
|
||||
// Confirm the last frontier has the least number of uncemented blocks
|
||||
auto last_frontier_it = node->active.priority_cementable_frontiers.get<1> ().end ();
|
||||
--last_frontier_it;
|
||||
ASSERT_EQ (last_frontier_it->account, last_keypair.pub);
|
||||
ASSERT_EQ (last_frontier_it->blocks_uncemented, 1);
|
||||
}
|
||||
|
||||
// Add a new frontier with 1 block, it should not be added to the frontier container because it is not higher than any already in the maxed out container
|
||||
nano::keypair key;
|
||||
auto latest_genesis = node->latest (nano::dev::genesis_key.pub);
|
||||
auto send = builder
|
||||
.send ()
|
||||
.previous (latest_genesis)
|
||||
.destination (key.pub)
|
||||
.balance (nano::Gxrb_ratio - 1)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*system.work.generate (latest_genesis))
|
||||
.build ();
|
||||
auto open = builder
|
||||
.open ()
|
||||
.source (send->hash ())
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.account (key.pub)
|
||||
.sign (key.prv, key.pub)
|
||||
.work (*system.work.generate (key.pub))
|
||||
.build ();
|
||||
{
|
||||
auto transaction = node->store.tx_begin_write ();
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *open).code);
|
||||
}
|
||||
transaction.refresh ();
|
||||
node->active.prioritize_frontiers_for_confirmation (transaction, std::chrono::seconds (60), std::chrono::seconds (60));
|
||||
ASSERT_EQ (node->active.priority_cementable_frontiers_size (), num_accounts / 2);
|
||||
ASSERT_EQ (node->active.priority_wallet_cementable_frontiers_size (), num_accounts / 2);
|
||||
|
||||
// The account now has an extra block (2 in total) so has 1 more uncemented block than the next smallest frontier in the collection.
|
||||
auto send1 = builder
|
||||
.send ()
|
||||
.previous (send->hash ())
|
||||
.destination (key.pub)
|
||||
.balance (nano::Gxrb_ratio - 2)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*system.work.generate (send->hash ()))
|
||||
.build ();
|
||||
auto receive = builder
|
||||
.receive ()
|
||||
.previous (open->hash ())
|
||||
.source (send1->hash ())
|
||||
.sign (key.prv, key.pub)
|
||||
.work (*system.work.generate (open->hash ()))
|
||||
.build ();
|
||||
{
|
||||
auto transaction = node->store.tx_begin_write ();
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send1).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *receive).code);
|
||||
}
|
||||
|
||||
// Confirm that it gets replaced
|
||||
transaction.refresh ();
|
||||
node->active.prioritize_frontiers_for_confirmation (transaction, std::chrono::seconds (60), std::chrono::seconds (60));
|
||||
ASSERT_EQ (node->active.priority_cementable_frontiers_size (), num_accounts / 2);
|
||||
ASSERT_EQ (node->active.priority_wallet_cementable_frontiers_size (), num_accounts / 2);
|
||||
ASSERT_EQ (node->active.priority_cementable_frontiers.find (last_keypair.pub), node->active.priority_cementable_frontiers.end ());
|
||||
ASSERT_NE (node->active.priority_cementable_frontiers.find (key.pub), node->active.priority_cementable_frontiers.end ());
|
||||
|
||||
// Check there are no matching accounts found in both containers
|
||||
for (auto it = node->active.priority_cementable_frontiers.begin (); it != node->active.priority_cementable_frontiers.end (); ++it)
|
||||
{
|
||||
ASSERT_EQ (node->active.priority_wallet_cementable_frontiers.find (it->account), node->active.priority_wallet_cementable_frontiers.end ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue