diff --git a/rai/core_test/block_store.cpp b/rai/core_test/block_store.cpp index 4de956c3..5355b220 100644 --- a/rai/core_test/block_store.cpp +++ b/rai/core_test/block_store.cpp @@ -428,7 +428,7 @@ TEST (block_store, latest_exists) rai::transaction transaction (store.environment, nullptr, true); store.account_put (transaction, two, info); rai::block_hash one (1); - ASSERT_FALSE (store.account_exists (one)); + ASSERT_FALSE (store.account_exists (transaction, one)); } TEST (block_store, stack) @@ -635,4 +635,4 @@ TEST (block_store, upgrade_v2_v3) rai::account_info info; ASSERT_FALSE (store.account_get (transaction, rai::test_genesis_key.pub, info)); ASSERT_EQ (change_hash, info.rep_block); -} \ No newline at end of file +} diff --git a/rai/core_test/node.cpp b/rai/core_test/node.cpp index e23a1630..6220f2cb 100644 --- a/rai/core_test/node.cpp +++ b/rai/core_test/node.cpp @@ -1204,3 +1204,37 @@ TEST (node, bootstrap_no_publish) ASSERT_TRUE (node1->active.roots.empty ()); } } + +// Bootstrapping a forked open block should succeed. +TEST (node, bootstrap_fork_open) +{ + rai::system system0 (24000, 2); + system0.wallet(0)->insert_adhoc (rai::test_genesis_key.prv); + auto node0 (system0.nodes [0]); + auto node1 (system0.nodes [1]); + rai::keypair key0; + rai::send_block send0 (system0.nodes [0]->latest (rai::test_genesis_key.pub), key0.pub, rai::genesis_amount - 500, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::open_block open0 (send0.hash (), 1, key0.pub, key0.prv, key0.pub, 0); + rai::open_block open1 (send0.hash (), 2, key0.pub, key0.prv, key0.pub, 0); + node0->generate_work (send0); + node0->generate_work (open0); + node0->generate_work (open1); + { + rai::transaction transaction0 (node0->store.environment, nullptr, true); + rai::transaction transaction1 (node1->store.environment, nullptr, true); + ASSERT_EQ (rai::process_result::progress, node0->ledger.process (transaction0, send0).code); + ASSERT_EQ (rai::process_result::progress, node1->ledger.process (transaction1, send0).code); + ASSERT_EQ (rai::process_result::progress, node0->ledger.process (transaction0, open0).code); + ASSERT_EQ (rai::process_result::progress, node1->ledger.process (transaction1, open1).code); + } + node1->bootstrap_initiator.bootstrap (node0->network.endpoint ()); + ASSERT_TRUE (node1->bootstrap_initiator.in_progress ()); + ASSERT_TRUE (node1->active.roots.empty ()); + int iterations (0); + while (node1->ledger.block_exists (open1.hash ())) + { + system0.poll (); + ASSERT_LT (iterations, 200); + ++iterations; + } +} diff --git a/rai/node/bootstrap.cpp b/rai/node/bootstrap.cpp index 1de63ef6..bef95e4f 100644 --- a/rai/node/bootstrap.cpp +++ b/rai/node/bootstrap.cpp @@ -537,7 +537,7 @@ void rai::bulk_pull_client::process_end () case rai::process_result::fork: { auto node_l (connection->connection->node); - auto block (node_l->store.block_get (transaction_a, node_l->store.block_successor (transaction_a, block_a.root ()))); + auto block (node_l->ledger.forked_block (transaction_a, block_a)); node_l->active.start (transaction_a, *block, [node_l] (rai::block & block_a) { node_l->process_confirmed (block_a); diff --git a/rai/secure.cpp b/rai/secure.cpp index f0064911..c5794899 100644 --- a/rai/secure.cpp +++ b/rai/secure.cpp @@ -1911,10 +1911,9 @@ void rai::block_store::account_del (MDB_txn * transaction_a, rai::account const assert (status == 0); } -bool rai::block_store::account_exists (rai::account const & account_a) +bool rai::block_store::account_exists (MDB_txn * transaction_a, rai::account const & account_a) { - rai::transaction transaction (environment, nullptr, false); - auto iterator (latest_begin (transaction, account_a)); + auto iterator (latest_begin (transaction_a, account_a)); return iterator != rai::store_iterator (nullptr) && rai::account (iterator->first) == account_a; } @@ -2866,10 +2865,10 @@ void rai::ledger::change_latest (MDB_txn * transaction_a, rai::account const & a std::unique_ptr rai::ledger::successor (MDB_txn * transaction_a, rai::block_hash const & block_a) { - assert (store.account_exists (block_a) || store.block_exists (transaction_a, block_a)); - assert (store.account_exists (block_a) || latest (transaction_a, account (transaction_a, block_a)) != block_a); + assert (store.account_exists (transaction_a, block_a) || store.block_exists (transaction_a, block_a)); + assert (store.account_exists (transaction_a, block_a) || latest (transaction_a, account (transaction_a, block_a)) != block_a); rai::block_hash successor; - if (store.account_exists (block_a)) + if (store.account_exists (transaction_a, block_a)) { rai::account_info info; auto error (store.account_get (transaction_a, block_a, info)); @@ -2886,6 +2885,23 @@ std::unique_ptr rai::ledger::successor (MDB_txn * transaction_a, ra return result; } +std::unique_ptr rai::ledger::forked_block (MDB_txn * transaction_a, rai::block const & block_a) +{ + assert (!store.block_exists (transaction_a, block_a.hash ())); + auto root (block_a.root ()); + assert (store.block_exists (transaction_a, root) || store.account_exists (transaction_a, root)); + std::unique_ptr result (store.block_get (transaction_a, store.block_successor (transaction_a, root))); + if (result == nullptr) + { + rai::account_info info; + auto error (store.account_get (transaction_a, root, info)); + assert (!error); + result = store.block_get (transaction_a, info.open_block); + assert (result != nullptr); + } + return result; +} + void ledger_processor::change_block (rai::change_block const & block_a) { auto hash (block_a.hash ()); diff --git a/rai/secure.hpp b/rai/secure.hpp index 92a5e281..a869265a 100644 --- a/rai/secure.hpp +++ b/rai/secure.hpp @@ -320,7 +320,7 @@ public: void account_put (MDB_txn *, rai::account const &, rai::account_info const &); bool account_get (MDB_txn *, rai::account const &, rai::account_info &); void account_del (MDB_txn *, rai::account const &); - bool account_exists (rai::account const &); + bool account_exists (MDB_txn *, rai::account const &); rai::store_iterator latest_begin (MDB_txn *, rai::account const &); rai::store_iterator latest_begin (MDB_txn *); rai::store_iterator latest_end (); @@ -458,6 +458,7 @@ public: rai::uint128_t account_balance (MDB_txn *, rai::account const &); rai::uint128_t weight (MDB_txn *, rai::account const &); std::unique_ptr successor (MDB_txn *, rai::block_hash const &); + std::unique_ptr forked_block (MDB_txn *, rai::block const &); rai::block_hash latest (MDB_txn *, rai::account const &); rai::block_hash latest_root (MDB_txn *, rai::account const &); rai::block_hash representative (MDB_txn *, rai::block_hash const &);