Skip to content

Commit

Permalink
Merge pull request #3284 from nanocurrency/v22rc2_cherry_pick
Browse files Browse the repository at this point in the history
Cherry picking latest commits from develop.
  • Loading branch information
clemahieu committed May 13, 2021
2 parents 2a3afcb + 9a532b1 commit ef09e55
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 98 deletions.
128 changes: 36 additions & 92 deletions nano/core_test/active_transactions.cpp
Expand Up @@ -308,7 +308,7 @@ TEST (active_transactions, inactive_votes_cache_existing_vote)
// Insert vote
auto vote1 (std::make_shared<nano::vote> (key.pub, key.prv, 1, std::vector<nano::block_hash> (1, send->hash ())));
node.vote_processor.vote (vote1, std::make_shared<nano::transport::channel_loopback> (node));
ASSERT_TIMELY (5s, election->votes ().size () == 2)
ASSERT_TIMELY (5s, election->votes ().size () == 2);
ASSERT_EQ (1, node.stats.count (nano::stat::type::election, nano::stat::detail::vote_new));
auto last_vote1 (election->votes ()[key.pub]);
ASSERT_EQ (send->hash (), last_vote1.hash);
Expand Down Expand Up @@ -388,49 +388,28 @@ TEST (active_transactions, inactive_votes_cache_election_start)
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto & node = *system.add_node (node_config);
nano::block_hash latest (node.latest (nano::dev_genesis_key.pub));
nano::keypair key1, key2, key3, key4, key5;
nano::keypair key1, key2;
nano::send_block_builder send_block_builder;
nano::state_block_builder state_block_builder;
auto send1 = send_block_builder.make_block ()
.previous (latest)
.destination (key1.pub)
.balance (nano::genesis_amount - 2000 * nano::Gxrb_ratio)
.balance (nano::genesis_amount - 5000 * nano::Gxrb_ratio)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (latest))
.build_shared ();
auto send2 = send_block_builder.make_block ()
.previous (send1->hash ())
.destination (key2.pub)
.balance (nano::genesis_amount - 4000 * nano::Gxrb_ratio)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (send1->hash ()))
.build_shared ();
auto send3 = send_block_builder.make_block ()
.previous (send2->hash ())
.destination (key3.pub)
.balance (nano::genesis_amount - 6000 * nano::Gxrb_ratio)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (send2->hash ()))
.build_shared ();
auto send4 = send_block_builder.make_block ()
.previous (send3->hash ())
.destination (key4.pub)
.balance (nano::genesis_amount - 8000 * nano::Gxrb_ratio)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (send3->hash ()))
.build_shared ();
auto send5 = send_block_builder.make_block ()
.previous (send4->hash ())
.destination (key5.pub)
.balance (nano::genesis_amount - 10000 * nano::Gxrb_ratio)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (send4->hash ()))
.work (*system.work.generate (send1->hash ()))
.build_shared ();
auto open1 = state_block_builder.make_block ()
.account (key1.pub)
.previous (0)
.representative (key1.pub)
.balance (2000 * nano::Gxrb_ratio)
.balance (5000 * nano::Gxrb_ratio)
.link (send1->hash ())
.sign (key1.prv, key1.pub)
.work (*system.work.generate (key1.pub))
Expand All @@ -439,107 +418,69 @@ TEST (active_transactions, inactive_votes_cache_election_start)
.account (key2.pub)
.previous (0)
.representative (key2.pub)
.balance (2000 * nano::Gxrb_ratio)
.balance (5000 * nano::Gxrb_ratio)
.link (send2->hash ())
.sign (key2.prv, key2.pub)
.work (*system.work.generate (key2.pub))
.build_shared ();
auto open3 = state_block_builder.make_block ()
.account (key3.pub)
.previous (0)
.representative (key3.pub)
.balance (2000 * nano::Gxrb_ratio)
.link (send3->hash ())
.sign (key3.prv, key3.pub)
.work (*system.work.generate (key3.pub))
.build_shared ();
auto open4 = state_block_builder.make_block ()
.account (key4.pub)
.previous (0)
.representative (key4.pub)
.balance (2000 * nano::Gxrb_ratio)
.link (send4->hash ())
.sign (key4.prv, key4.pub)
.work (*system.work.generate (key4.pub))
.build_shared ();
auto open5 = state_block_builder.make_block ()
.account (key5.pub)
.previous (0)
.representative (key5.pub)
.balance (2000 * nano::Gxrb_ratio)
.link (send5->hash ())
.sign (key5.prv, key5.pub)
.work (*system.work.generate (key5.pub))
.build_shared ();
node.block_processor.add (send1);
node.block_processor.add (send2);
node.block_processor.add (send3);
node.block_processor.add (send4);
node.block_processor.add (send5);
node.block_processor.add (open1);
node.block_processor.add (open2);
node.block_processor.add (open3);
node.block_processor.add (open4);
node.block_processor.add (open5);
node.block_processor.flush ();
ASSERT_TIMELY (5s, 11 == node.ledger.cache.block_count);
ASSERT_TIMELY (5s, 5 == node.ledger.cache.block_count);
ASSERT_TRUE (node.active.empty ());
ASSERT_EQ (1, node.ledger.cache.cemented_count);
// These blocks will be processed later
auto send6 = send_block_builder.make_block ()
.previous (send5->hash ())
auto send3 = send_block_builder.make_block ()
.previous (send2->hash ())
.destination (nano::keypair ().pub)
.balance (send5->balance ().number () - 1)
.balance (send2->balance ().number () - 1)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (send5->hash ()))
.work (*system.work.generate (send2->hash ()))
.build_shared ();
auto send7 = send_block_builder.make_block ()
.previous (send6->hash ())
auto send4 = send_block_builder.make_block ()
.previous (send3->hash ())
.destination (nano::keypair ().pub)
.balance (send6->balance ().number () - 1)
.balance (send3->balance ().number () - 1)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (send6->hash ()))
.work (*system.work.generate (send3->hash ()))
.build_shared ();
// Inactive votes
std::vector<nano::block_hash> hashes{ open1->hash (), open2->hash (), open3->hash (), open4->hash (), open5->hash (), send7->hash () };
std::vector<nano::block_hash> hashes{ open1->hash (), open2->hash (), send4->hash () };
auto vote1 (std::make_shared<nano::vote> (key1.pub, key1.prv, 0, hashes));
node.vote_processor.vote (vote1, std::make_shared<nano::transport::channel_loopback> (node));
auto vote2 (std::make_shared<nano::vote> (key2.pub, key2.prv, 0, hashes));
node.vote_processor.vote (vote2, std::make_shared<nano::transport::channel_loopback> (node));
auto vote3 (std::make_shared<nano::vote> (key3.pub, key3.prv, 0, hashes));
node.vote_processor.vote (vote3, std::make_shared<nano::transport::channel_loopback> (node));
auto vote4 (std::make_shared<nano::vote> (key4.pub, key4.prv, 0, hashes));
node.vote_processor.vote (vote4, std::make_shared<nano::transport::channel_loopback> (node));
ASSERT_TIMELY (5s, node.active.inactive_votes_cache_size () == 6);
ASSERT_TIMELY (5s, node.active.inactive_votes_cache_size () == 3);
ASSERT_TRUE (node.active.empty ());
ASSERT_EQ (1, node.ledger.cache.cemented_count);
// 5 votes are required to start election
auto vote5 (std::make_shared<nano::vote> (key5.pub, key5.prv, 0, hashes));
node.vote_processor.vote (vote5, std::make_shared<nano::transport::channel_loopback> (node));
ASSERT_TIMELY (5s, 5 == node.active.size ());
// 2 votes are required to start election (dev network)
auto vote2 (std::make_shared<nano::vote> (key2.pub, key2.prv, 0, hashes));
node.vote_processor.vote (vote2, std::make_shared<nano::transport::channel_loopback> (node));
// Only open1 & open2 blocks elections should start (send4 is missing previous block in ledger)
ASSERT_TIMELY (5s, 2 == node.active.size ());
// Confirm elections with weight quorum
auto vote0 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, std::numeric_limits<uint64_t>::max (), hashes)); // Final vote for confirmation
node.vote_processor.vote (vote0, std::make_shared<nano::transport::channel_loopback> (node));
ASSERT_TIMELY (5s, node.active.empty ());
ASSERT_TIMELY (5s, 11 == node.ledger.cache.cemented_count);
ASSERT_TIMELY (5s, 5 == node.ledger.cache.cemented_count);
// A late block arrival also checks the inactive votes cache
ASSERT_TRUE (node.active.empty ());
auto send7_cache (node.active.find_inactive_votes_cache (send7->hash ()));
ASSERT_EQ (6, send7_cache.voters.size ());
ASSERT_TRUE (send7_cache.status.bootstrap_started);
ASSERT_TRUE (send7_cache.status.confirmed);
ASSERT_TRUE (send7_cache.status.election_started); // already marked even though the block does not exist
node.process_active (send6);
auto send4_cache (node.active.find_inactive_votes_cache (send4->hash ()));
ASSERT_EQ (3, send4_cache.voters.size ());
ASSERT_TRUE (send4_cache.status.bootstrap_started);
ASSERT_TRUE (send4_cache.status.confirmed);
ASSERT_TRUE (send4_cache.status.election_started); // already marked even though the block does not exist
node.process_active (send3);
node.block_processor.flush ();
// An election is started for send6 but does not confirm
ASSERT_TIMELY (5s, 1 == node.active.size ());
node.vote_processor.flush ();
ASSERT_FALSE (node.block_confirmed_or_being_confirmed (node.store.tx_begin_read (), send6->hash ()));
ASSERT_FALSE (node.block_confirmed_or_being_confirmed (node.store.tx_begin_read (), send3->hash ()));
// send7 cannot be voted on but an election should be started from inactive votes
ASSERT_FALSE (node.ledger.dependents_confirmed (node.store.tx_begin_read (), *send7));
node.process_active (send7);
ASSERT_FALSE (node.ledger.dependents_confirmed (node.store.tx_begin_read (), *send4));
node.process_active (send4);
node.block_processor.flush ();
ASSERT_TIMELY (5s, 13 == node.ledger.cache.cemented_count);
ASSERT_TIMELY (5s, 7 == node.ledger.cache.cemented_count);
}

