Fire callback & add to history after confirmation height is set (#2233)

* Fire callback & add to history only after confirmation height is set

* Clear dependent election blocks after a block is confirmed and this is already pending in conf height processor

* Formatting

* Fix failed merge

* Serg review comments

* Formatting
This commit is contained in:
Wesley Shillingford 2019-09-29 11:49:33 +01:00 committed by GitHub
commit ceff5a98fd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 1372 additions and 1034 deletions

View file

@ -4,6 +4,7 @@ add_executable (core_test
active_transactions.cpp
block.cpp
block_store.cpp
confirmation_height.cpp
conflicts.cpp
difficulty.cpp
distributed_work.cpp

File diff suppressed because it is too large Load diff

View file

@ -1473,779 +1473,6 @@ TEST (bootstrap, tcp_node_id_handshake)
}
}
namespace
{
void add_callback_stats (nano::node & node)
{
node.observers.blocks.add ([& stats = node.stats](nano::election_status const & status_a, nano::account const &, nano::amount const &, bool) {
stats.inc (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out);
});
}
}
TEST (confirmation_height, single)
{
auto amount (std::numeric_limits<nano::uint128_t>::max ());
nano::system system (24000, 2);
nano::keypair key1;
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
nano::block_hash latest1 (system.nodes[0]->latest (nano::test_genesis_key.pub));
system.wallet (1)->insert_adhoc (key1.prv);
auto send1 (std::make_shared<nano::send_block> (latest1, key1.pub, amount - system.nodes[0]->config.receive_minimum.number (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (latest1)));
// Check confirmation heights before, should be uninitialized (1 for genesis).
uint64_t confirmation_height;
for (auto & node : system.nodes)
{
add_callback_stats (*node);
auto transaction = node->store.tx_begin_read ();
ASSERT_FALSE (node->store.confirmation_height_get (transaction, nano::test_genesis_key.pub, confirmation_height));
ASSERT_EQ (1, confirmation_height);
}
for (auto & node : system.nodes)
{
node->process_active (send1);
node->block_processor.flush ();
system.deadline_set (10s);
while (true)
{
auto transaction = node->store.tx_begin_read ();
if (node->ledger.block_confirmed (transaction, send1->hash ()))
{
break;
}
ASSERT_NO_ERROR (system.poll ());
}
auto transaction = node->store.tx_begin_write ();
ASSERT_FALSE (node->store.confirmation_height_get (transaction, nano::test_genesis_key.pub, confirmation_height));
ASSERT_EQ (2, confirmation_height);
// Rollbacks should fail as these blocks have been cemented
ASSERT_TRUE (node->ledger.rollback (transaction, latest1));
ASSERT_TRUE (node->ledger.rollback (transaction, send1->hash ()));
ASSERT_EQ (1, node->stats.count (nano::stat::type::confirmation_height, nano::stat::detail::blocks_confirmed, nano::stat::dir::in));
ASSERT_EQ (1, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out));
}
}
TEST (confirmation_height, multiple_accounts)
{
nano::system system;
nano::node_config node_config (24001, system.logging);
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
system.add_node (node_config);
node_config.peering_port = 24002;
system.add_node (node_config);
nano::keypair key1;
nano::keypair key2;
nano::keypair key3;
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
nano::block_hash latest1 (system.nodes[0]->latest (nano::test_genesis_key.pub));
system.wallet (1)->insert_adhoc (key1.prv);
system.wallet (0)->insert_adhoc (key2.prv);
system.wallet (1)->insert_adhoc (key3.prv);
// Send to all accounts
nano::send_block send1 (latest1, key1.pub, system.nodes.front ()->config.online_weight_minimum.number () + 300, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (latest1));
nano::send_block send2 (send1.hash (), key2.pub, system.nodes.front ()->config.online_weight_minimum.number () + 200, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send1.hash ()));
nano::send_block send3 (send2.hash (), key3.pub, system.nodes.front ()->config.online_weight_minimum.number () + 100, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send2.hash ()));
// Open all accounts
nano::open_block open1 (send1.hash (), nano::genesis_account, key1.pub, key1.prv, key1.pub, system.work.generate (key1.pub));
nano::open_block open2 (send2.hash (), nano::genesis_account, key2.pub, key2.prv, key2.pub, system.work.generate (key2.pub));
nano::open_block open3 (send3.hash (), nano::genesis_account, key3.pub, key3.prv, key3.pub, system.work.generate (key3.pub));
// Send and recieve various blocks to these accounts
nano::send_block send4 (open1.hash (), key2.pub, 50, key1.prv, key1.pub, system.work.generate (open1.hash ()));
nano::send_block send5 (send4.hash (), key2.pub, 10, key1.prv, key1.pub, system.work.generate (send4.hash ()));
nano::receive_block receive1 (open2.hash (), send4.hash (), key2.prv, key2.pub, system.work.generate (open2.hash ()));
nano::send_block send6 (receive1.hash (), key3.pub, 10, key2.prv, key2.pub, system.work.generate (receive1.hash ()));
nano::receive_block receive2 (send6.hash (), send5.hash (), key2.prv, key2.pub, system.work.generate (send6.hash ()));
for (auto & node : system.nodes)
{
add_callback_stats (*node);
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, open1).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, send4).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, send5).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, receive1).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, send6).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, receive2).code);
// Check confirmation heights of all the accounts are uninitialized (0),
// as we have any just added them to the ledger and not processed any live transactions yet.
uint64_t confirmation_height;
ASSERT_FALSE (node->store.confirmation_height_get (transaction, nano::test_genesis_key.pub, confirmation_height));
ASSERT_EQ (1, confirmation_height);
ASSERT_FALSE (node->store.confirmation_height_get (transaction, key1.pub, confirmation_height));
ASSERT_EQ (0, confirmation_height);
ASSERT_FALSE (node->store.confirmation_height_get (transaction, key2.pub, confirmation_height));
ASSERT_EQ (0, confirmation_height);
ASSERT_FALSE (node->store.confirmation_height_get (transaction, key3.pub, confirmation_height));
ASSERT_EQ (0, confirmation_height);
}
// The nodes process a live receive which propagates across to all accounts
auto receive3 = std::make_shared<nano::receive_block> (open3.hash (), send6.hash (), key3.prv, key3.pub, system.work.generate (open3.hash ()));
for (auto & node : system.nodes)
{
node->process_active (receive3);
node->block_processor.flush ();
system.deadline_set (10s);
while (true)
{
auto transaction = node->store.tx_begin_read ();
if (node->ledger.block_confirmed (transaction, receive3->hash ()))
{
break;
}
ASSERT_NO_ERROR (system.poll ());
}
nano::account_info account_info;
uint64_t confirmation_height;
auto & store = node->store;
auto transaction = node->store.tx_begin_read ();
ASSERT_FALSE (store.account_get (transaction, nano::test_genesis_key.pub, account_info));
ASSERT_FALSE (node->store.confirmation_height_get (transaction, nano::test_genesis_key.pub, confirmation_height));
ASSERT_EQ (4, confirmation_height);
ASSERT_EQ (4, account_info.block_count);
ASSERT_FALSE (store.account_get (transaction, key1.pub, account_info));
ASSERT_FALSE (node->store.confirmation_height_get (transaction, key1.pub, confirmation_height));
ASSERT_EQ (2, confirmation_height);
ASSERT_EQ (3, account_info.block_count);
ASSERT_FALSE (store.account_get (transaction, key2.pub, account_info));
ASSERT_FALSE (node->store.confirmation_height_get (transaction, key2.pub, confirmation_height));
ASSERT_EQ (3, confirmation_height);
ASSERT_EQ (4, account_info.block_count);
ASSERT_FALSE (store.account_get (transaction, key3.pub, account_info));
ASSERT_FALSE (node->store.confirmation_height_get (transaction, key3.pub, confirmation_height));
ASSERT_EQ (2, confirmation_height);
ASSERT_EQ (2, account_info.block_count);
// The accounts for key1 and key2 have 1 more block in the chain than is confirmed.
// So this can be rolled back, but the one before that cannot. Check that this is the case
{
auto transaction = node->store.tx_begin_write ();
ASSERT_FALSE (node->ledger.rollback (transaction, node->latest (key2.pub)));
ASSERT_FALSE (node->ledger.rollback (transaction, node->latest (key1.pub)));
}
{
// These rollbacks should fail
auto transaction = node->store.tx_begin_write ();
ASSERT_TRUE (node->ledger.rollback (transaction, node->latest (key1.pub)));
ASSERT_TRUE (node->ledger.rollback (transaction, node->latest (key2.pub)));
// Confirm the other latest can't be rolled back either
ASSERT_TRUE (node->ledger.rollback (transaction, node->latest (key3.pub)));
ASSERT_TRUE (node->ledger.rollback (transaction, node->latest (nano::test_genesis_key.pub)));
// Attempt some others which have been cemented
ASSERT_TRUE (node->ledger.rollback (transaction, open1.hash ()));
ASSERT_TRUE (node->ledger.rollback (transaction, send2.hash ()));
}
ASSERT_EQ (10, node->stats.count (nano::stat::type::confirmation_height, nano::stat::detail::blocks_confirmed, nano::stat::dir::in));
ASSERT_EQ (10, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out));
}
}
TEST (confirmation_height, gap_bootstrap)
{
nano::system system (24000, 1);
auto & node1 (*system.nodes[0]);
nano::genesis genesis;
nano::keypair destination;
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::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
node1.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::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
node1.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::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
node1.work_generate_blocking (*send3);
auto open1 (std::make_shared<nano::open_block> (send1->hash (), destination.pub, destination.pub, destination.prv, destination.pub, 0));
node1.work_generate_blocking (*open1);
// Receive
auto receive1 (std::make_shared<nano::receive_block> (open1->hash (), send2->hash (), destination.prv, destination.pub, 0));
node1.work_generate_blocking (*receive1);
auto receive2 (std::make_shared<nano::receive_block> (receive1->hash (), send3->hash (), destination.prv, destination.pub, 0));
node1.work_generate_blocking (*receive2);
node1.block_processor.add (send1);
node1.block_processor.add (send2);
node1.block_processor.add (send3);
node1.block_processor.add (receive1);
node1.block_processor.flush ();
add_callback_stats (node1);
// Receive 2 comes in on the live network, however the chain has not been finished so it gets added to unchecked
node1.process_active (receive2);
node1.block_processor.flush ();
// Confirmation heights should not be updated
{
auto transaction (node1.store.tx_begin_read ());
auto unchecked_count (node1.store.unchecked_count (transaction));
ASSERT_EQ (unchecked_count, 2);
uint64_t confirmation_height;
ASSERT_FALSE (node1.store.confirmation_height_get (transaction, nano::test_genesis_key.pub, confirmation_height));
ASSERT_EQ (1, confirmation_height);
}
// Now complete the chain where the block comes in on the bootstrap network.
node1.block_processor.add (open1);
node1.block_processor.flush ();
// Confirmation height should be unchanged and unchecked should now be 0
{
auto transaction (node1.store.tx_begin_read ());
auto unchecked_count (node1.store.unchecked_count (transaction));
ASSERT_EQ (unchecked_count, 0);
uint64_t confirmation_height;
ASSERT_FALSE (node1.store.confirmation_height_get (transaction, nano::test_genesis_key.pub, confirmation_height));
ASSERT_EQ (1, confirmation_height);
ASSERT_FALSE (node1.store.confirmation_height_get (transaction, destination.pub, confirmation_height));
ASSERT_EQ (0, confirmation_height);
}
ASSERT_EQ (0, node1.stats.count (nano::stat::type::confirmation_height, nano::stat::detail::blocks_confirmed, nano::stat::dir::in));
ASSERT_EQ (0, node1.stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out));
}
TEST (confirmation_height, gap_live)
{
nano::system system;
nano::node_config node_config (24001, system.logging);
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
system.add_node (node_config);
node_config.peering_port = 24002;
system.add_node (node_config);
nano::keypair destination;
system.wallet (0)->insert_adhoc (nano::test_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::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
system.nodes[0]->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::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
system.nodes[0]->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::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
system.nodes[0]->work_generate_blocking (*send3);
auto open1 (std::make_shared<nano::open_block> (send1->hash (), destination.pub, destination.pub, destination.prv, destination.pub, 0));
system.nodes[0]->work_generate_blocking (*open1);
auto receive1 (std::make_shared<nano::receive_block> (open1->hash (), send2->hash (), destination.prv, destination.pub, 0));
system.nodes[0]->work_generate_blocking (*receive1);
auto receive2 (std::make_shared<nano::receive_block> (receive1->hash (), send3->hash (), destination.prv, destination.pub, 0));
system.nodes[0]->work_generate_blocking (*receive2);
for (auto & node : system.nodes)
{
node->block_processor.add (send1);
node->block_processor.add (send2);
node->block_processor.add (send3);
node->block_processor.add (receive1);
node->block_processor.flush ();
add_callback_stats (*node);
// Receive 2 comes in on the live network, however the chain has not been finished so it gets added to unchecked
node->process_active (receive2);
node->block_processor.flush ();
// Confirmation heights should not be updated
{
auto transaction = node->store.tx_begin_read ();
uint64_t confirmation_height;
ASSERT_FALSE (node->store.confirmation_height_get (transaction, nano::test_genesis_key.pub, confirmation_height));
ASSERT_EQ (1, confirmation_height);
}
// Now complete the chain where the block comes in on the live network
node->process_active (open1);
node->block_processor.flush ();
system.deadline_set (10s);
while (true)
{
auto transaction = node->store.tx_begin_read ();
if (node->ledger.block_confirmed (transaction, receive2->hash ()))
{
break;
}
ASSERT_NO_ERROR (system.poll ());
}
// This should confirm the open block and the source of the receive blocks
auto transaction (node->store.tx_begin_read ());
auto unchecked_count (node->store.unchecked_count (transaction));
ASSERT_EQ (unchecked_count, 0);
uint64_t confirmation_height;
ASSERT_FALSE (node->store.confirmation_height_get (transaction, nano::test_genesis_key.pub, confirmation_height));
ASSERT_EQ (4, confirmation_height);
ASSERT_FALSE (node->store.confirmation_height_get (transaction, destination.pub, confirmation_height));
ASSERT_EQ (3, confirmation_height);
ASSERT_EQ (6, node->stats.count (nano::stat::type::confirmation_height, nano::stat::detail::blocks_confirmed, nano::stat::dir::in));
ASSERT_EQ (6, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out));
}
}
TEST (confirmation_height, send_receive_between_2_accounts)
{
nano::system system;
nano::node_config node_config (24000, system.logging);
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto node = system.add_node (node_config);
nano::keypair key1;
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
nano::block_hash latest (node->latest (nano::test_genesis_key.pub));
system.wallet (0)->insert_adhoc (key1.prv);
nano::send_block send1 (latest, key1.pub, node->config.online_weight_minimum.number () + 2, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (latest));
nano::open_block open1 (send1.hash (), nano::genesis_account, key1.pub, key1.prv, key1.pub, system.work.generate (key1.pub));
nano::send_block send2 (open1.hash (), nano::genesis_account, 1000, key1.prv, key1.pub, system.work.generate (open1.hash ()));
nano::send_block send3 (send2.hash (), nano::genesis_account, 900, key1.prv, key1.pub, system.work.generate (send2.hash ()));
nano::send_block send4 (send3.hash (), nano::genesis_account, 500, key1.prv, key1.pub, system.work.generate (send3.hash ()));
nano::receive_block receive1 (send1.hash (), send2.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send1.hash ()));
nano::receive_block receive2 (receive1.hash (), send3.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (receive1.hash ()));
nano::receive_block receive3 (receive2.hash (), send4.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (receive2.hash ()));
nano::send_block send5 (receive3.hash (), key1.pub, node->config.online_weight_minimum.number () + 1, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (receive3.hash ()));
auto receive4 = std::make_shared<nano::receive_block> (send4.hash (), send5.hash (), key1.prv, key1.pub, system.work.generate (send4.hash ()));
// Unpocketed send
nano::keypair key2;
nano::send_block send6 (send5.hash (), key2.pub, node->config.online_weight_minimum.number (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send5.hash ()));
{
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, open1).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, send2).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, receive1).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, receive2).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, receive3).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);
}
add_callback_stats (*node);
node->process_active (receive4);
node->block_processor.flush ();
system.deadline_set (10s);
while (true)
{
auto transaction = node->store.tx_begin_read ();
if (node->ledger.block_confirmed (transaction, receive4->hash ()))
{
break;
}
ASSERT_NO_ERROR (system.poll ());
}
auto transaction (node->store.tx_begin_read ());
nano::account_info account_info;
uint64_t confirmation_height;
ASSERT_FALSE (node->store.account_get (transaction, nano::test_genesis_key.pub, account_info));
ASSERT_FALSE (node->store.confirmation_height_get (transaction, nano::test_genesis_key.pub, confirmation_height));
ASSERT_EQ (6, confirmation_height);
ASSERT_EQ (7, account_info.block_count);
ASSERT_FALSE (node->store.account_get (transaction, key1.pub, account_info));
ASSERT_FALSE (node->store.confirmation_height_get (transaction, key1.pub, confirmation_height));
ASSERT_EQ (5, confirmation_height);
ASSERT_EQ (5, account_info.block_count);
ASSERT_EQ (10, node->stats.count (nano::stat::type::confirmation_height, nano::stat::detail::blocks_confirmed, nano::stat::dir::in));
ASSERT_EQ (10, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out));
ASSERT_EQ (11, node->ledger.cemented_count);
}
TEST (confirmation_height, send_receive_self)
{
nano::system system;
nano::node_config node_config (24000, system.logging);
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto node = system.add_node (node_config);
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
nano::block_hash latest (node->latest (nano::test_genesis_key.pub));
nano::send_block send1 (latest, nano::test_genesis_key.pub, nano::genesis_amount - 2, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (latest));
nano::receive_block receive1 (send1.hash (), send1.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send1.hash ()));
nano::send_block send2 (receive1.hash (), nano::test_genesis_key.pub, nano::genesis_amount - 2, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (receive1.hash ()));
nano::send_block send3 (send2.hash (), nano::test_genesis_key.pub, nano::genesis_amount - 3, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send2.hash ()));
nano::receive_block receive2 (send3.hash (), send2.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send3.hash ()));
auto receive3 = std::make_shared<nano::receive_block> (receive2.hash (), send3.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (receive2.hash ()));
// Send to another account to prevent automatic receiving on the genesis account
nano::keypair key1;
nano::send_block send4 (receive3->hash (), key1.pub, node->config.online_weight_minimum.number (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (receive3->hash ()));
{
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, receive1).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, receive2).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *receive3).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, send4).code);
}
add_callback_stats (*node);
node->block_confirm (receive3);
system.deadline_set (10s);
while (true)
{
auto transaction = node->store.tx_begin_read ();
if (node->ledger.block_confirmed (transaction, receive3->hash ()))
{
break;
}
ASSERT_NO_ERROR (system.poll ());
}
auto transaction (node->store.tx_begin_read ());
nano::account_info account_info;
ASSERT_FALSE (node->store.account_get (transaction, nano::test_genesis_key.pub, account_info));
uint64_t confirmation_height;
ASSERT_FALSE (node->store.confirmation_height_get (transaction, nano::test_genesis_key.pub, confirmation_height));
ASSERT_EQ (7, confirmation_height);
ASSERT_EQ (8, account_info.block_count);
ASSERT_EQ (6, node->stats.count (nano::stat::type::confirmation_height, nano::stat::detail::blocks_confirmed, nano::stat::dir::in));
ASSERT_EQ (6, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out));
ASSERT_EQ (confirmation_height, node->ledger.cemented_count);
}
TEST (confirmation_height, all_block_types)
{
nano::system system;
nano::node_config node_config (24000, system.logging);
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto node = system.add_node (node_config);
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
nano::block_hash latest (node->latest (nano::test_genesis_key.pub));
nano::keypair key1;
nano::keypair key2;
auto & store = node->store;
nano::send_block send (latest, key1.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (latest));
nano::send_block send1 (send.hash (), key2.pub, nano::genesis_amount - nano::Gxrb_ratio * 2, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send.hash ()));
nano::open_block open (send.hash (), nano::test_genesis_key.pub, key1.pub, key1.prv, key1.pub, system.work.generate (key1.pub));
nano::state_block state_open (key2.pub, 0, 0, nano::Gxrb_ratio, send1.hash (), key2.prv, key2.pub, system.work.generate (key2.pub));
nano::send_block send2 (open.hash (), key2.pub, 0, key1.prv, key1.pub, system.work.generate (open.hash ()));
nano::state_block state_receive (key2.pub, state_open.hash (), 0, nano::Gxrb_ratio * 2, send2.hash (), key2.prv, key2.pub, system.work.generate (state_open.hash ()));
nano::state_block state_send (key2.pub, state_receive.hash (), 0, nano::Gxrb_ratio, key1.pub, key2.prv, key2.pub, system.work.generate (state_receive.hash ()));
nano::receive_block receive (send2.hash (), state_send.hash (), key1.prv, key1.pub, system.work.generate (send2.hash ()));
nano::change_block change (receive.hash (), key2.pub, key1.prv, key1.pub, system.work.generate (receive.hash ()));
nano::state_block state_change (key2.pub, state_send.hash (), nano::test_genesis_key.pub, nano::Gxrb_ratio, 0, key2.prv, key2.pub, system.work.generate (state_send.hash ()));
nano::state_block epoch (key2.pub, state_change.hash (), nano::test_genesis_key.pub, nano::Gxrb_ratio, node->ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (state_change.hash ()));
nano::state_block epoch1 (key1.pub, change.hash (), key2.pub, nano::Gxrb_ratio, node->ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (change.hash ()));
nano::state_block state_send1 (key1.pub, epoch1.hash (), 0, nano::Gxrb_ratio - 1, key2.pub, key1.prv, key1.pub, system.work.generate (epoch1.hash ()));
nano::state_block state_receive2 (key2.pub, epoch.hash (), 0, nano::Gxrb_ratio + 1, state_send1.hash (), key2.prv, key2.pub, system.work.generate (epoch.hash ()));
auto state_send2 = std::make_shared<nano::state_block> (key2.pub, state_receive2.hash (), 0, nano::Gxrb_ratio, key1.pub, key2.prv, key2.pub, system.work.generate (state_receive2.hash ()));
nano::state_block state_send3 (key2.pub, state_send2->hash (), 0, nano::Gxrb_ratio - 1, key1.pub, key2.prv, key2.pub, system.work.generate (state_send2->hash ()));
nano::state_block state_send4 (key1.pub, state_send1.hash (), 0, nano::Gxrb_ratio - 2, nano::test_genesis_key.pub, key1.prv, key1.pub, system.work.generate (state_send1.hash ()));
nano::state_block state_receive3 (nano::genesis_account, send1.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio * 2 + 1, state_send4.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send1.hash ()));
{
auto transaction (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, send1).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, open).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, state_open).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, send2).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, state_receive).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, state_send).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, receive).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, change).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, state_change).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, epoch).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, epoch1).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, state_send1).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, state_receive2).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *state_send2).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, state_send3).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, state_send4).code);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, state_receive3).code);
}
add_callback_stats (*node);
node->block_confirm (state_send2);
system.deadline_set (10s);
while (true)
{
auto transaction = node->store.tx_begin_read ();
if (node->ledger.block_confirmed (transaction, state_send2->hash ()))
{
break;
}
ASSERT_NO_ERROR (system.poll ());
}
auto transaction (node->store.tx_begin_read ());
nano::account_info account_info;
uint64_t confirmation_height;
ASSERT_FALSE (node->store.account_get (transaction, nano::test_genesis_key.pub, account_info));
ASSERT_FALSE (node->store.confirmation_height_get (transaction, nano::test_genesis_key.pub, confirmation_height));
ASSERT_EQ (3, confirmation_height);
ASSERT_LE (4, account_info.block_count);
ASSERT_FALSE (node->store.account_get (transaction, key1.pub, account_info));
ASSERT_FALSE (node->store.confirmation_height_get (transaction, key1.pub, confirmation_height));
ASSERT_EQ (6, confirmation_height);
ASSERT_LE (7, account_info.block_count);
ASSERT_FALSE (node->store.account_get (transaction, key2.pub, account_info));
ASSERT_FALSE (node->store.confirmation_height_get (transaction, key2.pub, confirmation_height));
ASSERT_EQ (7, confirmation_height);
ASSERT_LE (8, account_info.block_count);
ASSERT_EQ (15, node->stats.count (nano::stat::type::confirmation_height, nano::stat::detail::blocks_confirmed, nano::stat::dir::in));
ASSERT_EQ (15, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out));
ASSERT_EQ (16, node->ledger.cemented_count);
}
/* Bulk of the this test was taken from the node.fork_flip test */
TEST (confirmation_height, conflict_rollback_cemented)
{
boost::iostreams::stream_buffer<nano::stringstream_mt_sink> sb;
sb.open (nano::stringstream_mt_sink{});
nano::boost_log_cerr_redirect redirect_cerr (&sb);
nano::system system (24000, 2);
auto & node1 (*system.nodes[0]);
auto & node2 (*system.nodes[1]);
ASSERT_EQ (1, node1.network.size ());
nano::keypair key1;
nano::genesis genesis;
auto send1 (std::make_shared<nano::send_block> (genesis.hash (), key1.pub, nano::genesis_amount - 100, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (genesis.hash ())));
nano::publish publish1 (send1);
nano::keypair key2;
auto send2 (std::make_shared<nano::send_block> (genesis.hash (), key2.pub, nano::genesis_amount - 100, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (genesis.hash ())));
nano::publish publish2 (send2);
auto channel1 (node1.network.udp_channels.create (node1.network.endpoint ()));
node1.network.process_message (publish1, channel1);
node1.block_processor.flush ();
auto channel2 (node2.network.udp_channels.create (node1.network.endpoint ()));
node2.network.process_message (publish2, channel2);
node2.block_processor.flush ();
ASSERT_EQ (1, node1.active.size ());
ASSERT_EQ (1, node2.active.size ());
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
node1.network.process_message (publish2, channel1);
node1.block_processor.flush ();
node2.network.process_message (publish1, channel2);
node2.block_processor.flush ();
nano::unique_lock<std::mutex> lock (node2.active.mutex);
auto conflict (node2.active.roots.find (nano::qualified_root (genesis.hash (), genesis.hash ())));
ASSERT_NE (node2.active.roots.end (), conflict);
auto votes1 (conflict->election);
ASSERT_NE (nullptr, votes1);
ASSERT_EQ (1, votes1->last_votes.size ());
lock.unlock ();
// Force blocks to be cemented on both nodes
{
auto transaction (system.nodes[0]->store.tx_begin_write ());
ASSERT_TRUE (node1.store.block_exists (transaction, publish1.block->hash ()));
node1.store.confirmation_height_put (transaction, nano::genesis_account, 2);
}
{
auto transaction (system.nodes[1]->store.tx_begin_write ());
ASSERT_TRUE (node2.store.block_exists (transaction, publish2.block->hash ()));
node2.store.confirmation_height_put (transaction, nano::genesis_account, 2);
}
auto rollback_log_entry = boost::str (boost::format ("Failed to roll back %1%") % send2->hash ().to_string ());
system.deadline_set (20s);
auto done (false);
while (!done)
{
ASSERT_NO_ERROR (system.poll ());
done = (sb.component ()->str ().find (rollback_log_entry) != std::string::npos);
}
auto transaction1 (system.nodes[0]->store.tx_begin_read ());
auto transaction2 (system.nodes[1]->store.tx_begin_read ());
lock.lock ();
auto winner (*votes1->tally ().begin ());
ASSERT_EQ (*publish1.block, *winner.second);
ASSERT_EQ (nano::genesis_amount - 100, winner.first);
ASSERT_TRUE (node1.store.block_exists (transaction1, publish1.block->hash ()));
ASSERT_TRUE (node2.store.block_exists (transaction2, publish2.block->hash ()));
ASSERT_FALSE (node2.store.block_exists (transaction2, publish1.block->hash ()));
}
TEST (confirmation_height, observers)
{
auto amount (std::numeric_limits<nano::uint128_t>::max ());
nano::system system (24000, 1);
auto node1 (system.nodes[0]);
nano::keypair key1;
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
nano::block_hash latest1 (node1->latest (nano::test_genesis_key.pub));
auto send1 (std::make_shared<nano::send_block> (latest1, key1.pub, amount - node1->config.receive_minimum.number (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (latest1)));
add_callback_stats (*node1);
node1->process_active (send1);
node1->block_processor.flush ();
bool confirmed (false);
system.deadline_set (10s);
while (!confirmed)
{
auto transaction = node1->store.tx_begin_read ();
confirmed = node1->ledger.block_confirmed (transaction, send1->hash ());
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (1, node1->stats.count (nano::stat::type::confirmation_height, nano::stat::detail::blocks_confirmed, nano::stat::dir::in));
ASSERT_EQ (1, node1->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out));
}
// This tests when a read has been done and the block no longer exists by the time a write is done
TEST (confirmation_height, modified_chain)
{
nano::system system;
nano::node_config node_config (24000, system.logging);
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto node = system.add_node (node_config);
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
nano::block_hash latest (node->latest (nano::test_genesis_key.pub));
nano::keypair key1;
auto & store = node->store;
auto send = std::make_shared<nano::send_block> (latest, key1.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (latest));
{
auto transaction = node->store.tx_begin_write ();
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send).code);
}
{
// The write guard prevents the confirmation height processor doing any writes
auto write_guard = node->write_database_queue.wait (nano::writer::process_batch);
node->confirmation_height_processor.add (send->hash ());
system.deadline_set (10s);
while (!node->write_database_queue.contains (nano::writer::confirmation_height))
{
ASSERT_NO_ERROR (system.poll ());
}
store.block_del (store.tx_begin_write (), send->hash ());
}
system.deadline_set (10s);
while (node->write_database_queue.contains (nano::writer::confirmation_height))
{
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (1, node->stats.count (nano::stat::type::confirmation_height, nano::stat::detail::invalid_block, nano::stat::dir::in));
}
namespace nano
{
TEST (confirmation_height, pending_observer_callbacks)
{
nano::system system;
nano::node_config node_config (24000, system.logging);
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto node = system.add_node (node_config);
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
nano::block_hash latest (node->latest (nano::test_genesis_key.pub));
nano::keypair key1;
nano::send_block send (latest, key1.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (latest));
auto send1 = std::make_shared<nano::send_block> (send.hash (), key1.pub, nano::genesis_amount - nano::Gxrb_ratio * 2, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send.hash ()));
{
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, *send1).code);
}
add_callback_stats (*node);
node->confirmation_height_processor.add (send1->hash ());
while (true)
{
if (node->pending_confirmation_height.size () == 0)
{
break;
}
}
// Can have timing issues.
node->confirmation_height_processor.add (send.hash ());
{
nano::unique_lock<std::mutex> lk (node->pending_confirmation_height.mutex);
while (!node->pending_confirmation_height.current_hash.is_zero ())
{
lk.unlock ();
std::this_thread::yield ();
lk.lock ();
}
}
// Confirm the callback is not called under this circumstance
ASSERT_EQ (2, node->stats.count (nano::stat::type::confirmation_height, nano::stat::detail::blocks_confirmed, nano::stat::dir::in));
ASSERT_EQ (0, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out));
ASSERT_EQ (3, node->ledger.cemented_count);
}
}
TEST (bootstrap, tcp_listener_timeout_empty)
{
nano::system system (24000, 1);

View file

@ -367,8 +367,10 @@ TEST (node, search_pending_multiple)
TEST (node, search_pending_confirmed)
{
nano::system system (24000, 1);
auto node (system.nodes[0]);
nano::system system;
nano::node_config node_config (24000, system.logging);
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto node = system.add_node (node_config);
nano::keypair key2;
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
auto send1 (system.wallet (0)->send_action (nano::test_genesis_key.pub, key2.pub, node->config.receive_minimum.number ()));
@ -1679,6 +1681,7 @@ TEST (node, broadcast_elected)
node2->process_active (fork1);
//std::cerr << "fork0: " << fork_hash.to_string () << std::endl;
//std::cerr << "fork1: " << fork1.hash ().to_string () << std::endl;
system.deadline_set (10s);
while (!node0->ledger.block_exists (fork0->hash ()) || !node1->ledger.block_exists (fork0->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
@ -3145,203 +3148,6 @@ TEST (node, bidirectional_tcp)
}
}
namespace nano
{
TEST (confirmation_height, prioritize_frontiers)
{
nano::system system;
// Prevent frontiers being confirmed as it will affect the priorization checking
nano::node_config node_config (24001, 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_hash latest1 (system.nodes[0]->latest (nano::test_genesis_key.pub));
// Send different numbers of blocks all accounts
nano::send_block send1 (latest1, key1.pub, node->config.online_weight_minimum.number () + 10000, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (latest1));
nano::send_block send2 (send1.hash (), key1.pub, node->config.online_weight_minimum.number () + 8500, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send1.hash ()));
nano::send_block send3 (send2.hash (), key1.pub, node->config.online_weight_minimum.number () + 8000, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send2.hash ()));
nano::send_block send4 (send3.hash (), key2.pub, node->config.online_weight_minimum.number () + 7500, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send3.hash ()));
nano::send_block send5 (send4.hash (), key3.pub, node->config.online_weight_minimum.number () + 6500, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send4.hash ()));
nano::send_block send6 (send5.hash (), key4.pub, node->config.online_weight_minimum.number () + 6000, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send5.hash ()));
// Open all accounts and add other sends to get different uncemented counts (as well as some which are the same)
nano::open_block open1 (send1.hash (), nano::genesis_account, key1.pub, key1.prv, key1.pub, system.work.generate (key1.pub));
nano::send_block send7 (open1.hash (), nano::test_genesis_key.pub, 500, key1.prv, key1.pub, system.work.generate (open1.hash ()));
nano::open_block open2 (send4.hash (), nano::genesis_account, key2.pub, key2.prv, key2.pub, system.work.generate (key2.pub));
nano::open_block open3 (send5.hash (), nano::genesis_account, key3.pub, key3.prv, key3.pub, system.work.generate (key3.pub));
nano::send_block send8 (open3.hash (), nano::test_genesis_key.pub, 500, key3.prv, key3.pub, system.work.generate (open3.hash ()));
nano::send_block send9 (send8.hash (), nano::test_genesis_key.pub, 200, key3.prv, key3.pub, system.work.generate (send8.hash ()));
nano::open_block open4 (send6.hash (), nano::genesis_account, key4.pub, key4.prv, key4.pub, system.work.generate (key4.pub));
nano::send_block send10 (open4.hash (), nano::test_genesis_key.pub, 500, key4.prv, key4.pub, system.work.generate (open4.hash ()));
nano::send_block send11 (send10.hash (), nano::test_genesis_key.pub, 200, key4.prv, key4.pub, system.work.generate (send10.hash ()));
{
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;
// clang-format off
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);
});
};
// clang-format on
{
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::genesis_account, key3.pub, key4.pub, key1.pub, key2.pub };
std::array<nano::account, num_accounts> desired_order_2{ nano::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::test_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::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::genesis_account, key3.pub, key4.pub, key1.pub, key2.pub };
std::array<nano::account, num_accounts> desired_order_2{ nano::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.
nano::send_block send12 (send9.hash (), nano::test_genesis_key.pub, 100, key3.prv, key3.pub, system.work.generate (send9.hash ()));
nano::send_block send13 (send12.hash (), nano::test_genesis_key.pub, 90, key3.prv, key3.pub, system.work.generate (send12.hash ()));
nano::send_block send14 (send13.hash (), nano::test_genesis_key.pub, 80, key3.prv, key3.pub, system.work.generate (send13.hash ()));
nano::send_block send15 (send14.hash (), nano::test_genesis_key.pub, 70, key3.prv, key3.pub, system.work.generate (send14.hash ()));
nano::send_block send16 (send15.hash (), nano::test_genesis_key.pub, 60, key3.prv, key3.pub, system.work.generate (send15.hash ()));
nano::send_block send17 (send16.hash (), nano::test_genesis_key.pub, 50, key3.prv, key3.pub, system.work.generate (send16.hash ()));
{
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::genesis_account, key4.pub, key1.pub, key2.pub }));
node->active.confirm_frontiers (transaction);
// Check that the active transactions roots contains the frontiers
system.deadline_set (std::chrono::seconds (10));
while (node->active.size () != num_accounts)
{
ASSERT_NO_ERROR (system.poll ());
}
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_NE (node->active.roots.find (frontier), node->active.roots.end ());
}
}
}
TEST (confirmation_height, frontiers_confirmation_mode)
{
nano::genesis genesis;
nano::keypair key;
// Always mode
{
nano::system system;
nano::node_config node_config (24000, system.logging);
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::always;
auto node = system.add_node (node_config);
nano::state_block send (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *node->work_generate_blocking (genesis.hash ()));
{
auto transaction = node->store.tx_begin_write ();
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, send).code);
}
system.deadline_set (5s);
while (node->active.size () != 1)
{
ASSERT_NO_ERROR (system.poll ());
}
}
// Auto mode
{
nano::system system;
nano::node_config node_config (24000, system.logging);
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::automatic;
auto node = system.add_node (node_config);
nano::state_block send (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *node->work_generate_blocking (genesis.hash ()));
{
auto transaction = node->store.tx_begin_write ();
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, send).code);
}
system.deadline_set (5s);
while (node->active.size () != 1)
{
ASSERT_NO_ERROR (system.poll ());
}
}
// Disabled mode
{
nano::system system;
nano::node_config node_config (24000, system.logging);
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto node = system.add_node (node_config);
nano::state_block send (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *node->work_generate_blocking (genesis.hash ()));
{
auto transaction = node->store.tx_begin_write ();
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, send).code);
}
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
std::this_thread::sleep_for (std::chrono::seconds (1));
ASSERT_EQ (0, node->active.size ());
}
}
TEST (active_difficulty, recalculate_work)
{
nano::system system;

View file

@ -101,6 +101,51 @@ void nano::active_transactions::confirm_frontiers (nano::transaction const & tra
next_frontier_check = steady_clock::now () + (agressive_factor / test_network_factor);
}
}
void nano::active_transactions::post_confirmation_height_set (nano::transaction const & transaction_a, std::shared_ptr<nano::block> block_a, nano::block_sideband const & sideband_a, nano::election_status_type election_status_type_a)
{
if (election_status_type_a == nano::election_status_type::inactive_confirmation_height)
{
nano::account account (0);
nano::uint128_t amount (0);
bool is_state_send (false);
nano::account pending_account (0);
node.process_confirmed_data (transaction_a, block_a, block_a->hash (), sideband_a, account, amount, is_state_send, pending_account);
node.observers.blocks.notify (nano::election_status{ block_a, 0, std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::system_clock::now ().time_since_epoch ()), std::chrono::duration_values<std::chrono::milliseconds>::zero (), nano::election_status_type::inactive_confirmation_height }, account, amount, is_state_send);
}
else
{
auto hash (block_a->hash ());
nano::lock_guard<std::mutex> lock (mutex);
auto existing (pending_conf_height.find (hash));
if (existing != pending_conf_height.end ())
{
auto election = existing->second;
if (election->confirmed && !election->stopped && election->status.winner->hash () == hash)
{
add_confirmed (existing->second->status, block_a->qualified_root ());
node.receive_confirmed (transaction_a, block_a, hash);
nano::account account (0);
nano::uint128_t amount (0);
bool is_state_send (false);
nano::account pending_account (0);
node.process_confirmed_data (transaction_a, block_a, hash, sideband_a, account, amount, is_state_send, pending_account);
election->status.type = election_status_type_a;
node.observers.blocks.notify (election->status, account, amount, is_state_send);
if (amount > 0)
{
node.observers.account_balance.notify (account, false);
if (!pending_account.is_zero ())
{
node.observers.account_balance.notify (pending_account, true);
}
}
}
pending_conf_height.erase (hash);
}
}
}
void nano::active_transactions::request_confirm (nano::unique_lock<std::mutex> & lock_a)
{
@ -128,11 +173,10 @@ void nano::active_transactions::request_confirm (nano::unique_lock<std::mutex> &
auto election_l (i->election);
if ((election_l->confirmed || election_l->stopped) && election_l->confirmation_request_count >= minimum_confirmation_request_count - 1)
{
if (election_l->confirmed)
if (election_l->stopped)
{
add_confirmed (election_l->status, root);
inactive.insert (root);
}
inactive.insert (root);
}
else
{
@ -877,7 +921,14 @@ bool nano::active_transactions::publish (std::shared_ptr<nano::block> block_a)
return result;
}
void nano::active_transactions::confirm_block (nano::transaction const & transaction_a, std::shared_ptr<nano::block> block_a, nano::block_sideband const & sideband_a)
void nano::active_transactions::clear_block (nano::block_hash const & hash_a)
{
nano::lock_guard<std::mutex> guard (mutex);
pending_conf_height.erase (hash_a);
}
// Returns the type of election status requiring callbacks calling later
boost::optional<nano::election_status_type> nano::active_transactions::confirm_block (nano::transaction const & transaction_a, std::shared_ptr<nano::block> block_a)
{
auto hash (block_a->hash ());
nano::unique_lock<std::mutex> lock (mutex);
@ -887,17 +938,16 @@ void nano::active_transactions::confirm_block (nano::transaction const & transac
if (!existing->second->confirmed && !existing->second->stopped && existing->second->status.winner->hash () == hash)
{
existing->second->confirm_once (nano::election_status_type::active_confirmation_height);
return nano::election_status_type::active_confirmation_height;
}
else
{
return boost::optional<nano::election_status_type>{};
}
}
else
{
lock.unlock ();
nano::account account (0);
nano::uint128_t amount (0);
bool is_state_send (false);
nano::account pending_account (0);
node.process_confirmed_data (transaction_a, block_a, hash, sideband_a, account, amount, is_state_send, pending_account);
node.observers.blocks.notify (nano::election_status{ block_a, 0, std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::system_clock::now ().time_since_epoch ()), std::chrono::duration_values<std::chrono::milliseconds>::zero (), nano::election_status_type::inactive_confirmation_height }, account, amount, is_state_send);
return nano::election_status_type::inactive_confirmation_height;
}
}
@ -985,17 +1035,20 @@ std::unique_ptr<seq_con_info_component> collect_seq_con_info (active_transaction
size_t roots_count = 0;
size_t blocks_count = 0;
size_t confirmed_count = 0;
size_t pending_conf_height_count = 0;
{
nano::lock_guard<std::mutex> guard (active_transactions.mutex);
roots_count = active_transactions.roots.size ();
blocks_count = active_transactions.blocks.size ();
confirmed_count = active_transactions.confirmed.size ();
pending_conf_height_count = active_transactions.pending_conf_height.size ();
}
auto composite = std::make_unique<seq_con_info_composite> (name);
composite->add_component (std::make_unique<seq_con_info_leaf> (seq_con_info{ "roots", roots_count, sizeof (decltype (active_transactions.roots)::value_type) }));
composite->add_component (std::make_unique<seq_con_info_leaf> (seq_con_info{ "blocks", blocks_count, sizeof (decltype (active_transactions.blocks)::value_type) }));
composite->add_component (std::make_unique<seq_con_info_leaf> (seq_con_info{ "pending_conf_height", pending_conf_height_count, sizeof (decltype (active_transactions.pending_conf_height)::value_type) }));
composite->add_component (std::make_unique<seq_con_info_leaf> (seq_con_info{ "confirmed", confirmed_count, sizeof (decltype (active_transactions.confirmed)::value_type) }));
composite->add_component (std::make_unique<seq_con_info_leaf> (seq_con_info{ "priority_wallet_cementable_frontiers_count", active_transactions.priority_wallet_cementable_frontiers_size (), sizeof (nano::cementable_account) }));
composite->add_component (std::make_unique<seq_con_info_leaf> (seq_con_info{ "priority_cementable_frontiers_count", active_transactions.priority_cementable_frontiers_size (), sizeof (nano::cementable_account) }));

View file

@ -106,7 +106,8 @@ public:
size_t size ();
void stop ();
bool publish (std::shared_ptr<nano::block> block_a);
void confirm_block (nano::transaction const &, std::shared_ptr<nano::block>, nano::block_sideband const &);
boost::optional<nano::election_status_type> confirm_block (nano::transaction const &, std::shared_ptr<nano::block>);
void post_confirmation_height_set (nano::transaction const & transaction_a, std::shared_ptr<nano::block> block_a, nano::block_sideband const & sideband_a, nano::election_status_type election_status_type_a);
boost::multi_index_container<
nano::conflict_info,
boost::multi_index::indexed_by<
@ -136,6 +137,8 @@ public:
size_t priority_wallet_cementable_frontiers_size ();
boost::circular_buffer<double> difficulty_trend ();
size_t inactive_votes_cache_size ();
std::unordered_map<nano::block_hash, std::shared_ptr<nano::election>> pending_conf_height;
void clear_block (nano::block_hash const & hash_a);
private:
// Call action with confirmed block, may be different than what we started with

View file

@ -4,6 +4,7 @@
#include <nano/lib/utility.hpp>
#include <nano/node/active_transactions.hpp>
#include <nano/node/confirmation_height_processor.hpp>
#include <nano/node/election.hpp>
#include <nano/node/write_database_queue.hpp>
#include <nano/secure/blockstore.hpp>
#include <nano/secure/common.hpp>
@ -48,7 +49,7 @@ void nano::confirmation_height_processor::run ()
nano::unique_lock<std::mutex> lk (pending_confirmations.mutex);
while (!stopped)
{
if (!pending_confirmations.pending.empty ())
if (!paused && !pending_confirmations.pending.empty ())
{
pending_confirmations.current_hash = *pending_confirmations.pending.begin ();
pending_confirmations.pending.erase (pending_confirmations.current_hash);
@ -83,6 +84,17 @@ void nano::confirmation_height_processor::run ()
}
}
void nano::confirmation_height_processor::pause ()
{
paused = true;
}
void nano::confirmation_height_processor::unpause ()
{
paused = false;
condition.notify_one ();
}
void nano::confirmation_height_processor::add (nano::block_hash const & hash_a)
{
{
@ -106,6 +118,7 @@ void nano::confirmation_height_processor::add_confirmation_height (nano::block_h
release_assert (receive_source_pairs.empty ());
auto read_transaction (ledger.store.tx_begin_read ());
auto last_iteration = false;
// Traverse account chain and all sources for receive blocks iteratively
do
{
@ -123,6 +136,7 @@ void nano::confirmation_height_processor::add_confirmation_height (nano::block_h
{
current = hash_a;
receive_details = boost::none;
last_iteration = true;
}
}
@ -145,7 +159,25 @@ void nano::confirmation_height_processor::add_confirmation_height (nano::block_h
}
}
if (!last_iteration && current == hash_a && confirmation_height >= block_height)
{
auto it = std::find_if (pending_writes.begin (), pending_writes.end (), [&hash_a](auto & conf_height_details) {
auto it = std::find_if (conf_height_details.block_callbacks_required.begin (), conf_height_details.block_callbacks_required.end (), [&hash_a](auto & callback_data) {
return callback_data.block->hash () == hash_a;
});
return (it != conf_height_details.block_callbacks_required.end ());
});
if (it == pending_writes.end ())
{
// This is a block which has been added to the processor but already has its confirmation height set (or about to be set)
// Just need to perform active cleanup, no callbacks are needed.
active.clear_block (hash_a);
}
}
auto count_before_receive = receive_source_pairs.size ();
std::vector<callback_data> block_callbacks_required;
if (block_height > iterated_height)
{
if ((block_height - iterated_height) > 20000)
@ -153,7 +185,7 @@ void nano::confirmation_height_processor::add_confirmation_height (nano::block_h
logger.always_log ("Iterating over a large account chain for setting confirmation height. The top block: ", current.to_string ());
}
collect_unconfirmed_receive_and_sources_for_account (block_height, iterated_height, current, account, read_transaction);
collect_unconfirmed_receive_and_sources_for_account (block_height, iterated_height, current, account, read_transaction, block_callbacks_required);
}
// Exit early when the processor has been stopped, otherwise this function may take a
@ -187,7 +219,7 @@ void nano::confirmation_height_processor::add_confirmation_height (nano::block_h
confirmed_iterated_pairs.emplace (account, confirmed_iterated_pair{ block_height, block_height });
}
pending_writes.emplace_back (account, current, block_height, block_height - confirmation_height);
pending_writes.emplace_back (account, current, block_height, block_height - confirmation_height, block_callbacks_required);
}
if (receive_details)
@ -298,6 +330,11 @@ bool nano::confirmation_height_processor::write_pending (std::deque<conf_height_
return true;
}
for (auto & callback_data : pending.block_callbacks_required)
{
active.post_confirmation_height_set (transaction, callback_data.block, callback_data.sideband, callback_data.election_status_type);
}
ledger.stats.add (nano::stat::type::confirmation_height, nano::stat::detail::blocks_confirmed, nano::stat::dir::in, pending.height - confirmation_height);
assert (pending.num_blocks_confirmed == pending.height - confirmation_height);
confirmation_height = pending.height;
@ -319,7 +356,7 @@ bool nano::confirmation_height_processor::write_pending (std::deque<conf_height_
return false;
}
void nano::confirmation_height_processor::collect_unconfirmed_receive_and_sources_for_account (uint64_t block_height_a, uint64_t confirmation_height_a, nano::block_hash const & hash_a, nano::account const & account_a, nano::read_transaction const & transaction_a)
void nano::confirmation_height_processor::collect_unconfirmed_receive_and_sources_for_account (uint64_t block_height_a, uint64_t confirmation_height_a, nano::block_hash const & hash_a, nano::account const & account_a, nano::read_transaction const & transaction_a, std::vector<callback_data> & block_callbacks_required)
{
auto hash (hash_a);
auto num_to_confirm = block_height_a - confirmation_height_a;
@ -335,8 +372,18 @@ void nano::confirmation_height_processor::collect_unconfirmed_receive_and_source
{
if (!pending_confirmations.is_processing_block (hash))
{
active.confirm_block (transaction_a, block, sideband);
auto election_status_type = active.confirm_block (transaction_a, block);
if (election_status_type.is_initialized ())
{
block_callbacks_required.emplace_back (block, sideband, *election_status_type);
}
}
else
{
// This block is the original which is having its confirmation height set on
block_callbacks_required.emplace_back (block, sideband, nano::election_status_type::active_confirmed_quorum);
}
auto source (block->source ());
if (source.is_zero ())
{
@ -350,9 +397,15 @@ void nano::confirmation_height_processor::collect_unconfirmed_receive_and_source
if (next_height != height_not_set)
{
receive_source_pairs.back ().receive_details.num_blocks_confirmed = next_height - block_height;
auto & receive_callbacks_required = receive_source_pairs.back ().receive_details.block_callbacks_required;
// Don't include the last one as that belongs to the next recieve
std::copy (block_callbacks_required.begin (), block_callbacks_required.end () - 1, std::back_inserter (receive_callbacks_required));
block_callbacks_required = { block_callbacks_required.back () };
}
receive_source_pairs.emplace_back (conf_height_details{ account_a, hash, block_height, height_not_set }, source);
receive_source_pairs.emplace_back (conf_height_details{ account_a, hash, block_height, height_not_set, {} }, source);
++receive_source_pairs_size;
next_height = block_height;
}
@ -374,16 +427,18 @@ void nano::confirmation_height_processor::collect_unconfirmed_receive_and_source
{
auto & last_receive_details = receive_source_pairs.back ().receive_details;
last_receive_details.num_blocks_confirmed = last_receive_details.height - confirmation_height_a;
last_receive_details.block_callbacks_required = block_callbacks_required;
}
}
namespace nano
{
confirmation_height_processor::conf_height_details::conf_height_details (nano::account const & account_a, nano::block_hash const & hash_a, uint64_t height_a, uint64_t num_blocks_confirmed_a) :
confirmation_height_processor::conf_height_details::conf_height_details (nano::account const & account_a, nano::block_hash const & hash_a, uint64_t height_a, uint64_t num_blocks_confirmed_a, std::vector<callback_data> const & block_callbacks_required_a) :
account (account_a),
hash (hash_a),
height (height_a),
num_blocks_confirmed (num_blocks_confirmed_a)
num_blocks_confirmed (num_blocks_confirmed_a),
block_callbacks_required (block_callbacks_required_a)
{
}
@ -398,6 +453,13 @@ confirmed_height (confirmed_height_a), iterated_height (iterated_height_a)
{
}
confirmation_height_processor::callback_data::callback_data (std::shared_ptr<nano::block> const & block_a, nano::block_sideband const & sideband_a, nano::election_status_type election_status_type_a) :
block (block_a),
sideband (sideband_a),
election_status_type (election_status_type_a)
{
}
std::unique_ptr<seq_con_info_component> collect_seq_con_info (confirmation_height_processor & confirmation_height_processor_a, const std::string & name_a)
{
size_t receive_source_pairs_count = confirmation_height_processor_a.receive_source_pairs_size;

View file

@ -1,6 +1,8 @@
#pragma once
#include <nano/lib/numbers.hpp>
#include <nano/node/active_transactions.hpp>
#include <nano/secure/blockstore.hpp>
#include <nano/secure/common.hpp>
#include <condition_variable>
@ -30,6 +32,8 @@ private:
nano::block_hash current_hash{ 0 };
friend class confirmation_height_processor;
friend class confirmation_height_pending_observer_callbacks_Test;
friend class confirmation_height_dependent_election_Test;
friend class confirmation_height_dependent_election_after_already_cemented_Test;
};
std::unique_ptr<seq_con_info_component> collect_seq_con_info (pending_confirmation_height &, const std::string &);
@ -41,6 +45,8 @@ public:
~confirmation_height_processor ();
void add (nano::block_hash const &);
void stop ();
void pause ();
void unpause ();
/** The maximum amount of accounts to iterate over while writing */
static uint64_t constexpr batch_write_size = 2048;
@ -49,15 +55,25 @@ public:
static uint64_t constexpr batch_read_size = 4096;
private:
class callback_data final
{
public:
callback_data (std::shared_ptr<nano::block> const &, nano::block_sideband const &, nano::election_status_type);
std::shared_ptr<nano::block> block;
nano::block_sideband sideband;
nano::election_status_type election_status_type;
};
class conf_height_details final
{
public:
conf_height_details (nano::account const &, nano::block_hash const &, uint64_t, uint64_t);
conf_height_details (nano::account const &, nano::block_hash const &, uint64_t, uint64_t, std::vector<callback_data> const &);
nano::account account;
nano::block_hash hash;
uint64_t height;
uint64_t num_blocks_confirmed;
std::vector<callback_data> block_callbacks_required;
};
class receive_source_pair final
@ -80,6 +96,7 @@ private:
nano::condition_variable condition;
nano::pending_confirmation_height & pending_confirmations;
std::atomic<bool> stopped{ false };
std::atomic<bool> paused{ false };
nano::ledger & ledger;
nano::active_transactions & active;
nano::logger_mt & logger;
@ -97,7 +114,7 @@ private:
void run ();
void add_confirmation_height (nano::block_hash const &);
void collect_unconfirmed_receive_and_sources_for_account (uint64_t, uint64_t, nano::block_hash const &, nano::account const &, nano::read_transaction const &);
void collect_unconfirmed_receive_and_sources_for_account (uint64_t, uint64_t, nano::block_hash const &, nano::account const &, nano::read_transaction const &, std::vector<callback_data> &);
bool write_pending (std::deque<conf_height_details> &);
friend std::unique_ptr<seq_con_info_component> collect_seq_con_info (confirmation_height_processor &, const std::string &);

View file

@ -51,7 +51,7 @@ void nano::election::confirm_once (nano::election_status_type type_a)
--node.active.long_unconfirmed_size;
}
auto root (status.winner->qualified_root ());
node.active.add_confirmed (status, root);
node.active.pending_conf_height.emplace (status.winner->hash (), shared_from_this ());
clear_blocks ();
clear_dependent ();
node.active.roots.erase (root);

View file

@ -687,6 +687,7 @@ void nano::node::stop ()
if (!stopped.exchange (true))
{
logger.always_log ("Node stopping");
write_database_queue.stop ();
block_processor.stop ();
if (block_processor_thread.joinable ())
{
@ -706,7 +707,6 @@ void nano::node::stop ()
checker.stop ();
wallets.stop ();
stats.stop ();
write_database_queue.stop ();
worker.stop ();
// work pool is not stopped on purpose due to testing setup
}
@ -1181,41 +1181,27 @@ void nano::node::process_confirmed_data (nano::transaction const & transaction_a
void nano::node::process_confirmed (nano::election_status const & status_a, uint8_t iteration)
{
auto block_a (status_a.winner);
auto hash (block_a->hash ());
nano::block_sideband sideband;
auto transaction (store.tx_begin_read ());
if (store.block_get (transaction, hash, &sideband) != nullptr)
if (status_a.type == nano::election_status_type::active_confirmed_quorum)
{
confirmation_height_processor.add (hash);
receive_confirmed (transaction, block_a, hash);
nano::account account (0);
nano::uint128_t amount (0);
bool is_state_send (false);
nano::account pending_account (0);
process_confirmed_data (transaction, block_a, hash, sideband, account, amount, is_state_send, pending_account);
observers.blocks.notify (status_a, account, amount, is_state_send);
if (amount > 0)
auto block_a (status_a.winner);
auto hash (block_a->hash ());
auto transaction (store.tx_begin_read ());
if (store.block_get (transaction, hash) != nullptr)
{
observers.account_balance.notify (account, false);
if (!pending_account.is_zero ())
{
observers.account_balance.notify (pending_account, true);
}
confirmation_height_processor.add (hash);
}
// Limit to 0.5 * 20 = 10 seconds (more than max block_processor::process_batch finish time)
else if (iteration < 20)
{
iteration++;
std::weak_ptr<nano::node> node_w (shared ());
alarm.add (std::chrono::steady_clock::now () + network_params.node.process_confirmed_interval, [node_w, status_a, iteration]() {
if (auto node_l = node_w.lock ())
{
node_l->process_confirmed (status_a, iteration);
}
});
}
}
// Limit to 0.5 * 20 = 10 seconds (more than max block_processor::process_batch finish time)
else if (iteration < 20)
{
iteration++;
std::weak_ptr<nano::node> node_w (shared ());
alarm.add (std::chrono::steady_clock::now () + network_params.node.process_confirmed_interval, [node_w, status_a, iteration]() {
if (auto node_l = node_w.lock ())
{
node_l->process_confirmed (status_a, iteration);
}
});
}
}
@ -1379,12 +1365,10 @@ std::unique_ptr<nano::block_store> nano::make_store (nano::logger_mt & logger, b
#if NANO_ROCKSDB
/** To use RocksDB in tests make sure the node is built with the cmake variable -DNANO_ROCKSDB=ON and the environment variable TEST_USE_ROCKSDB=1 is set */
static nano::network_constants network_constants;
if (auto use_rocksdb_str = std::getenv ("TEST_USE_ROCKSDB") && network_constants.is_test_network ())
auto use_rocksdb_str = std::getenv ("TEST_USE_ROCKSDB");
if (use_rocksdb_str && (boost::lexical_cast<int> (use_rocksdb_str) == 1) && network_constants.is_test_network ())
{
if (boost::lexical_cast<int> (use_rocksdb_str) == 1)
{
return make_rocksdb ();
}
return make_rocksdb ();
}
#endif
}

View file

@ -12,7 +12,8 @@ namespace nano
enum class writer
{
confirmation_height,
process_batch
process_batch,
testing // Used in tests to emulate a write lock
};
class write_guard final