Remove election fallback behaviors and adjusted multiplier calculations (#2891)

* Remove election fallback behaviors and adjusted multiplier calculations

Removes backtracking and dependency activation. The move to sequential elections also allows removing the adjusted multiplier from chains.

Frontier successor insertion (https://github.com/nanocurrency/nano-node/pull/2885) is the new fallback behavior which does not escalate.

* Fix node.block_confirm which relied on activating dependencies
This commit is contained in:
Guilherme Lawless 2020-08-25 11:27:02 +01:00 committed by GitHub
commit ee85e1cc8e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 16 additions and 978 deletions

View file

@ -99,166 +99,6 @@ TEST (active_transactions, confirm_frontier)
}
}
TEST (active_transactions, adjusted_multiplier_priority)
{
nano::system system;
nano::node_config node_config (nano::get_available_port (), system.logging);
node_config.enable_voting = false;
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto & node1 = *system.add_node (node_config);
nano::keypair key1, key2, key3;
nano::state_block_builder builder;
auto send1 = builder.make_block ()
.account (nano::dev_genesis_key.pub)
.previous (nano::genesis_hash)
.representative (nano::dev_genesis_key.pub)
.balance (nano::genesis_amount - 10 * nano::xrb_ratio)
.link (key1.pub)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (nano::genesis_hash))
.build_shared ();
auto send2 = builder.make_block ()
.account (nano::dev_genesis_key.pub)
.previous (send1->hash ())
.representative (nano::dev_genesis_key.pub)
.balance (nano::genesis_amount - 20 * nano::xrb_ratio)
.link (key2.pub)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (send1->hash ()))
.build_shared ();
auto open1 = builder.make_block ()
.account (key1.pub)
.previous (0)
.representative (key1.pub)
.balance (10 * nano::xrb_ratio)
.link (send1->hash ())
.sign (key1.prv, key1.pub)
.work (*system.work.generate (key1.pub))
.build_shared ();
auto open2 = builder.make_block ()
.account (key2.pub)
.previous (0)
.representative (key2.pub)
.balance (10 * nano::xrb_ratio)
.link (send2->hash ())
.sign (key2.prv, key2.pub)
.work (*system.work.generate (key2.pub))
.build_shared ();
node1.process_active (send1); // genesis
node1.process_active (send2); // genesis
node1.process_active (open1); // key1
node1.process_active (open2); // key2
nano::blocks_confirm (node1, { send1, send2, open1, open2 });
ASSERT_TIMELY (10s, node1.active.size () == 4);
// Check adjusted difficulty
{
nano::lock_guard<std::mutex> active_guard (node1.active.mutex);
node1.active.update_adjusted_multiplier ();
ASSERT_EQ (node1.active.roots.get<1> ().begin ()->election->status.winner->hash (), send1->hash ());
ASSERT_LT (node1.active.roots.find (send2->qualified_root ())->adjusted_multiplier, node1.active.roots.find (send1->qualified_root ())->adjusted_multiplier);
ASSERT_LT (node1.active.roots.find (open1->qualified_root ())->adjusted_multiplier, node1.active.roots.find (send1->qualified_root ())->adjusted_multiplier);
ASSERT_LT (node1.active.roots.find (open2->qualified_root ())->adjusted_multiplier, node1.active.roots.find (send2->qualified_root ())->adjusted_multiplier);
}
// Confirm elections
system.deadline_set (10s);
while (!node1.active.empty ())
{
nano::lock_guard<std::mutex> active_guard (node1.active.mutex);
if (!node1.active.roots.empty ())
{
node1.active.roots.begin ()->election->confirm_once ();
}
}
ASSERT_TIMELY (10s, node1.ledger.cache.cemented_count == 5 && node1.active.empty ());
//genesis and key1,key2 are opened
//start chain of 2 on each
auto send3 = builder.make_block ()
.account (nano::dev_genesis_key.pub)
.previous (send2->hash ())
.representative (nano::dev_genesis_key.pub)
.balance (9 * nano::xrb_ratio)
.link (key3.pub)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (send2->hash (), nano::difficulty::from_multiplier (150, node1.network_params.network.publish_thresholds.base)))
.build_shared ();
auto send4 = builder.make_block ()
.account (nano::dev_genesis_key.pub)
.previous (send3->hash ())
.representative (nano::dev_genesis_key.pub)
.balance (8 * nano::xrb_ratio)
.link (key3.pub)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (send3->hash (), nano::difficulty::from_multiplier (150, node1.network_params.network.publish_thresholds.base)))
.build_shared ();
auto send5 = builder.make_block ()
.account (key1.pub)
.previous (open1->hash ())
.representative (key1.pub)
.balance (9 * nano::xrb_ratio)
.link (key3.pub)
.sign (key1.prv, key1.pub)
.work (system.work_generate_limited (open1->hash (), nano::difficulty::from_multiplier (10, node1.network_params.network.publish_thresholds.base), nano::difficulty::from_multiplier (50, node1.network_params.network.publish_thresholds.base)))
.build_shared ();
auto send6 = builder.make_block ()
.account (key1.pub)
.previous (send5->hash ())
.representative (key1.pub)
.balance (8 * nano::xrb_ratio)
.link (key3.pub)
.sign (key1.prv, key1.pub)
.work (system.work_generate_limited (send5->hash (), nano::difficulty::from_multiplier (10, node1.network_params.network.publish_thresholds.base), nano::difficulty::from_multiplier (50, node1.network_params.network.publish_thresholds.base)))
.build_shared ();
auto send7 = builder.make_block ()
.account (key2.pub)
.previous (open2->hash ())
.representative (key2.pub)
.balance (9 * nano::xrb_ratio)
.link (key3.pub)
.sign (key2.prv, key2.pub)
.work (system.work_generate_limited (open2->hash (), nano::difficulty::from_multiplier (50, node1.network_params.network.publish_thresholds.base), nano::difficulty::from_multiplier (150, node1.network_params.network.publish_thresholds.base)))
.build_shared ();
auto send8 = builder.make_block ()
.account (key2.pub)
.previous (send7->hash ())
.representative (key2.pub)
.balance (8 * nano::xrb_ratio)
.link (key3.pub)
.sign (key2.prv, key2.pub)
.work (system.work_generate_limited (send7->hash (), nano::difficulty::from_multiplier (50, node1.network_params.network.publish_thresholds.base), nano::difficulty::from_multiplier (150, node1.network_params.network.publish_thresholds.base)))
.build_shared ();
node1.process_active (send3); // genesis
node1.process_active (send5); // key1
node1.process_active (send7); // key2
node1.process_active (send4); // genesis
node1.process_active (send6); // key1
node1.process_active (send8); // key2
nano::blocks_confirm (node1, { send3, send4, send5, send6, send7, send8 });
ASSERT_TIMELY (10s, node1.active.size () == 6);
// Check adjusted difficulty
nano::lock_guard<std::mutex> lock (node1.active.mutex);
node1.active.update_adjusted_multiplier ();
double last_adjusted (0.0);
for (auto i (node1.active.roots.get<1> ().begin ()), n (node1.active.roots.get<1> ().end ()); i != n; ++i)
{
//first root has nothing to compare
if (last_adjusted != 0.0)
{
ASSERT_LE (i->adjusted_multiplier, last_adjusted);
}
last_adjusted = i->adjusted_multiplier;
}
ASSERT_LT (node1.active.roots.find (send4->qualified_root ())->adjusted_multiplier, node1.active.roots.find (send3->qualified_root ())->adjusted_multiplier);
ASSERT_LT (node1.active.roots.find (send6->qualified_root ())->adjusted_multiplier, node1.active.roots.find (send5->qualified_root ())->adjusted_multiplier);
ASSERT_LT (node1.active.roots.find (send8->qualified_root ())->adjusted_multiplier, node1.active.roots.find (send7->qualified_root ())->adjusted_multiplier);
}
TEST (active_transactions, keep_local)
{
nano::system system;
@ -328,129 +168,6 @@ TEST (active_transactions, keep_local)
ASSERT_EQ (1, node.stats.count (nano::stat::type::election, nano::stat::detail::election_drop));
}
TEST (active_transactions, prioritize_chains)
{
nano::system system;
nano::node_config node_config (nano::get_available_port (), system.logging);
node_config.enable_voting = false;
node_config.active_elections_size = 4; //bound to 4, wont drop wallet created transactions, but good to test dropping remote
// Disable frontier confirmation to allow the test to finish before
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto & node1 = *system.add_node (node_config);
nano::genesis genesis;
nano::keypair key1, key2, key3;
nano::state_block_builder builder;
auto send1 = builder.make_block ()
.account (nano::dev_genesis_key.pub)
.previous (genesis.hash ())
.representative (nano::dev_genesis_key.pub)
.balance (nano::genesis_amount - 10 * nano::xrb_ratio)
.link (key1.pub)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (genesis.hash ()))
.build_shared ();
auto open1 = builder.make_block ()
.account (key1.pub)
.previous (0)
.representative (key1.pub)
.balance (10 * nano::xrb_ratio)
.link (send1->hash ())
.sign (key1.prv, key1.pub)
.work (*system.work.generate (key1.pub))
.build_shared ();
auto send2 = builder.make_block ()
.account (key1.pub)
.previous (open1->hash ())
.representative (key1.pub)
.balance (9 * nano::xrb_ratio)
.link (key2.pub)
.sign (key1.prv, key1.pub)
.work (*system.work.generate (open1->hash ()))
.build_shared ();
auto send3 = builder.make_block ()
.from (*send2)
.previous (send2->hash ())
.balance (8 * nano::xrb_ratio)
.sign (key1.prv, key1.pub)
.work (*system.work.generate (send2->hash ()))
.build_shared ();
auto send4 = builder.make_block ()
.from (*send3)
.previous (send3->hash ())
.balance (7 * nano::xrb_ratio)
.sign (key1.prv, key1.pub)
.work (*system.work.generate (send3->hash ()))
.build_shared ();
auto send5 = builder.make_block ()
.from (*send1)
.previous (send1->hash ())
.balance (nano::genesis_amount - 20 * nano::xrb_ratio)
.link (key2.pub)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (send1->hash ()))
.build_shared ();
auto send6 = builder.make_block ()
.from (*send5)
.previous (send5->hash ())
.balance (nano::genesis_amount - 30 * nano::xrb_ratio)
.link (key3.pub)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (send5->hash ()))
.build_shared ();
auto open2 = builder.make_block ()
.account (key2.pub)
.previous (0)
.representative (key2.pub)
.balance (10 * nano::xrb_ratio)
.link (send5->hash ())
.sign (key2.prv, key2.pub)
.work (*system.work.generate (key2.pub))
.build_shared ();
auto multiplier1 (nano::normalized_multiplier (nano::difficulty::to_multiplier (open2->difficulty (), nano::work_threshold (open2->work_version (), nano::block_details (nano::epoch::epoch_0, false, true, false))), node1.network_params.network.publish_thresholds.epoch_1));
auto multiplier2 (nano::normalized_multiplier (nano::difficulty::to_multiplier (send6->difficulty (), nano::work_threshold (open2->work_version (), nano::block_details (nano::epoch::epoch_0, true, false, false))), node1.network_params.network.publish_thresholds.epoch_1));
node1.process_active (send1);
node1.process_active (open1);
node1.process_active (send5);
nano::blocks_confirm (node1, { send1, open1, send5 });
ASSERT_TIMELY (10s, node1.active.size () == 3);
while (!node1.active.empty ())
{
nano::lock_guard<std::mutex> active_guard (node1.active.mutex);
if (!node1.active.roots.empty ())
{
node1.active.roots.begin ()->election->confirm_once ();
}
}
node1.process_active (send2);
node1.process_active (send3);
node1.process_active (send4);
node1.process_active (send6);
nano::blocks_confirm (node1, { send2, send3, send4, send6 });
ASSERT_TIMELY (10s, node1.active.size () == 4);
std::this_thread::sleep_for (1s);
node1.process_active (open2);
ASSERT_TIMELY (10s, node1.active.size () == 4);
size_t seen (0);
{
nano::lock_guard<std::mutex> active_guard (node1.active.mutex);
node1.active.update_adjusted_multiplier ();
auto it (node1.active.roots.get<1> ().begin ());
while (!node1.active.roots.empty () && it != node1.active.roots.get<1> ().end ())
{
if (it->multiplier == multiplier1 || it->multiplier == multiplier2)
{
seen++;
}
it++;
}
}
ASSERT_LT (seen, 2);
ASSERT_EQ (node1.active.size (), 4);
}
TEST (active_transactions, inactive_votes_cache)
{
nano::system system (1);
@ -977,89 +694,8 @@ TEST (active_transactions, vote_replays)
}
}
TEST (active_transactions, activate_dependencies)
{
// Ensure that we attempt to backtrack if an election isn't getting confirmed and there are more uncemented blocks to start elections for
nano::system system;
nano::node_config config (nano::get_available_port (), system.logging);
config.enable_voting = true;
nano::node_flags flags;
flags.disable_bootstrap_listener = true;
config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto node1 (system.add_node (config, flags));
config.peering_port = nano::get_available_port ();
auto node2 (system.add_node (config, flags));
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
nano::genesis genesis;
nano::block_builder builder;
auto block0 = builder.state ()
.account (nano::dev_genesis_key.pub)
.previous (genesis.hash ())
.representative (nano::dev_genesis_key.pub)
.balance (nano::genesis_amount - nano::Gxrb_ratio)
.link (0)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (node1->work_generate_blocking (genesis.hash ()).value ())
.build_shared ();
// Establish a representative
node2->process_active (block0);
node2->block_processor.flush ();
ASSERT_TIMELY (10s, node1->block (block0->hash ()));
auto block1 = builder.state ()
.account (nano::dev_genesis_key.pub)
.previous (block0->hash ())
.representative (nano::dev_genesis_key.pub)
.balance (nano::genesis_amount - nano::Gxrb_ratio)
.link (0)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (node1->work_generate_blocking (block0->hash ()).value ())
.build ();
// Wait for confirmation of the previous block, which tries to activate the successor
// We want to test that behavior through activating dependencies instead
ASSERT_TIMELY (3s, node2->block_confirmed (block0->hash ()));
{
auto transaction = node2->store.tx_begin_write ();
ASSERT_EQ (nano::process_result::progress, node2->ledger.process (transaction, *block1).code);
}
std::shared_ptr<nano::block> block2 = builder.state ()
.account (nano::dev_genesis_key.pub)
.previous (block1->hash ())
.representative (nano::dev_genesis_key.pub)
.balance (nano::genesis_amount - 2 * nano::Gxrb_ratio)
.link (0)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (node1->work_generate_blocking (block1->hash ()).value ())
.build ();
node2->process_active (block2);
node2->block_processor.flush ();
node2->block_confirm (block2);
ASSERT_TIMELY (10s, node1->block (block2->hash ()));
ASSERT_NE (nullptr, node1->block (block2->hash ()));
ASSERT_TIMELY (10s, node1->active.empty () && node2->active.empty ());
ASSERT_TRUE (node1->block_confirmed_or_being_confirmed (node1->store.tx_begin_read (), block2->hash ()));
ASSERT_TRUE (node2->block_confirmed_or_being_confirmed (node2->store.tx_begin_read (), block2->hash ()));
}
namespace nano
{
TEST (active_transactions, activate_dependencies_invalid)
{
nano::system system;
nano::node_flags flags;
flags.disable_request_loop = true;
auto & node (*system.add_node (flags));
node.active.pending_dependencies.emplace_back (nano::genesis ().open->hash (), 10);
node.active.pending_dependencies.emplace_back (1, 1);
node.active.pending_dependencies.emplace_back (0, -1);
node.active.pending_dependencies.emplace_back (-1, 0);
{
nano::unique_lock<std::mutex> lock (node.active.mutex);
node.active.activate_dependencies (lock);
}
ASSERT_TRUE (node.active.empty ());
ASSERT_EQ (0, node.active.pending_dependencies.size ());
}
// Tests that blocks are correctly cleared from the duplicate filter for unconfirmed elections
TEST (active_transactions, dropped_cleanup)
{

View file

@ -189,106 +189,3 @@ TEST (conflicts, reprioritize)
ASSERT_EQ (multiplier2, existing2->multiplier);
}
}
TEST (conflicts, dependency)
{
nano::system system;
nano::node_config node_config (nano::get_available_port (), system.logging);
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto node1 = system.add_node (node_config);
nano::genesis genesis;
nano::keypair key1;
auto send1 (std::make_shared<nano::send_block> (genesis.hash (), key1.pub, nano::genesis_amount - nano::xrb_ratio, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, 0));
node1->work_generate_blocking (*send1);
auto state_open1 (std::make_shared<nano::state_block> (key1.pub, 0, nano::dev_genesis_key.pub, nano::xrb_ratio, send1->hash (), key1.prv, key1.pub, 0));
node1->work_generate_blocking (*state_open1);
ASSERT_EQ (nano::process_result::progress, node1->process (*send1).code);
ASSERT_EQ (nano::process_result::progress, node1->process (*state_open1).code);
ASSERT_EQ (0, node1->active.size ());
auto election1 = node1->active.insert (send1);
node1->active.insert (state_open1);
ASSERT_EQ (2, node1->active.size ());
// Check dependency for send block
{
nano::lock_guard<std::mutex> guard (node1->active.mutex);
ASSERT_NE (nullptr, election1.election);
ASSERT_EQ (1, election1.election->dependent_blocks.size ());
ASSERT_NE (election1.election->dependent_blocks.end (), election1.election->dependent_blocks.find (state_open1->hash ()));
}
}
TEST (conflicts, adjusted_multiplier)
{
nano::system system;
nano::node_flags flags;
flags.disable_request_loop = true;
auto & node1 (*system.add_node (flags));
nano::genesis genesis;
nano::keypair key1;
nano::keypair key2;
nano::keypair key3;
ASSERT_EQ (0, node1.active.size ());
auto send1 (std::make_shared<nano::send_block> (genesis.hash (), key1.pub, nano::genesis_amount - 2 * nano::xrb_ratio, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (genesis.hash ())));
node1.process_active (send1);
auto send2 (std::make_shared<nano::send_block> (send1->hash (), nano::dev_genesis_key.pub, nano::genesis_amount - 3 * nano::xrb_ratio, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (send1->hash ())));
node1.process_active (send2);
auto receive1 (std::make_shared<nano::receive_block> (send2->hash (), send2->hash (), nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (send2->hash ())));
node1.process_active (receive1);
auto open1 (std::make_shared<nano::open_block> (send1->hash (), key1.pub, key1.pub, key1.prv, key1.pub, *system.work.generate (key1.pub)));
node1.process_active (open1);
auto send3 (std::make_shared<nano::state_block> (key1.pub, open1->hash (), key1.pub, nano::xrb_ratio, key2.pub, key1.prv, key1.pub, *system.work.generate (open1->hash ())));
node1.process_active (send3);
auto send4 (std::make_shared<nano::state_block> (key1.pub, send3->hash (), key1.pub, 0, key3.pub, key1.prv, key1.pub, *system.work.generate (send3->hash ())));
node1.process_active (send4);
ASSERT_EQ (node1.ledger.epoch_signer (node1.ledger.epoch_link (nano::epoch::epoch_1)), nano::dev_genesis_key.pub);
auto open_epoch1 (std::make_shared<nano::state_block> (key2.pub, 0, 0, 0, node1.ledger.epoch_link (nano::epoch::epoch_1), nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (key2.pub)));
node1.process_active (open_epoch1);
auto receive2 (std::make_shared<nano::state_block> (key2.pub, open_epoch1->hash (), 0, nano::xrb_ratio, send3->hash (), key2.prv, key2.pub, *system.work.generate (open_epoch1->hash ())));
node1.process_active (receive2);
auto open2 (std::make_shared<nano::state_block> (key3.pub, 0, key3.pub, nano::xrb_ratio, send4->hash (), key3.prv, key3.pub, *system.work.generate (key3.pub)));
node1.process_active (open2);
auto change1 (std::make_shared<nano::state_block> (key3.pub, open2->hash (), nano::dev_genesis_key.pub, nano::xrb_ratio, 0, key3.prv, key3.pub, *system.work.generate (open2->hash ())));
node1.process_active (change1);
nano::keypair key4;
auto send5 (std::make_shared<nano::state_block> (key3.pub, change1->hash (), nano::dev_genesis_key.pub, 0, key4.pub, key3.prv, key3.pub, *system.work.generate (change1->hash ()))); // Pending for open epoch block
node1.process_active (send5);
nano::blocks_confirm (node1, { send1, send2, receive1, open1, send3, send4, open_epoch1, receive2, open2, change1, send5 });
ASSERT_TIMELY (3s, node1.active.size () == 11);
std::unordered_map<nano::block_hash, double> adjusted_multipliers;
{
nano::lock_guard<std::mutex> guard (node1.active.mutex);
node1.active.update_adjusted_multiplier ();
ASSERT_EQ (node1.active.roots.get<1> ().begin ()->election->status.winner->hash (), send1->hash ());
for (auto i (node1.active.roots.get<1> ().begin ()), n (node1.active.roots.get<1> ().end ()); i != n; ++i)
{
adjusted_multipliers.insert (std::make_pair (i->election->status.winner->hash (), i->adjusted_multiplier));
}
}
// genesis
ASSERT_GT (adjusted_multipliers.find (send1->hash ())->second, adjusted_multipliers.find (send2->hash ())->second);
ASSERT_GT (adjusted_multipliers.find (send2->hash ())->second, adjusted_multipliers.find (receive1->hash ())->second);
// key1
ASSERT_GT (adjusted_multipliers.find (send1->hash ())->second, adjusted_multipliers.find (open1->hash ())->second);
ASSERT_GT (adjusted_multipliers.find (open1->hash ())->second, adjusted_multipliers.find (send3->hash ())->second);
ASSERT_GT (adjusted_multipliers.find (send3->hash ())->second, adjusted_multipliers.find (send4->hash ())->second);
//key2
ASSERT_GT (adjusted_multipliers.find (send3->hash ())->second, adjusted_multipliers.find (receive2->hash ())->second);
ASSERT_GT (adjusted_multipliers.find (open_epoch1->hash ())->second, adjusted_multipliers.find (receive2->hash ())->second);
// key3
ASSERT_GT (adjusted_multipliers.find (send4->hash ())->second, adjusted_multipliers.find (open2->hash ())->second);
ASSERT_GT (adjusted_multipliers.find (open2->hash ())->second, adjusted_multipliers.find (change1->hash ())->second);
ASSERT_GT (adjusted_multipliers.find (change1->hash ())->second, adjusted_multipliers.find (send5->hash ())->second);
// Independent elections can have higher difficulty than adjusted tree
auto open_epoch2 (std::make_shared<nano::state_block> (key4.pub, 0, 0, 0, node1.ledger.epoch_link (nano::epoch::epoch_1), nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (key4.pub, nano::difficulty::from_multiplier ((adjusted_multipliers.find (send1->hash ())->second), node1.network_params.network.publish_thresholds.base))));
ASSERT_GT (open_epoch2->difficulty (), nano::difficulty::from_multiplier ((adjusted_multipliers.find (send1->hash ())->second), node1.network_params.network.publish_thresholds.base));
node1.process_active (open_epoch2);
node1.block_processor.flush ();
node1.block_confirm (open_epoch2);
ASSERT_TIMELY (3s, node1.active.size () == 12);
{
nano::lock_guard<std::mutex> guard (node1.active.mutex);
node1.active.update_adjusted_multiplier ();
ASSERT_EQ (node1.active.roots.size (), 12);
ASSERT_EQ (node1.active.roots.get<1> ().begin ()->election->status.winner->hash (), open_epoch2->hash ());
}
}