namespace nano
Expand Down Expand Up @@ -1046,6 +987,7 @@ TEST (active_transactions, restart_dropped)
ASSERT_EQ (0, node.active.size ());
node.process_active (send);
node.block_processor.flush ();
node.scheduler.flush ();
ASSERT_EQ (1, node.active.size ());
ASSERT_EQ (1, node.stats.count (nano::stat::type::election, nano::stat::detail::election_restart));
auto ledger_block (node.store.block_get (node.store.tx_begin_read (), send->hash ()));
Expand All @@ -1058,6 +1000,7 @@ TEST (active_transactions, restart_dropped)
// Try to restart election with the same difficulty
node.process_active (send);
node.block_processor.flush ();
node.scheduler.flush ();
ASSERT_EQ (0, node.active.size ());
ASSERT_EQ (1, node.stats.count (nano::stat::type::election, nano::stat::detail::election_restart));
// Generate even higher difficulty work
Expand All @@ -1068,6 +1011,7 @@ TEST (active_transactions, restart_dropped)
ASSERT_EQ (0, node.active.size ());
node.process_active (send);
node.block_processor.flush ();
node.scheduler.flush ();
ASSERT_EQ (1, node.active.size ());
ASSERT_EQ (1, node.ledger.cache.cemented_count);
ASSERT_EQ (2, node.stats.count (nano::stat::type::election, nano::stat::detail::election_restart));
Expand Down
7 changes: 4 additions & 3 deletions nano/core_test/confirmation_height.cpp
Expand Up @@ -304,17 +304,18 @@ TEST (confirmation_height, gap_live)
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto node = system.add_node (node_config, node_flags);
node_config.peering_port = nano::get_available_port ();
node_config.receive_minimum = nano::genesis_amount; // Prevent auto-receive & open1/receive1/receive2 blocks conflicts
system.add_node (node_config, node_flags);
nano::keypair destination;
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
system.wallet (1)->insert_adhoc (destination.prv);

