account_exists needs to be transactional

Adding ledger::forked_block as a utility function to retrieve the block with which block_a conflicts in the local ledger.  Since this could be either an open_block fork or normal fork, which have different semantics.
This commit is contained in:
clemahieu 2017-01-22 22:29:06 -06:00
commit 4a661979ce
5 changed files with 61 additions and 10 deletions

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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::block> 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::block> rai::ledger::successor (MDB_txn * transaction_a, ra
return result;
}
std::unique_ptr <rai::block> 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 <rai::block> 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 ());

View file

@ -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 <rai::block> successor (MDB_txn *, rai::block_hash const &);
std::unique_ptr <rai::block> 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 &);