View file

@ -13,161 +13,3 @@ TEST (election, construction)
auto election = node.active.insert (genesis.open).election;
election->transition_active ();
}
namespace nano
{
TEST (election, bisect_dependencies)
{
nano::system system;
nano::node_flags flags;
flags.disable_request_loop = true;
auto & node = *system.add_node (flags);
nano::genesis genesis;
nano::confirmation_height_info conf_info;
ASSERT_FALSE (node.store.confirmation_height_get (node.store.tx_begin_read (), nano::dev_genesis_key.pub, conf_info));
ASSERT_EQ (1, conf_info.height);
std::vector<std::shared_ptr<nano::block>> blocks;
blocks.push_back (nullptr); // idx == height
blocks.push_back (genesis.open);
nano::block_builder builder;
auto amount = nano::genesis_amount;
for (int i = 0; i < 299; ++i)
{
auto latest = blocks.back ();
blocks.push_back (builder.state ()
.previous (latest->hash ())
.account (nano::dev_genesis_key.pub)
.representative (nano::dev_genesis_key.pub)
.balance (--amount)
.link (nano::dev_genesis_key.pub)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (latest->hash ()))
.build ());
ASSERT_EQ (nano::process_result::progress, node.process (*blocks.back ()).code);
}
ASSERT_EQ (301, blocks.size ());
ASSERT_TRUE (node.active.empty ());
{
auto election = node.active.insert (blocks.back ()).election;
ASSERT_NE (nullptr, election);
ASSERT_EQ (300, election->blocks.begin ()->second->sideband ().height);
nano::unique_lock<std::mutex> lock (node.active.mutex);
election->activate_dependencies ();
node.active.activate_dependencies (lock);
}
// The first dependency activation also starts an election for the first unconfirmed block
ASSERT_EQ (3, node.active.size ());
{
auto election = node.active.election (blocks[2]->qualified_root ());
ASSERT_NE (nullptr, election);
ASSERT_EQ (2, election->blocks.begin ()->second->sideband ().height);
}
auto check_height_and_activate_next = [&node, &blocks](uint64_t height_a) {
auto election = node.active.election (blocks[height_a]->qualified_root ());
ASSERT_NE (nullptr, election);
ASSERT_EQ (height_a, election->blocks.begin ()->second->sideband ().height);
nano::unique_lock<std::mutex> lock (node.active.mutex);
election->activate_dependencies ();
node.active.activate_dependencies (lock);
};
check_height_and_activate_next (300 - 128); // ensure limited by 128 jumps
ASSERT_EQ (4, node.active.size ());
check_height_and_activate_next (87);
ASSERT_EQ (5, node.active.size ());
check_height_and_activate_next (44);
ASSERT_EQ (6, node.active.size ());
check_height_and_activate_next (23);
ASSERT_EQ (7, node.active.size ());
check_height_and_activate_next (12);
ASSERT_EQ (8, node.active.size ());
check_height_and_activate_next (7);
ASSERT_EQ (9, node.active.size ());
check_height_and_activate_next (4);
ASSERT_EQ (10, node.active.size ());
check_height_and_activate_next (3);
ASSERT_EQ (10, node.active.size ()); // height 2 already inserted initially, no more blocks to activate
check_height_and_activate_next (2);
ASSERT_EQ (10, node.active.size ()); // conf height is 1, no more blocks to activate
ASSERT_EQ (node.active.blocks.size (), node.active.roots.size ());
}
// Tests successful dependency activation of the open block of an account, and its corresponding source
TEST (election, dependencies_open_link)
{
nano::system system;
nano::node_flags flags;
flags.disable_request_loop = true;
auto & node = *system.add_node (flags);
nano::state_block_builder builder;
nano::keypair key;
// Send to key
auto gen_send = builder.make_block ()
.account (nano::dev_genesis_key.pub)
.previous (nano::genesis_hash)
.representative (nano::dev_genesis_key.pub)
.link (key.pub)
.balance (nano::genesis_amount - 1)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (nano::genesis_hash))
.build ();
// Receive from genesis
auto key_open = builder.make_block ()
.account (key.pub)
.previous (0)
.representative (key.pub)
.link (gen_send->hash ())
.balance (1)
.sign (key.prv, key.pub)
.work (*system.work.generate (key.pub))
.build ();
// Send to self
std::shared_ptr<nano::block> key_send = builder.make_block ()
.account (key.pub)
.previous (key_open->hash ())
.representative (key.pub)
.link (key.pub)
.balance (0)
.sign (key.prv, key.pub)
.work (*system.work.generate (key_open->hash ()))
.build ();
node.process (*gen_send);
node.process (*key_open);
node.process (*key_send);
// Insert frontier
node.block_confirm (key_send);
ASSERT_EQ (1, node.active.size ());
{
auto election = node.active.election (key_send->qualified_root ());
ASSERT_NE (nullptr, election);
nano::unique_lock<std::mutex> lock (node.active.mutex);
election->activate_dependencies ();
node.active.activate_dependencies (lock);
}
// Must have activated the open block
ASSERT_EQ (2, node.active.size ());
{
auto election = node.active.election (key_open->qualified_root ());
ASSERT_NE (nullptr, election);
nano::unique_lock<std::mutex> lock (node.active.mutex);
election->activate_dependencies ();
node.active.activate_dependencies (lock);
}
// Must have activated the open's source block
ASSERT_EQ (3, node.active.size ());
{
auto election = node.active.election (gen_send->qualified_root ());
ASSERT_NE (nullptr, election);
nano::unique_lock<std::mutex> lock (node.active.mutex);
election->activate_dependencies ();
node.active.activate_dependencies (lock);
}
// Nothing else to activate
ASSERT_EQ (3, node.active.size ());
}
}