nano::genesis genesis;
auto send1 (std::make_shared<nano::state_block> (nano::genesis_account, genesis.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, destination.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, 0));
auto send1 (std::make_shared<nano::state_block> (nano::genesis_account, genesis.hash (), nano::genesis_account, nano::genesis_amount - 1, destination.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, 0));
node->work_generate_blocking (*send1);
auto send2 (std::make_shared<nano::state_block> (nano::genesis_account, send1->hash (), nano::genesis_account, nano::genesis_amount - 2 * nano::Gxrb_ratio, destination.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, 0));
auto send2 (std::make_shared<nano::state_block> (nano::genesis_account, send1->hash (), nano::genesis_account, nano::genesis_amount - 2, destination.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, 0));
node->work_generate_blocking (*send2);
auto send3 (std::make_shared<nano::state_block> (nano::genesis_account, send2->hash (), nano::genesis_account, nano::genesis_amount - 3 * nano::Gxrb_ratio, destination.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, 0));
auto send3 (std::make_shared<nano::state_block> (nano::genesis_account, send2->hash (), nano::genesis_account, nano::genesis_amount - 3, destination.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, 0));
node->work_generate_blocking (*send3);

auto open1 (std::make_shared<nano::open_block> (send1->hash (), destination.pub, destination.pub, destination.prv, destination.pub, 0));
Expand Down
3 changes: 2 additions & 1 deletion nano/core_test/conflicts.cpp
Expand Up @@ -40,11 +40,12 @@ TEST (conflicts, add_existing)
auto send2 (std::make_shared<nano::send_block> (genesis.hash (), key2.pub, 0, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, 0));
send2->sideband_set ({});
node1.scheduler.activate (nano::dev_genesis_key.pub, node1.store.tx_begin_read ());
node1.scheduler.flush ();
auto election1 = node1.active.election (send2->qualified_root ());
ASSERT_NE (nullptr, election1);
ASSERT_EQ (1, node1.active.size ());
auto vote1 (std::make_shared<nano::vote> (key2.pub, key2.prv, 0, send2));
node1.active.vote (vote1);
ASSERT_NE (nullptr, election1);
ASSERT_EQ (2, election1->votes ().size ());
auto votes (election1->votes ());
ASSERT_NE (votes.end (), votes.find (key2.pub));
Expand Down
93 changes: 93 additions & 0 deletions nano/core_test/node.cpp
Expand Up @@ -4055,6 +4055,99 @@ TEST (node, rollback_vote_self)
ASSERT_EQ (fork->hash (), vote->second.hash);
}

