diff --git a/nano/core_test/bootstrap_ascending.cpp b/nano/core_test/bootstrap_ascending.cpp index 015abe203a..4595d08123 100644 --- a/nano/core_test/bootstrap_ascending.cpp +++ b/nano/core_test/bootstrap_ascending.cpp @@ -2,10 +2,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -266,3 +268,219 @@ TEST (bootstrap_ascending, trace_base) // std::cerr << "node1: " << node1.network.endpoint () << std::endl; ASSERT_TIMELY (10s, node1.block (receive1->hash ()) != nullptr); } + +TEST (bootstrap_ascending, pending_database_scanner) +{ + nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits::max () }; + + // Prepare pending sends from genesis + // 1 account with 1 pending + // 1 account with 21 pendings + // 2 accounts with 1 pending each + std::deque> blocks; + nano::keypair key1, key2, key3, key4; + { + nano::state_block_builder builder; + + auto source = nano::dev::genesis_key; + auto latest = nano::dev::genesis->hash (); + auto balance = nano::dev::genesis->balance ().number (); + + // 1 account with 1 pending + { + auto send = builder.make_block () + .account (source.pub) + .previous (latest) + .representative (source.pub) + .link (key1.pub) + .balance (balance - 1) + .sign (source.prv, source.pub) + .work (*pool.generate (latest)) + .build (); + latest = send->hash (); + balance = send->balance_field ().value ().number (); + blocks.push_back (send); + } + // 1 account with 21 pendings + for (int i = 0; i < 21; ++i) + { + auto send = builder.make_block () + .account (source.pub) + .previous (latest) + .representative (source.pub) + .link (key2.pub) + .balance (balance - 1) + .sign (source.prv, source.pub) + .work (*pool.generate (latest)) + .build (); + latest = send->hash (); + balance = send->balance_field ().value ().number (); + blocks.push_back (send); + } + // 2 accounts with 1 pending each + { + auto send = builder.make_block () + .account (source.pub) + .previous (latest) + .representative (source.pub) + .link (key3.pub) + .balance (balance - 1) + .sign (source.prv, source.pub) + .work (*pool.generate (latest)) + .build (); + latest = send->hash (); + balance = send->balance_field ().value ().number (); + blocks.push_back (send); + } + { + auto send = builder.make_block () + .account (source.pub) + .previous (latest) + .representative (source.pub) + .link (key4.pub) + .balance (balance - 1) + .sign (source.prv, source.pub) + .work (*pool.generate (latest)) + .build (); + latest = send->hash (); + balance = send->balance_field ().value ().number (); + blocks.push_back (send); + } + } + + nano::test::ledger_context ctx{ std::move (blocks) }; + + // Single batch + { + nano::bootstrap_ascending::pending_database_iterator scanner{ ctx.ledger () }; + auto transaction = ctx.store ().tx_begin_read (); + auto accounts = scanner.next_batch (transaction, 256); + + // Check that account set contains all keys + ASSERT_EQ (accounts.size (), 4); + ASSERT_TRUE (std::find (accounts.begin (), accounts.end (), key1.pub) != accounts.end ()); + ASSERT_TRUE (std::find (accounts.begin (), accounts.end (), key2.pub) != accounts.end ()); + ASSERT_TRUE (std::find (accounts.begin (), accounts.end (), key3.pub) != accounts.end ()); + ASSERT_TRUE (std::find (accounts.begin (), accounts.end (), key4.pub) != accounts.end ()); + + ASSERT_EQ (scanner.completed, 1); + } + // Multi batch + { + nano::bootstrap_ascending::pending_database_iterator scanner{ ctx.ledger () }; + auto transaction = ctx.store ().tx_begin_read (); + + // Request accounts in multiple batches + auto accounts1 = scanner.next_batch (transaction, 2); + auto accounts2 = scanner.next_batch (transaction, 1); + auto accounts3 = scanner.next_batch (transaction, 1); + + ASSERT_EQ (accounts1.size (), 2); + ASSERT_EQ (accounts2.size (), 1); + ASSERT_EQ (accounts3.size (), 1); + + std::deque accounts; + accounts.insert (accounts.end (), accounts1.begin (), accounts1.end ()); + accounts.insert (accounts.end (), accounts2.begin (), accounts2.end ()); + accounts.insert (accounts.end (), accounts3.begin (), accounts3.end ()); + + // Check that account set contains all keys + ASSERT_EQ (accounts.size (), 4); + ASSERT_TRUE (std::find (accounts.begin (), accounts.end (), key1.pub) != accounts.end ()); + ASSERT_TRUE (std::find (accounts.begin (), accounts.end (), key2.pub) != accounts.end ()); + ASSERT_TRUE (std::find (accounts.begin (), accounts.end (), key3.pub) != accounts.end ()); + ASSERT_TRUE (std::find (accounts.begin (), accounts.end (), key4.pub) != accounts.end ()); + + ASSERT_EQ (scanner.completed, 1); + } +} + +TEST (bootstrap_ascending, account_database_scanner) +{ + nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits::max () }; + + size_t const count = 4; + + // Prepare some accounts + std::deque> blocks; + std::deque keys; + { + nano::state_block_builder builder; + + auto source = nano::dev::genesis_key; + auto latest = nano::dev::genesis->hash (); + auto balance = nano::dev::genesis->balance ().number (); + + for (int i = 0; i < count; ++i) + { + nano::keypair key; + auto send = builder.make_block () + .account (source.pub) + .previous (latest) + .representative (source.pub) + .link (key.pub) + .balance (balance - 1) + .sign (source.prv, source.pub) + .work (*pool.generate (latest)) + .build (); + auto open = builder.make_block () + .account (key.pub) + .previous (0) + .representative (key.pub) + .link (send->hash ()) + .balance (1) + .sign (key.prv, key.pub) + .work (*pool.generate (key.pub)) + .build (); + latest = send->hash (); + balance = send->balance_field ().value ().number (); + blocks.push_back (send); + blocks.push_back (open); + keys.push_back (key); + } + } + + nano::test::ledger_context ctx{ std::move (blocks) }; + + // Single batch + { + nano::bootstrap_ascending::account_database_iterator scanner{ ctx.ledger () }; + auto transaction = ctx.store ().tx_begin_read (); + auto accounts = scanner.next_batch (transaction, 256); + + // Check that account set contains all keys + ASSERT_EQ (accounts.size (), keys.size () + 1); // +1 for genesis + for (auto const & key : keys) + { + ASSERT_TRUE (std::find (accounts.begin (), accounts.end (), key.pub) != accounts.end ()); + } + ASSERT_EQ (scanner.completed, 1); + } + // Multi batch + { + nano::bootstrap_ascending::account_database_iterator scanner{ ctx.ledger () }; + auto transaction = ctx.store ().tx_begin_read (); + + // Request accounts in multiple batches + auto accounts1 = scanner.next_batch (transaction, 2); + auto accounts2 = scanner.next_batch (transaction, 2); + auto accounts3 = scanner.next_batch (transaction, 1); + + ASSERT_EQ (accounts1.size (), 2); + ASSERT_EQ (accounts2.size (), 2); + ASSERT_EQ (accounts3.size (), 1); + + std::deque accounts; + accounts.insert (accounts.end (), accounts1.begin (), accounts1.end ()); + accounts.insert (accounts.end (), accounts2.begin (), accounts2.end ()); + accounts.insert (accounts.end (), accounts3.begin (), accounts3.end ()); + + // Check that account set contains all keys + ASSERT_EQ (accounts.size (), keys.size () + 1); // +1 for genesis + for (auto const & key : keys) + { + ASSERT_TRUE (std::find (accounts.begin (), accounts.end (), key.pub) != accounts.end ()); + } + ASSERT_EQ (scanner.completed, 1); + } +} \ No newline at end of file diff --git a/nano/node/bootstrap_ascending/database_scan.cpp b/nano/node/bootstrap_ascending/database_scan.cpp index 7a7b287fc0..5fac775c37 100644 --- a/nano/node/bootstrap_ascending/database_scan.cpp +++ b/nano/node/bootstrap_ascending/database_scan.cpp @@ -136,7 +136,7 @@ std::deque nano::bootstrap_ascending::pending_database_iterator:: } // If we didn't advance to the next account, perform a fresh lookup - if (it != end && it->first.account != starting_account) + if (it != end && it->first.account == starting_account) { it = ledger.store.pending.begin (transaction, { starting_account.number () + 1, 0 }); }