View file

@ -3244,54 +3244,3 @@ TEST (ledger, can_vote)
ledger.store.confirmation_height_put (transaction, nano::genesis_account, height);
ASSERT_TRUE (ledger.can_vote (transaction, *receive2));
}
TEST (ledger, backtrack)
{
nano::genesis genesis;
nano::stat stats;
nano::logger_mt logger;
auto store = nano::make_store (logger, nano::unique_path ());
ASSERT_TRUE (!store->init_error ());
bool cb_hit = false;
nano::ledger ledger (*store, stats, nano::generate_cache (), [&cb_hit]() {
cb_hit = true;
});
{
auto transaction (store->tx_begin_write ());
store->initialize (transaction, genesis, ledger.cache);
}
nano::work_pool pool (std::numeric_limits<unsigned>::max ());
std::vector<std::shared_ptr<nano::block>> blocks;
blocks.push_back (nullptr); // idx == height
blocks.push_back (genesis.open);
auto amount = nano::genesis_amount;
for (auto i = 0; i < 300; ++i)
{
nano::block_builder builder;
std::error_code ec;
auto latest = blocks.back ();
blocks.push_back (builder.state ()
.previous (latest->hash ())
.account (nano::dev_genesis_key.pub)
.representative (nano::dev_genesis_key.pub)
.balance (--amount)
.link (nano::dev_genesis_key.pub)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*pool.generate (latest->hash ()))
.build (ec));
ASSERT_FALSE (ec);
ASSERT_EQ (nano::process_result::progress, ledger.process (store->tx_begin_write (), *blocks.back ()).code);
}
ASSERT_EQ (302, blocks.size ());
ASSERT_EQ (301, blocks[301]->sideband ().height);
auto transaction (store->tx_begin_read ());
auto block_100 = ledger.backtrack (transaction, blocks[300], 200);
ASSERT_NE (nullptr, block_100);
ASSERT_EQ (*block_100, *blocks[100]);
ASSERT_NE (nullptr, ledger.backtrack (transaction, blocks[10], 10));
ASSERT_NE (ledger.backtrack (transaction, blocks[10], 1), ledger.backtrack (transaction, blocks[11], 2));
ASSERT_EQ (ledger.backtrack (transaction, blocks[1], 0), ledger.backtrack (transaction, blocks[1], 1));
ASSERT_NE (ledger.backtrack (transaction, blocks[2], 0), ledger.backtrack (transaction, blocks[2], 1));
ASSERT_EQ (nullptr, ledger.backtrack (transaction, nullptr, 0));
ASSERT_EQ (nullptr, ledger.backtrack (transaction, nullptr, 10));
}