TEST (node, rollback_gap_source)
{
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);
nano::state_block_builder builder;
nano::keypair key;
auto send1 = 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_shared ();
auto fork = builder.make_block ()
.account (key.pub)
.previous (0)
.representative (key.pub)
.link (send1->hash ())
.balance (1)
.sign (key.prv, key.pub)
.work (*system.work.generate (key.pub))
.build_shared ();
auto send2 = builder.make_block ()
.from (*send1)
.previous (send1->hash ())
.balance (send1->balance ().number () - 1)
.link (key.pub)
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
.work (*system.work.generate (send1->hash ()))
.build_shared ();
auto open = builder.make_block ()
.from (*fork)
.link (send2->hash ())
.sign (key.prv, key.pub)
.build_shared ();
ASSERT_EQ (nano::process_result::progress, node.process (*send1).code);
ASSERT_EQ (nano::process_result::progress, node.process (*fork).code);
// Node has fork & doesn't have source for correct block open (send2)
ASSERT_EQ (nullptr, node.block (send2->hash ()));
// Start election for fork
nano::blocks_confirm (node, { fork });
{
auto election = node.active.election (fork->qualified_root ());
ASSERT_NE (nullptr, election);
// Process conflicting block for election
node.process_active (open);
node.block_processor.flush ();
ASSERT_EQ (2, election->blocks ().size ());
ASSERT_EQ (1, election->votes ().size ());
// Confirm open
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, std::numeric_limits<uint64_t>::max (), std::vector<nano::block_hash> (1, open->hash ())));
node.vote_processor.vote (vote1, std::make_shared<nano::transport::channel_loopback> (node));
ASSERT_TIMELY (5s, election->votes ().size () == 2);
ASSERT_TIMELY (3s, election->confirmed ());
}
// Wait for the rollback (attempt to replace fork with open)
ASSERT_TIMELY (5s, node.stats.count (nano::stat::type::rollback, nano::stat::detail::open) == 1);
ASSERT_TIMELY (5s, node.active.empty ());
// But replacing is not possible (missing source block - send2)
node.block_processor.flush ();
ASSERT_EQ (nullptr, node.block (open->hash ()));
ASSERT_EQ (nullptr, node.block (fork->hash ()));
// Fork can be returned by some other forked node or attacker
node.process_active (fork);
node.block_processor.flush ();
ASSERT_NE (nullptr, node.block (fork->hash ()));
// With send2 block in ledger election can start again to remove fork block
ASSERT_EQ (nano::process_result::progress, node.process (*send2).code);
nano::blocks_confirm (node, { fork });
{
auto election = node.active.election (fork->qualified_root ());
ASSERT_NE (nullptr, election);
// Process conflicting block for election
node.process_active (open);
node.block_processor.flush ();
ASSERT_EQ (2, election->blocks ().size ());
// Confirm open (again)
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, std::numeric_limits<uint64_t>::max (), std::vector<nano::block_hash> (1, open->hash ())));
node.vote_processor.vote (vote1, std::make_shared<nano::transport::channel_loopback> (node));
ASSERT_TIMELY (5s, election->votes ().size () == 2);
}
// Wait for new rollback
ASSERT_TIMELY (5s, node.stats.count (nano::stat::type::rollback, nano::stat::detail::open) == 2);
// Now fork block should be replaced with open
node.block_processor.flush ();
ASSERT_NE (nullptr, node.block (open->hash ()));
ASSERT_EQ (nullptr, node.block (fork->hash ()));
}