View file

@ -2513,7 +2513,6 @@ TEST (node, block_confirm)
auto & node2 (*system.nodes[1]);
nano::genesis genesis;
nano::keypair key;
system.wallet (1)->insert_adhoc (nano::dev_genesis_key.prv);
nano::state_block_builder builder;
auto send1 = builder.make_block ()
.account (nano::dev_genesis_key.pub)
@ -2533,6 +2532,16 @@ TEST (node, block_confirm)
ASSERT_TIMELY (5s, node1.ledger.block_exists (send1->hash ()) && node2.ledger.block_exists (send1_copy->hash ()));
ASSERT_TRUE (node1.ledger.block_exists (send1->hash ()));
ASSERT_TRUE (node2.ledger.block_exists (send1_copy->hash ()));
// Confirm send1 on node2 so it can vote for send2
node2.block_confirm (send1_copy);
{
auto election = node2.active.election (send1_copy->qualified_root ());
ASSERT_NE (nullptr, election);
nano::lock_guard<std::mutex> guard (node2.active.mutex);
election->confirm_once ();
}
ASSERT_TIMELY (3s, node2.block_confirmed (send1_copy->hash ()) && node2.active.empty ());
system.wallet (1)->insert_adhoc (nano::dev_genesis_key.prv);
auto send2 (std::make_shared<nano::state_block> (nano::dev_genesis_key.pub, send1->hash (), nano::dev_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio * 2, key.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *node1.work_generate_blocking (send1->hash ())));
{
auto transaction (node1.store.tx_begin_write ());
@ -2542,9 +2551,9 @@ TEST (node, block_confirm)
auto transaction (node2.store.tx_begin_write ());
ASSERT_EQ (nano::process_result::progress, node2.ledger.process (transaction, *send2).code);
}
node1.block_confirm (send2);
ASSERT_TRUE (node1.active.list_recently_cemented ().empty ());
ASSERT_TIMELY (10s, !node1.active.list_recently_cemented ().empty ());
node1.block_confirm (send2);
ASSERT_TIMELY (10s, node1.active.list_recently_cemented ().size () == 2);
}
}
@ -4197,7 +4206,7 @@ TEST (node, dependency_graph)
}
// Confirm a complex dependency graph starting from a frontier
TEST (node, dependency_graph_frontier)
TEST (node, DISABLED_dependency_graph_frontier)
{
nano::system system;
nano::node_config config (nano::get_available_port (), system.logging);

View file

@ -273,7 +273,6 @@ void nano::active_transactions::request_confirm (nano::unique_lock<std::mutex> &
solicitor.flush ();
generator_session.flush ();
lock_a.lock ();
activate_dependencies (lock_a);
// This is updated after the loop to ensure slow machines don't do the full check often
if (check_all_elections_l)
@ -312,100 +311,6 @@ void nano::active_transactions::frontiers_confirmation (nano::unique_lock<std::m
}
}
void nano::active_transactions::activate_dependencies (nano::unique_lock<std::mutex> & lock_a)
{
debug_assert (lock_a.owns_lock ());
decltype (pending_dependencies) pending_l;
pending_l.swap (pending_dependencies);
lock_a.unlock ();
auto first_unconfirmed = [this](nano::transaction const & transaction_a, nano::account const & account_a, nano::block_hash const & confirmed_frontier_a) {
if (!confirmed_frontier_a.is_zero ())
{
return this->node.store.block_successor (transaction_a, confirmed_frontier_a);
}
else
{
nano::account_info account_info_l;
auto error = node.store.account_get (transaction_a, account_a, account_info_l);
(void)error;
debug_assert (!error);
return account_info_l.open_block;
}
};
// Store blocks to activate when the lock is re-acquired, adding the hash of the original election as a dependency
std::vector<std::pair<std::shared_ptr<nano::block>, nano::block_hash>> activate_l;
{
auto transaction = node.store.tx_begin_read ();
for (auto const & entry_l : pending_l)
{
auto const & hash_l (entry_l.first);
auto const block_l (node.store.block_get (transaction, hash_l));
if (block_l)
{
auto const height_l (entry_l.second);
auto const previous_hash_l (block_l->previous ());
if (!previous_hash_l.is_zero ())
{
/* Insert first unconfirmed block (pessimistic) and bisect the chain (likelihood) */
auto const account (node.store.block_account_calculated (*block_l));
nano::confirmation_height_info conf_info_l;
if (!node.store.confirmation_height_get (transaction, account, conf_info_l))
{
if (height_l > conf_info_l.height + 1)
{
auto const successor_hash_l = first_unconfirmed (transaction, account, conf_info_l.frontier);
if (!confirmation_height_processor.is_processing_block (successor_hash_l))
{
auto const successor_l = node.store.block_get (transaction, successor_hash_l);
debug_assert (successor_l != nullptr);
if (successor_l != nullptr)
{
activate_l.emplace_back (successor_l, hash_l);
}
}
}
if (height_l > conf_info_l.height + 2)
{
auto const jumps_l = std::min<uint64_t> (128, (height_l - conf_info_l.height) / 2);
auto const backtracked_l (node.ledger.backtrack (transaction, block_l, jumps_l));
if (backtracked_l != nullptr)
{
activate_l.emplace_back (backtracked_l, hash_l);
}
}
}
}
/* If previous block not existing/not commited yet, block_source can cause segfault for state blocks
So source check can be done only if previous != nullptr or previous is 0 (open account) */
if (previous_hash_l.is_zero () || node.ledger.block_exists (previous_hash_l))
{
auto source_hash_l (node.ledger.block_source (transaction, *block_l));
if (!source_hash_l.is_zero () && source_hash_l != previous_hash_l && blocks.find (source_hash_l) == blocks.end ())
{
auto source_l (node.store.block_get (transaction, source_hash_l));
if (source_l != nullptr && !node.block_confirmed_or_being_confirmed (transaction, source_hash_l))
{
activate_l.emplace_back (source_l, hash_l);
}
}
}
}
}
}
lock_a.lock ();
for (auto const & entry_l : activate_l)
{
auto election = insert_impl (entry_l.first);
if (election.inserted)
{
election.election->transition_active ();
election.election->dependent_blocks.insert (entry_l.second);
}
}
}
void nano::active_transactions::request_loop ()
{
nano::unique_lock<std::mutex> lock (mutex);
@ -424,7 +329,6 @@ void nano::active_transactions::request_loop ()
// Account for the time spent in request_confirm by defining the wakeup point beforehand
const auto wakeup_l (std::chrono::steady_clock::now () + std::chrono::milliseconds (node.network_params.network.request_interval_ms));
update_adjusted_multiplier ();
// frontiers_confirmation should be above update_active_multiplier to ensure new sorted roots are updated
frontiers_confirmation (lock);
update_active_multiplier (lock);
@ -642,9 +546,8 @@ nano::election_insertion_result nano::active_transactions::insert_impl (std::sha
double multiplier (normalized_multiplier (*block_a));
bool prioritized = roots.size () < prioritized_cutoff || multiplier > last_prioritized_multiplier.value_or (0);
result.election = nano::make_shared<nano::election> (node, block_a, confirmation_action_a, prioritized);
roots.get<tag_root> ().emplace (nano::active_transactions::conflict_info{ root, multiplier, multiplier, result.election, epoch, previous_balance });
roots.get<tag_root> ().emplace (nano::active_transactions::conflict_info{ root, multiplier, result.election, epoch, previous_balance });
blocks.emplace (hash, result.election);
add_adjust_difficulty (hash);
result.election->insert_inactive_votes_cache (hash);
node.stats.inc (nano::stat::type::election, prioritized ? nano::stat::detail::election_priority : nano::stat::detail::election_non_priority);
}
@ -835,7 +738,6 @@ bool nano::active_transactions::update_difficulty_impl (nano::active_transaction
roots.get<tag_root> ().modify (root_it_a, [multiplier](nano::active_transactions::conflict_info & info_a) {
info_a.multiplier = multiplier;
});
add_adjust_difficulty (block_a.hash ());
node.stats.inc (nano::stat::type::election, nano::stat::detail::election_difficulty_update);
}
return error;
@ -922,97 +824,6 @@ double nano::active_transactions::normalized_multiplier (nano::block const & blo
return multiplier;
}
void nano::active_transactions::add_adjust_difficulty (nano::block_hash const & hash_a)
{
debug_assert (!mutex.try_lock ());
adjust_difficulty_list.push_back (hash_a);
}
void nano::active_transactions::update_adjusted_multiplier ()
{
debug_assert (!mutex.try_lock ());
std::unordered_set<nano::block_hash> processed_blocks;
while (!adjust_difficulty_list.empty ())
{
auto const & adjust_difficulty_item (adjust_difficulty_list.front ());
std::deque<std::pair<nano::block_hash, int64_t>> remaining_blocks;
remaining_blocks.emplace_back (adjust_difficulty_item, 0);
adjust_difficulty_list.pop_front ();
std::vector<std::pair<nano::qualified_root, int64_t>> elections_list;
double sum (0.);
int64_t highest_level (0);
int64_t lowest_level (0);
while (!remaining_blocks.empty ())
{
auto const & item (remaining_blocks.front ());
auto hash (item.first);
auto level (item.second);
if (processed_blocks.find (hash) == processed_blocks.end ())
{
auto existing (blocks.find (hash));
if (existing != blocks.end () && !existing->second->confirmed () && existing->second->status.winner->hash () == hash)
{
auto previous (existing->second->status.winner->previous ());
if (!previous.is_zero ())
{
remaining_blocks.emplace_back (previous, level + 1);
}
auto source (existing->second->status.winner->source ());
if (!source.is_zero () && source != previous)
{
remaining_blocks.emplace_back (source, level + 1);
}
auto link (existing->second->status.winner->link ());
if (!link.is_zero () && !node.ledger.is_epoch_link (link) && link != previous)
{
remaining_blocks.emplace_back (link, level + 1);
}
for (auto & dependent_block : existing->second->dependent_blocks)
{
remaining_blocks.emplace_back (dependent_block, level - 1);
}
processed_blocks.insert (hash);
nano::qualified_root root (previous, existing->second->status.winner->root ());
auto existing_root (roots.get<tag_root> ().find (root));
if (existing_root != roots.get<tag_root> ().end ())
{
sum += existing_root->multiplier;
elections_list.emplace_back (root, level);
if (level > highest_level)
{
highest_level = level;
}
else if (level < lowest_level)
{
lowest_level = level;
}
}
}
}
remaining_blocks.pop_front ();
}
if (!elections_list.empty ())
{
double avg_multiplier = sum / elections_list.size ();
double min_unit = 32.0 * avg_multiplier * std::numeric_limits<double>::epsilon ();
debug_assert (min_unit > 0);
// Set adjusted multiplier
for (auto & item : elections_list)
{
auto existing_root (roots.get<tag_root> ().find (item.first));
double multiplier_a = avg_multiplier + (double)item.second * min_unit;
if (existing_root->adjusted_multiplier != multiplier_a)
{
roots.get<tag_root> ().modify (existing_root, [multiplier_a](nano::active_transactions::conflict_info & info_a) {
info_a.adjusted_multiplier = multiplier_a;
});
}
}
}
}
}
void nano::active_transactions::update_active_multiplier (nano::unique_lock<std::mutex> & lock_a)
{
debug_assert (!mutex.try_lock ());
@ -1028,7 +839,7 @@ void nano::active_transactions::update_active_multiplier (nano::unique_lock<std:
{
if (!it->election->confirmed ())
{
prioritized.push_back (it->adjusted_multiplier);
prioritized.push_back (it->multiplier);
}
}
if (prioritized.size () > 10 || (node.network_params.network.is_dev_network () && !prioritized.empty ()))
@ -1125,7 +936,6 @@ void nano::active_transactions::erase (nano::block const & block_a)
if (root_it != roots.get<tag_root> ().end ())
{
root_it->election->cleanup ();
root_it->election->adjust_dependent_difficulty ();
roots.get<tag_root> ().erase (root_it);
lock.unlock ();
node.logger.try_log (boost::str (boost::format ("Election erased for block block %1% root %2%") % block_a.hash ().to_string () % block_a.root ().to_string ()));

View file

@ -117,7 +117,6 @@ class active_transactions final
public:
nano::qualified_root root;
double multiplier;
double adjusted_multiplier;
std::shared_ptr<nano::election> election;
nano::epoch epoch;
nano::uint128_t previous_balance;
@ -142,7 +141,7 @@ public:
mi::hashed_unique<mi::tag<tag_root>,
mi::member<conflict_info, nano::qualified_root, &conflict_info::root>>,
mi::ordered_non_unique<mi::tag<tag_difficulty>,
mi::member<conflict_info, double, &conflict_info::adjusted_multiplier>,
mi::member<conflict_info, double, &conflict_info::multiplier>,
std::greater<double>>>>;
// clang-format on
ordered_roots roots;
@ -169,8 +168,6 @@ public:
// Returns false if the election was restarted
bool restart (std::shared_ptr<nano::block> const &, nano::write_transaction const &);
double normalized_multiplier (nano::block const &, boost::optional<roots_iterator> const & = boost::none) const;
void add_adjust_difficulty (nano::block_hash const &);
void update_adjusted_multiplier ();
void update_active_multiplier (nano::unique_lock<std::mutex> &);
uint64_t active_difficulty ();
uint64_t limited_active_difficulty (nano::block const &);
@ -229,8 +226,6 @@ private:
void frontiers_confirmation (nano::unique_lock<std::mutex> &);
nano::account next_frontier_account{ 0 };
std::chrono::steady_clock::time_point next_frontier_check{ std::chrono::steady_clock::now () };
void activate_dependencies (nano::unique_lock<std::mutex> &);
std::vector<std::pair<nano::block_hash, uint64_t>> pending_dependencies;
nano::condition_variable condition;
bool started{ false };
std::atomic<bool> stopped{ false };
@ -273,7 +268,6 @@ private:
void prioritize_account_for_confirmation (prioritize_num_uncemented &, size_t &, nano::account const &, nano::account_info const &, uint64_t);
static size_t constexpr max_priority_cementable_frontiers{ 100000 };
static size_t constexpr confirmed_frontiers_max_pending_size{ 10000 };
std::deque<nano::block_hash> adjust_difficulty_list;
// clang-format off
using ordered_cache = boost::multi_index_container<nano::inactive_cache_information,
mi::indexed_by<
@ -289,15 +283,12 @@ private:
friend class election;
friend std::unique_ptr<container_info_component> collect_container_info (active_transactions &, const std::string &);
friend class active_transactions_activate_dependencies_invalid_Test;
friend class active_transactions_dropped_cleanup_dev;
friend class active_transactions_vote_replays_Test;
friend class confirmation_height_prioritize_frontiers_Test;
friend class confirmation_height_prioritize_frontiers_overwrite_Test;
friend class active_transactions_confirmation_consistency_Test;
friend class node_deferred_dependent_elections_Test;
friend class election_bisect_dependencies_Test;
friend class election_dependencies_open_link_Test;
};
std::unique_ptr<container_info_component> collect_container_info (active_transactions & active_transactions, const std::string & name);

View file

@ -9,7 +9,6 @@ using namespace std::chrono;
int constexpr nano::election::passive_duration_factor;
int constexpr nano::election::active_request_count_min;
int constexpr nano::election::active_broadcasting_duration_factor;
int constexpr nano::election::confirmed_duration_factor;
std::chrono::milliseconds nano::election::base_latency () const
@ -33,7 +32,6 @@ root (block_a->root ())
{
last_votes.emplace (node.network_params.random.not_an_account, nano::vote_info{ std::chrono::steady_clock::now (), 0, block_a->hash () });
blocks.emplace (block_a->hash (), block_a);
update_dependent ();
}
void nano::election::confirm_once (nano::election_status_type type_a)
@ -58,7 +56,6 @@ void nano::election::confirm_once (nano::election_status_type type_a)
node.background ([node_l, status_l, confirmation_action_l]() {
confirmation_action_l (status_l.winner);
});
adjust_dependent_difficulty ();
}
}
@ -92,18 +89,6 @@ bool nano::election::valid_change (nano::election::state_t expected_a, nano::ele
}
break;
case nano::election::state_t::broadcasting:
switch (desired_a)
{
case nano::election::state_t::backtracking:
case nano::election::state_t::confirmed:
case nano::election::state_t::expired_unconfirmed:
result = true;
break;
default:
break;
}
break;
case nano::election::state_t::backtracking:
switch (desired_a)
{
case nano::election::state_t::confirmed:
@ -178,12 +163,6 @@ bool nano::election::confirmed () const
return state_m == nano::election::state_t::confirmed || state_m == nano::election::state_t::expired_confirmed;
}
void nano::election::activate_dependencies ()
{
debug_assert (!node.active.mutex.try_lock ());
node.active.pending_dependencies.emplace_back (status.winner->hash (), height);
}
void nano::election::broadcast_block (nano::confirmation_solicitor & solicitor_a)
{
if (base_latency () * 15 < std::chrono::steady_clock::now () - last_block)
@ -216,15 +195,6 @@ bool nano::election::transition_time (nano::confirmation_solicitor & solicitor_a
}
break;
case nano::election::state_t::broadcasting:
broadcast_block (solicitor_a);
send_confirm_req (solicitor_a);
if (base_latency () * active_broadcasting_duration_factor < std::chrono::steady_clock::now () - state_start)
{
state_change (nano::election::state_t::broadcasting, nano::election::state_t::backtracking);
activate_dependencies ();
}
break;
case nano::election::state_t::backtracking:
broadcast_block (solicitor_a);
send_confirm_req (solicitor_a);
break;
@ -303,8 +273,6 @@ void nano::election::confirm_if_quorum ()
status.winner = block_l;
remove_votes (status_winner_hash_l);
node.block_processor.force (block_l);
update_dependent ();
node.active.add_adjust_difficulty (winner_hash_l);
}
if (have_quorum (tally_l, sum))
{
@ -433,47 +401,6 @@ size_t nano::election::last_votes_size ()
return last_votes.size ();
}
void nano::election::update_dependent ()
{
debug_assert (!node.active.mutex.try_lock ());
std::vector<nano::block_hash> blocks_search;
auto hash (status.winner->hash ());
auto previous (status.winner->previous ());
if (!previous.is_zero ())
{
blocks_search.push_back (previous);
}
auto source (status.winner->source ());
if (!source.is_zero () && source != previous)
{
blocks_search.push_back (source);
}
auto link (status.winner->link ());
if (!link.is_zero () && !node.ledger.is_epoch_link (link) && link != previous)
{
blocks_search.push_back (link);
}
for (auto & block_search : blocks_search)
{
auto existing (node.active.blocks.find (block_search));
if (existing != node.active.blocks.end () && !existing->second->confirmed ())
{
if (existing->second->dependent_blocks.find (hash) == existing->second->dependent_blocks.end ())
{
existing->second->dependent_blocks.insert (hash);
}
}
}
}
void nano::election::adjust_dependent_difficulty ()
{
for (auto & dependent_block : dependent_blocks)
{
node.active.add_adjust_difficulty (dependent_block);
}
}
void nano::election::cleanup ()
{
bool unconfirmed (!confirmed ());

View file

@ -42,14 +42,12 @@ private: // State management
passive, // only listening for incoming votes
active, // actively request confirmations
broadcasting, // request confirmations and broadcast the winner
backtracking, // start an election for unconfirmed dependent blocks
confirmed, // confirmed but still listening for votes
expired_confirmed,
expired_unconfirmed
};
static int constexpr passive_duration_factor = 5;
static int constexpr active_request_count_min = 2;
static int constexpr active_broadcasting_duration_factor = 30;
static int constexpr confirmed_duration_factor = 5;
std::atomic<nano::election::state_t> state_m = { state_t::passive };
@ -63,7 +61,6 @@ private: // State management
bool state_change (nano::election::state_t, nano::election::state_t);
void broadcast_block (nano::confirmation_solicitor &);
void send_confirm_req (nano::confirmation_solicitor &);
void activate_dependencies ();
// Calculate votes for local representatives
void generate_votes ();
void remove_votes (nano::block_hash const &);
@ -81,8 +78,6 @@ public:
void log_votes (nano::tally_t const &) const;
bool publish (std::shared_ptr<nano::block> block_a);
size_t last_votes_size ();
void update_dependent ();
void adjust_dependent_difficulty ();
size_t insert_inactive_votes_cache (nano::block_hash const &);
bool prioritized () const;
void prioritize_election (nano::vote_generator_session &);
@ -105,14 +100,10 @@ public:
nano::election_status status;
unsigned confirmation_request_count{ 0 };
std::unordered_map<nano::block_hash, nano::uint128_t> last_tally;
std::unordered_set<nano::block_hash> dependent_blocks;
std::chrono::seconds late_blocks_delay{ 5 };
uint64_t const height;
nano::root const root;
friend class active_transactions;
friend class election_bisect_dependencies_Test;
friend class election_dependencies_open_link_Test;
};
}

View file

@ -1197,19 +1197,6 @@ std::shared_ptr<nano::block> nano::ledger::forked_block (nano::transaction const
return result;
}
std::shared_ptr<nano::block> nano::ledger::backtrack (nano::transaction const & transaction_a, std::shared_ptr<nano::block> const & start_a, uint64_t jumps_a)
{
auto block = start_a;
while (jumps_a > 0 && block != nullptr && !block->previous ().is_zero ())
{
block = store.block_get (transaction_a, block->previous ());
debug_assert (block != nullptr);
--jumps_a;
}
debug_assert (block == nullptr || block->previous ().is_zero () || jumps_a == 0);
return block;
}
bool nano::ledger::block_confirmed (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const
{
auto confirmed (false);

View file

@ -25,7 +25,6 @@ public:
nano::uint128_t weight (nano::account const &);
std::shared_ptr<nano::block> successor (nano::transaction const &, nano::qualified_root const &);
std::shared_ptr<nano::block> forked_block (nano::transaction const &, nano::block const &);
std::shared_ptr<nano::block> backtrack (nano::transaction const &, std::shared_ptr<nano::block> const &, uint64_t);
bool block_confirmed (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const;
bool block_not_confirmed_or_not_exists (nano::block const & block_a) const;
nano::block_hash latest (nano::transaction const &, nano::account const &);