// Confirm a complex dependency graph starting from the first block
TEST (node, dependency_graph)
{
Expand Down
1 change: 0 additions & 1 deletion nano/node/election.cpp
Expand Up @@ -53,7 +53,6 @@ void nano::election::confirm_once (nano::unique_lock<nano::mutex> & lock_a, nano
status.type = type_a;
auto const status_l = status;
lock_a.unlock ();
node.active.add_recently_confirmed (status_l.winner->qualified_root (), status_l.winner->hash ());
node.process_confirmed (status_l);
node.background ([node_l = node.shared (), status_l, confirmation_action_l = confirmation_action] () {
if (confirmation_action_l)
Expand Down
1 change: 1 addition & 0 deletions nano/node/node.cpp
Expand Up @@ -1353,6 +1353,7 @@ void nano::node::process_confirmed (nano::election_status const & status_a, uint
const auto num_iters = (config.block_processor_batch_max_time / network_params.node.process_confirmed_interval) * 4;
if (auto block_l = ledger.store.block_get (ledger.store.tx_begin_read (), hash))
{
active.add_recently_confirmed (block_l->qualified_root (), hash);
confirmation_height_processor.add (block_l);
}
else if (iteration_a < num_iters)
Expand Down
2 changes: 1 addition & 1 deletion nano/node/nodeconfig.cpp
Expand Up @@ -118,7 +118,7 @@ nano::error nano::node_config::serialize_toml (nano::tomlconfig & toml) const
work_peers_l->push_back (boost::str (boost::format ("%1%:%2%") % i->first % i->second));
}

auto preconfigured_peers_l (toml.create_array ("preconfigured_peers", "A list of \"address\" (hostname or ip address) entries to identify preconfigured peers."));
auto preconfigured_peers_l (toml.create_array ("preconfigured_peers", "A list of \"address\" (hostname or ipv6 notation ip address) entries to identify preconfigured peers."));
for (auto i (preconfigured_peers.begin ()), n (preconfigured_peers.end ()); i != n; ++i)
{
preconfigured_peers_l->push_back (*i);
Expand Down

0 comments on commit ef09e55

Please sign in to comment.