Add confirmation height (#1770)

* Upgrade database confirmation height to 0

* Constify getters

* Set confirmation when blocks are confirmed

* iterative solution working however it needs to only do it on live confirmations

* Update with new sideband height open blocks starting at 1

* Remove unnecessary changes. Make sure it is done with live transactions now.

* Formatting

* Fix incorrect merge

* Update account info in db separately from traversing old data

* Add account_confirmation_height RPC

* Fix 128 nested deep blocks error with MSVC

* Remove unneeded include

* Add confirmation_height_clear CLI optional option to --snapshot

* Check confirmation height in --snapshot option is not 0 before trying to write.

* Add --confirmation_height_clear as an independent CLI option

* Make review suggestions

* Be able to selectively clear confirmation height for an account via CLI

* Remove old test and the unnecessary check for confirmation == 0. Review comments & formatting

* Add tests for accounts which have gaps in them, and remove unused unchecked_exist () function

* Add missing block_confirmed rpc_handler function to map after merge

* Make release_assert a gtest assert in block_store test

* Put transaction back to read in process_confirmed
This commit is contained in:
Wesley Shillingford 2019-03-03 16:29:21 +00:00 committed by GitHub
commit 2a3b1d5393
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1170 additions and 333 deletions

View file

@ -6,6 +6,12 @@
#include <fstream>
namespace
{
void modify_account_info_to_v13 (nano::mdb_store & store, nano::transaction const & transaction_a, nano::account const & account_a);
void modify_genesis_account_info_to_v5 (nano::mdb_store & store, nano::transaction const & transaction_a);
}
TEST (block_store, construction)
{
nano::logging logging;
@ -474,7 +480,7 @@ TEST (block_store, frontier_retrieval)
nano::mdb_store store (init, logging, nano::unique_path ());
ASSERT_TRUE (!init);
nano::account account1 (0);
nano::account_info info1 (0, 0, 0, 0, 0, 0, nano::epoch::epoch_0);
nano::account_info info1 (0, 0, 0, 0, 0, 0, 0, nano::epoch::epoch_0);
auto transaction (store.tx_begin (true));
store.account_put (transaction, account1, info1);
nano::account_info info2;
@ -491,7 +497,7 @@ TEST (block_store, one_account)
nano::account account (0);
nano::block_hash hash (0);
auto transaction (store.tx_begin (true));
store.account_put (transaction, account, { hash, account, hash, 42, 100, 200, nano::epoch::epoch_0 });
store.account_put (transaction, account, { hash, account, hash, 42, 100, 200, 20, nano::epoch::epoch_0 });
auto begin (store.latest_begin (transaction));
auto end (store.latest_end ());
ASSERT_NE (end, begin);
@ -501,6 +507,7 @@ TEST (block_store, one_account)
ASSERT_EQ (42, info.balance.number ());
ASSERT_EQ (100, info.modified);
ASSERT_EQ (200, info.block_count);
ASSERT_EQ (20, info.confirmation_height);
++begin;
ASSERT_EQ (end, begin);
}
@ -535,14 +542,13 @@ TEST (block_store, two_account)
bool init (false);
nano::mdb_store store (init, logging, nano::unique_path ());
ASSERT_TRUE (!init);
store.stop ();
nano::account account1 (1);
nano::block_hash hash1 (2);
nano::account account2 (3);
nano::block_hash hash2 (4);
auto transaction (store.tx_begin (true));
store.account_put (transaction, account1, { hash1, account1, hash1, 42, 100, 300, nano::epoch::epoch_0 });
store.account_put (transaction, account2, { hash2, account2, hash2, 84, 200, 400, nano::epoch::epoch_0 });
store.account_put (transaction, account1, { hash1, account1, hash1, 42, 100, 300, 20, nano::epoch::epoch_0 });
store.account_put (transaction, account2, { hash2, account2, hash2, 84, 200, 400, 30, nano::epoch::epoch_0 });
auto begin (store.latest_begin (transaction));
auto end (store.latest_end ());
ASSERT_NE (end, begin);
@ -552,6 +558,7 @@ TEST (block_store, two_account)
ASSERT_EQ (42, info1.balance.number ());
ASSERT_EQ (100, info1.modified);
ASSERT_EQ (300, info1.block_count);
ASSERT_EQ (20, info1.confirmation_height);
++begin;
ASSERT_NE (end, begin);
ASSERT_EQ (account2, nano::account (begin->first));
@ -560,6 +567,7 @@ TEST (block_store, two_account)
ASSERT_EQ (84, info2.balance.number ());
ASSERT_EQ (200, info2.modified);
ASSERT_EQ (400, info2.block_count);
ASSERT_EQ (30, info2.confirmation_height);
++begin;
ASSERT_EQ (end, begin);
}
@ -570,14 +578,13 @@ TEST (block_store, latest_find)
bool init (false);
nano::mdb_store store (init, logging, nano::unique_path ());
ASSERT_TRUE (!init);
store.stop ();
nano::account account1 (1);
nano::block_hash hash1 (2);
nano::account account2 (3);
nano::block_hash hash2 (4);
auto transaction (store.tx_begin (true));
store.account_put (transaction, account1, { hash1, account1, hash1, 100, 0, 300, nano::epoch::epoch_0 });
store.account_put (transaction, account2, { hash2, account2, hash2, 200, 0, 400, nano::epoch::epoch_0 });
store.account_put (transaction, account1, { hash1, account1, hash1, 100, 0, 300, 0, nano::epoch::epoch_0 });
store.account_put (transaction, account2, { hash2, account2, hash2, 200, 0, 400, 0, nano::epoch::epoch_0 });
auto first (store.latest_begin (transaction));
auto second (store.latest_begin (transaction));
++second;
@ -786,7 +793,6 @@ TEST (block_store, upgrade_v2_v3)
bool init (false);
nano::mdb_store store (init, logging, path);
ASSERT_TRUE (!init);
store.stop ();
auto transaction (store.tx_begin (true));
nano::genesis genesis;
auto hash (genesis.hash ());
@ -837,7 +843,6 @@ TEST (block_store, upgrade_v3_v4)
bool init (false);
nano::mdb_store store (init, logging, path);
ASSERT_FALSE (init);
store.stop ();
auto transaction (store.tx_begin (true));
store.version_put (transaction, 3);
nano::pending_info_v3 info (key1.pub, 100, key2.pub);
@ -871,7 +876,6 @@ TEST (block_store, upgrade_v4_v5)
bool init (false);
nano::mdb_store store (init, logging, path);
ASSERT_FALSE (init);
store.stop ();
auto transaction (store.tx_begin (true));
nano::genesis genesis;
nano::stat stats;
@ -879,7 +883,7 @@ TEST (block_store, upgrade_v4_v5)
store.initialize (transaction, genesis);
store.version_put (transaction, 4);
nano::account_info info;
store.account_get (transaction, nano::test_genesis_key.pub, info);
ASSERT_FALSE (store.account_get (transaction, nano::test_genesis_key.pub, info));
nano::keypair key0;
nano::send_block block0 (info.head, key0.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, block0).code);
@ -888,11 +892,7 @@ TEST (block_store, upgrade_v4_v5)
genesis_hash = info.head;
store.block_successor_clear (transaction, info.head);
ASSERT_TRUE (store.block_successor (transaction, genesis_hash).is_zero ());
nano::account_info info2;
store.account_get (transaction, nano::test_genesis_key.pub, info2);
nano::account_info_v5 info_old (info2.head, info2.rep_block, info2.open_block, info2.balance, info2.modified);
auto status (mdb_put (store.env.tx (transaction), store.accounts_v0, nano::mdb_val (nano::test_genesis_key.pub), info_old.val (), 0));
assert (status == 0);
modify_genesis_account_info_to_v5 (store, transaction);
}
nano::logging logging;
bool init (false);
@ -924,16 +924,11 @@ TEST (block_store, upgrade_v5_v6)
bool init (false);
nano::mdb_store store (init, logging, path);
ASSERT_FALSE (init);
store.stop ();
auto transaction (store.tx_begin (true));
nano::genesis genesis;
store.initialize (transaction, genesis);
store.version_put (transaction, 5);
nano::account_info info;
store.account_get (transaction, nano::test_genesis_key.pub, info);
nano::account_info_v5 info_old (info.head, info.rep_block, info.open_block, info.balance, info.modified);
auto status (mdb_put (store.env.tx (transaction), store.accounts_v0, nano::mdb_val (nano::test_genesis_key.pub), info_old.val (), 0));
assert (status == 0);
modify_genesis_account_info_to_v5 (store, transaction);
}
nano::logging logging;
bool init (false);
@ -953,11 +948,11 @@ TEST (block_store, upgrade_v6_v7)
bool init (false);
nano::mdb_store store (init, logging, path);
ASSERT_FALSE (init);
store.stop ();
auto transaction (store.tx_begin (true));
nano::genesis genesis;
store.initialize (transaction, genesis);
store.version_put (transaction, 6);
modify_account_info_to_v13 (store, transaction, nano::genesis_account);
auto send1 (std::make_shared<nano::send_block> (0, 0, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
store.unchecked_put (transaction, send1->hash (), send1);
store.flush (transaction);
@ -1024,7 +1019,6 @@ TEST (block_store, upgrade_v7_v8)
nano::logging logging;
bool init (false);
nano::mdb_store store (init, logging, path);
store.stop ();
auto transaction (store.tx_begin (true));
ASSERT_EQ (0, mdb_drop (store.env.tx (transaction), store.unchecked, 1));
ASSERT_EQ (0, mdb_dbi_open (store.env.tx (transaction), "unchecked", MDB_CREATE, &store.unchecked));
@ -1097,7 +1091,6 @@ TEST (block_store, upgrade_v8_v9)
nano::logging logging;
bool init (false);
nano::mdb_store store (init, logging, path);
store.stop ();
auto transaction (store.tx_begin (true));
ASSERT_EQ (0, mdb_drop (store.env.tx (transaction), store.vote, 1));
ASSERT_EQ (0, mdb_dbi_open (store.env.tx (transaction), "sequence", MDB_CREATE, &store.vote));
@ -1174,10 +1167,10 @@ TEST (block_store, upgrade_sideband_genesis)
nano::logging logging;
nano::mdb_store store (error, logging, path);
ASSERT_FALSE (error);
store.stop ();
auto transaction (store.tx_begin (true));
store.version_put (transaction, 11);
store.initialize (transaction, genesis);
modify_account_info_to_v13 (store, transaction, nano::genesis_account);
nano::block_sideband sideband;
auto genesis_block (store.block_get (transaction, genesis.hash (), &sideband));
ASSERT_NE (nullptr, genesis_block);
@ -1190,17 +1183,8 @@ TEST (block_store, upgrade_sideband_genesis)
nano::logging logging;
nano::mdb_store store (error, logging, path);
ASSERT_FALSE (error);
auto done (false);
auto iterations (0);
while (!done)
{
std::this_thread::sleep_for (std::chrono::milliseconds (10));
auto transaction (store.tx_begin (false));
done = store.full_sideband (transaction);
ASSERT_LT (iterations, 200);
++iterations;
}
auto transaction (store.tx_begin_read ());
ASSERT_TRUE (store.full_sideband (transaction));
nano::block_sideband sideband;
auto genesis_block (store.block_get (transaction, genesis.hash (), &sideband));
ASSERT_NE (nullptr, genesis_block);
@ -1217,7 +1201,6 @@ TEST (block_store, upgrade_sideband_two_blocks)
nano::logging logging;
nano::mdb_store store (error, logging, path);
ASSERT_FALSE (error);
store.stop ();
nano::stat stat;
nano::ledger ledger (store, stat);
auto transaction (store.tx_begin (true));
@ -1228,21 +1211,13 @@ TEST (block_store, upgrade_sideband_two_blocks)
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, block).code);
write_legacy_sideband (store, transaction, *genesis.open, hash2, store.open_blocks);
write_legacy_sideband (store, transaction, block, 0, store.state_blocks_v0);
modify_account_info_to_v13 (store, transaction, nano::genesis_account);
}
nano::logging logging;
nano::mdb_store store (error, logging, path);
ASSERT_FALSE (error);
auto done (false);
auto iterations (0);
while (!done)
{
std::this_thread::sleep_for (std::chrono::milliseconds (10));
auto transaction (store.tx_begin (false));
done = store.full_sideband (transaction);
ASSERT_LT (iterations, 200);
++iterations;
}
auto transaction (store.tx_begin_read ());
ASSERT_TRUE (store.full_sideband (transaction));
nano::block_sideband sideband;
auto genesis_block (store.block_get (transaction, genesis.hash (), &sideband));
ASSERT_NE (nullptr, genesis_block);
@ -1265,7 +1240,6 @@ TEST (block_store, upgrade_sideband_two_accounts)
nano::logging logging;
nano::mdb_store store (error, logging, path);
ASSERT_FALSE (error);
store.stop ();
nano::stat stat;
nano::ledger ledger (store, stat);
auto transaction (store.tx_begin (true));
@ -1280,21 +1254,14 @@ TEST (block_store, upgrade_sideband_two_accounts)
write_legacy_sideband (store, transaction, *genesis.open, hash2, store.open_blocks);
write_legacy_sideband (store, transaction, block1, 0, store.state_blocks_v0);
write_legacy_sideband (store, transaction, block2, 0, store.state_blocks_v0);
modify_account_info_to_v13 (store, transaction, nano::genesis_account);
modify_account_info_to_v13 (store, transaction, block2.account ());
}
nano::logging logging;
nano::mdb_store store (error, logging, path);
ASSERT_FALSE (error);
auto done (false);
auto iterations (0);
while (!done)
{
std::this_thread::sleep_for (std::chrono::milliseconds (10));
auto transaction (store.tx_begin (false));
done = store.full_sideband (transaction);
ASSERT_LT (iterations, 200);
++iterations;
}
auto transaction (store.tx_begin_read ());
ASSERT_TRUE (store.full_sideband (transaction));
nano::block_sideband sideband;
auto genesis_block (store.block_get (transaction, genesis.hash (), &sideband));
ASSERT_NE (nullptr, genesis_block);
@ -1316,7 +1283,6 @@ TEST (block_store, insert_after_legacy)
nano::genesis genesis;
nano::mdb_store store (error, logging, nano::unique_path ());
ASSERT_FALSE (error);
store.stop ();
nano::stat stat;
nano::ledger ledger (store, stat);
auto transaction (store.tx_begin (true));
@ -1327,31 +1293,6 @@ TEST (block_store, insert_after_legacy)
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, block).code);
}
TEST (block_store, upgrade_sideband_rollback_old)
{
nano::logging logging;
bool error (false);
nano::genesis genesis;
nano::mdb_store store (error, logging, nano::unique_path ());
ASSERT_FALSE (error);
store.stop ();
nano::stat stat;
nano::ledger ledger (store, stat);
auto transaction (store.tx_begin (true));
store.version_put (transaction, 11);
store.initialize (transaction, genesis);
nano::send_block block1 (genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, block1).code);
nano::send_block block2 (block1.hash (), nano::test_genesis_key.pub, nano::genesis_amount - 2 * nano::Gxrb_ratio, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, block2).code);
write_legacy_sideband (store, transaction, *genesis.open, block1.hash (), store.open_blocks);
write_legacy_sideband (store, transaction, block1, block2.hash (), store.send_blocks);
write_legacy_sideband (store, transaction, block2, 0, store.send_blocks);
ASSERT_TRUE (store.block_exists (transaction, block2.hash ()));
ledger.rollback (transaction, block2.hash ());
ASSERT_FALSE (store.block_exists (transaction, block2.hash ()));
}
// Account for an open block should be retrievable
TEST (block_store, legacy_account_computed)
{
@ -1359,7 +1300,6 @@ TEST (block_store, legacy_account_computed)
bool init (false);
nano::mdb_store store (init, logging, nano::unique_path ());
ASSERT_TRUE (!init);
store.stop ();
nano::stat stats;
nano::ledger ledger (store, stats);
nano::genesis genesis;
@ -1380,7 +1320,6 @@ TEST (block_store, upgrade_sideband_epoch)
nano::logging logging;
nano::mdb_store store (error, logging, path);
ASSERT_FALSE (error);
store.stop ();
nano::stat stat;
nano::ledger ledger (store, stat, 42, nano::test_genesis_key.pub);
auto transaction (store.tx_begin (true));
@ -1392,23 +1331,15 @@ TEST (block_store, upgrade_sideband_epoch)
ASSERT_EQ (nano::epoch::epoch_1, store.block_version (transaction, hash2));
write_legacy_sideband (store, transaction, *genesis.open, hash2, store.open_blocks);
write_legacy_sideband (store, transaction, block1, 0, store.state_blocks_v1);
modify_account_info_to_v13 (store, transaction, nano::genesis_account);
}
nano::logging logging;
nano::mdb_store store (error, logging, path);
nano::stat stat;
nano::ledger ledger (store, stat, 42, nano::test_genesis_key.pub);
ASSERT_FALSE (error);
auto done (false);
auto iterations (0);
while (!done)
{
std::this_thread::sleep_for (std::chrono::milliseconds (10));
auto transaction (store.tx_begin (false));
done = store.full_sideband (transaction);
ASSERT_LT (iterations, 200);
++iterations;
}
auto transaction (store.tx_begin_write ());
ASSERT_TRUE (store.full_sideband (transaction));
ASSERT_EQ (nano::epoch::epoch_1, store.block_version (transaction, hash2));
nano::block_sideband sideband;
auto block1 (store.block_get (transaction, hash2, &sideband));
@ -1429,7 +1360,6 @@ TEST (block_store, sideband_height)
nano::keypair key3;
nano::mdb_store store (error, logging, nano::unique_path ());
ASSERT_FALSE (error);
store.stop ();
nano::stat stat;
nano::ledger ledger (store, stat);
ledger.epoch_signer = epoch_key.pub;
@ -1587,3 +1517,149 @@ TEST (block_store, online_weight)
ASSERT_EQ (0, store.online_weight_count (transaction));
ASSERT_EQ (store.online_weight_end (), store.online_weight_begin (transaction));
}
// Adding confirmation height to accounts
TEST (block_store, upgrade_v13_v14)
{
auto path (nano::unique_path ());
{
nano::logging logging;
nano::genesis genesis;
auto error (false);
nano::mdb_store store (error, logging, path);
auto transaction (store.tx_begin (true));
store.initialize (transaction, genesis);
nano::account_info account_info;
ASSERT_FALSE (store.account_get (transaction, nano::genesis_account, account_info));
ASSERT_EQ (account_info.confirmation_height, 0);
store.version_put (transaction, 13);
modify_account_info_to_v13 (store, transaction, nano::genesis_account);
// This should fail as sizes are no longer correct for account_info
nano::account_info account_info1;
ASSERT_TRUE (store.account_get (transaction, nano::genesis_account, account_info1));
}
// Now do the upgrade and confirm that confirmation height is 0 and version is updated as expected
nano::logging logging;
auto error (false);
nano::mdb_store store (error, logging, path);
ASSERT_FALSE (error);
auto transaction (store.tx_begin (true));
// This should now work and have confirmation height of 0
nano::account_info account_info;
ASSERT_FALSE (store.account_get (transaction, nano::genesis_account, account_info));
ASSERT_EQ (account_info.confirmation_height, 0);
ASSERT_LT (13, store.version_get (transaction));
}
// Test various confirmation height values as well as clearing them
TEST (block_store, confirmation_height)
{
auto path (nano::unique_path ());
nano::logging logging;
auto error (false);
nano::mdb_store store (error, logging, path);
auto transaction (store.tx_begin (true));
nano::account account1 (0);
nano::account_info info1 (0, 0, 0, 0, 0, 0, 500, nano::epoch::epoch_0);
store.account_put (transaction, account1, info1);
nano::account account2 (1);
nano::account_info info2 (0, 0, 0, 0, 0, 0, std::numeric_limits<uint64_t>::max (), nano::epoch::epoch_0);
store.account_put (transaction, account2, info2);
nano::account account3 (2);
nano::account_info info3 (0, 0, 0, 0, 0, 0, 10, nano::epoch::epoch_0);
store.account_put (transaction, account3, info3);
nano::account_info stored_account_info;
ASSERT_FALSE (store.account_get (transaction, account1, stored_account_info));
ASSERT_EQ (stored_account_info.confirmation_height, 500);
ASSERT_FALSE (store.account_get (transaction, account2, stored_account_info));
ASSERT_EQ (stored_account_info.confirmation_height, std::numeric_limits<uint64_t>::max ());
ASSERT_FALSE (store.account_get (transaction, account3, stored_account_info));
ASSERT_EQ (stored_account_info.confirmation_height, 10);
// Check cleaning of confirmation heights
store.confirmation_height_clear (transaction);
ASSERT_EQ (store.account_count (transaction), 3);
ASSERT_FALSE (store.account_get (transaction, account1, stored_account_info));
ASSERT_EQ (stored_account_info.confirmation_height, 0);
ASSERT_FALSE (store.account_get (transaction, account2, stored_account_info));
ASSERT_EQ (stored_account_info.confirmation_height, 0);
ASSERT_FALSE (store.account_get (transaction, account3, stored_account_info));
ASSERT_EQ (stored_account_info.confirmation_height, 0);
}
// Upgrade many accounts to add a confirmation height of 0
TEST (block_store, upgrade_confirmation_height_many)
{
auto error (false);
nano::genesis genesis;
auto total_num_accounts = 1000; // Includes the genesis account
auto path (nano::unique_path ());
{
nano::logging logging;
nano::mdb_store store (error, logging, path);
ASSERT_FALSE (error);
auto transaction (store.tx_begin (true));
store.version_put (transaction, 13);
store.initialize (transaction, genesis);
modify_account_info_to_v13 (store, transaction, nano::genesis_account);
// Add many accounts
for (auto i = 0; i < total_num_accounts - 1; ++i)
{
nano::account account (i);
nano::open_block open (1, 2, 3, nullptr);
nano::account_info_v13 account_info_v13 (open.hash (), open.hash (), open.hash (), 3, 4, 1, nano::epoch::epoch_1);
auto status (mdb_put (store.env.tx (transaction), store.accounts_v1, nano::mdb_val (account), nano::mdb_val (account_info_v13), 0));
ASSERT_EQ (status, 0);
}
ASSERT_EQ (store.account_count (transaction), total_num_accounts);
}
// Loop over them all and confirm all have a confirmation height of 0
nano::logging logging;
nano::mdb_store store (error, logging, path);
auto transaction (store.tx_begin (false));
ASSERT_EQ (store.account_count (transaction), total_num_accounts);
for (auto i (store.latest_begin (transaction)), n (store.latest_end ()); i != n; ++i)
{
nano::account_info current (i->second);
ASSERT_EQ (current.confirmation_height, 0);
}
}
namespace
{
// These functions take the latest account_info and create a legacy one so that upgrade tests can be emulated more easily.
void modify_account_info_to_v13 (nano::mdb_store & store, nano::transaction const & transaction_a, nano::account const & account)
{
nano::account_info info;
ASSERT_FALSE (store.account_get (transaction_a, account, info));
nano::account_info_v13 account_info_v13 (info.head, info.rep_block, info.open_block, info.balance, info.modified, info.block_count, info.epoch);
auto status (mdb_put (store.env.tx (transaction_a), store.get_account_db (info.epoch), nano::mdb_val (account), nano::mdb_val (account_info_v13), 0));
assert (status == 0);
}
void modify_genesis_account_info_to_v5 (nano::mdb_store & store, nano::transaction const & transaction_a)
{
nano::account_info info;
store.account_get (transaction_a, nano::test_genesis_key.pub, info);
nano::account_info_v5 info_old (info.head, info.rep_block, info.open_block, info.balance, info.modified);
auto status (mdb_put (store.env.tx (transaction_a), store.accounts_v0, nano::mdb_val (nano::test_genesis_key.pub), info_old.val (), 0));
assert (status == 0);
}
}

View file

@ -132,7 +132,7 @@ TEST (ledger, process_send)
auto latest5 (dynamic_cast<nano::open_block *> (latest4.get ()));
ASSERT_NE (nullptr, latest5);
ASSERT_EQ (open, *latest5);
ledger.rollback (transaction, hash2);
ASSERT_FALSE (ledger.rollback (transaction, hash2));
ASSERT_TRUE (store.frontier_get (transaction, hash2).is_zero ());
nano::account_info info5;
ASSERT_TRUE (ledger.store.account_get (transaction, key2.pub, info5));
@ -148,7 +148,7 @@ TEST (ledger, process_send)
nano::account_info info6;
ASSERT_FALSE (ledger.store.account_get (transaction, nano::test_genesis_key.pub, info6));
ASSERT_EQ (hash1, info6.head);
ledger.rollback (transaction, info6.head);
ASSERT_FALSE (ledger.rollback (transaction, info6.head));
ASSERT_EQ (nano::genesis_amount, ledger.weight (transaction, nano::test_genesis_key.pub));
ASSERT_EQ (nano::test_genesis_key.pub, store.frontier_get (transaction, info1.head));
ASSERT_TRUE (store.frontier_get (transaction, hash1).is_zero ());
@ -205,7 +205,7 @@ TEST (ledger, process_receive)
ASSERT_EQ (0, ledger.account_pending (transaction, key2.pub));
ASSERT_EQ (nano::genesis_amount - 25, ledger.account_balance (transaction, key2.pub));
ASSERT_EQ (nano::genesis_amount - 25, ledger.weight (transaction, key3.pub));
ledger.rollback (transaction, hash4);
ASSERT_FALSE (ledger.rollback (transaction, hash4));
ASSERT_TRUE (store.block_successor (transaction, hash2).is_zero ());
ASSERT_EQ (key2.pub, store.frontier_get (transaction, hash2));
ASSERT_TRUE (store.frontier_get (transaction, hash4).is_zero ());
@ -247,7 +247,7 @@ TEST (ledger, rollback_receiver)
ASSERT_EQ (50, ledger.weight (transaction, nano::test_genesis_key.pub));
ASSERT_EQ (0, ledger.weight (transaction, key2.pub));
ASSERT_EQ (nano::genesis_amount - 50, ledger.weight (transaction, key3.pub));
ledger.rollback (transaction, hash1);
ASSERT_FALSE (ledger.rollback (transaction, hash1));
ASSERT_EQ (nano::genesis_amount, ledger.account_balance (transaction, nano::test_genesis_key.pub));
ASSERT_EQ (0, ledger.account_balance (transaction, key2.pub));
ASSERT_EQ (nano::genesis_amount, ledger.weight (transaction, nano::test_genesis_key.pub));
@ -291,13 +291,13 @@ TEST (ledger, rollback_representation)
nano::account_info info1;
ASSERT_FALSE (store.account_get (transaction, key2.pub, info1));
ASSERT_EQ (open.hash (), info1.rep_block);
ledger.rollback (transaction, receive1.hash ());
ASSERT_FALSE (ledger.rollback (transaction, receive1.hash ()));
nano::account_info info2;
ASSERT_FALSE (store.account_get (transaction, key2.pub, info2));
ASSERT_EQ (open.hash (), info2.rep_block);
ASSERT_EQ (0, ledger.weight (transaction, key2.pub));
ASSERT_EQ (nano::genesis_amount - 50, ledger.weight (transaction, key4.pub));
ledger.rollback (transaction, open.hash ());
ASSERT_FALSE (ledger.rollback (transaction, open.hash ()));
ASSERT_EQ (1, ledger.weight (transaction, key3.pub));
ASSERT_EQ (0, ledger.weight (transaction, key4.pub));
ledger.rollback (transaction, send1.hash ());
@ -305,7 +305,7 @@ TEST (ledger, rollback_representation)
nano::account_info info3;
ASSERT_FALSE (store.account_get (transaction, nano::test_genesis_key.pub, info3));
ASSERT_EQ (change2.hash (), info3.rep_block);
ledger.rollback (transaction, change2.hash ());
ASSERT_FALSE (ledger.rollback (transaction, change2.hash ()));
nano::account_info info4;
ASSERT_FALSE (store.account_get (transaction, nano::test_genesis_key.pub, info4));
ASSERT_EQ (change1.hash (), info4.rep_block);
@ -328,7 +328,7 @@ TEST (ledger, receive_rollback)
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send).code);
nano::receive_block receive (send.hash (), send.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive).code);
ledger.rollback (transaction, receive.hash ());
ASSERT_FALSE (ledger.rollback (transaction, receive.hash ()));
}
TEST (ledger, process_duplicate)
@ -413,7 +413,7 @@ TEST (ledger, representative_change)
nano::account_info info2;
ASSERT_FALSE (store.account_get (transaction, nano::test_genesis_key.pub, info2));
ASSERT_EQ (block.hash (), info2.head);
ledger.rollback (transaction, info2.head);
ASSERT_FALSE (ledger.rollback (transaction, info2.head));
ASSERT_EQ (nano::test_genesis_key.pub, store.frontier_get (transaction, info1.head));
ASSERT_TRUE (store.frontier_get (transaction, block.hash ()).is_zero ());
nano::account_info info3;
@ -685,7 +685,7 @@ TEST (ledger, double_open)
ASSERT_EQ (nano::process_result::fork, ledger.process (transaction, open2).code);
}
TEST (ledegr, double_receive)
TEST (ledger, double_receive)
{
nano::logging logging;
bool init (false);
@ -1509,23 +1509,23 @@ TEST (ledger, send_open_receive_rollback)
ASSERT_EQ (100, ledger.weight (transaction, key2.pub));
ASSERT_EQ (0, ledger.weight (transaction, nano::test_genesis_key.pub));
ASSERT_EQ (nano::genesis_amount - 100, ledger.weight (transaction, key3.pub));
ledger.rollback (transaction, receive.hash ());
ASSERT_FALSE (ledger.rollback (transaction, receive.hash ()));
ASSERT_EQ (50, ledger.weight (transaction, key2.pub));
ASSERT_EQ (0, ledger.weight (transaction, nano::test_genesis_key.pub));
ASSERT_EQ (nano::genesis_amount - 100, ledger.weight (transaction, key3.pub));
ledger.rollback (transaction, open.hash ());
ASSERT_FALSE (ledger.rollback (transaction, open.hash ()));
ASSERT_EQ (0, ledger.weight (transaction, key2.pub));
ASSERT_EQ (0, ledger.weight (transaction, nano::test_genesis_key.pub));
ASSERT_EQ (nano::genesis_amount - 100, ledger.weight (transaction, key3.pub));
ledger.rollback (transaction, change1.hash ());
ASSERT_FALSE (ledger.rollback (transaction, change1.hash ()));
ASSERT_EQ (0, ledger.weight (transaction, key2.pub));
ASSERT_EQ (0, ledger.weight (transaction, key3.pub));
ASSERT_EQ (nano::genesis_amount - 100, ledger.weight (transaction, nano::test_genesis_key.pub));
ledger.rollback (transaction, send2.hash ());
ASSERT_FALSE (ledger.rollback (transaction, send2.hash ()));
ASSERT_EQ (0, ledger.weight (transaction, key2.pub));
ASSERT_EQ (0, ledger.weight (transaction, key3.pub));
ASSERT_EQ (nano::genesis_amount - 50, ledger.weight (transaction, nano::test_genesis_key.pub));
ledger.rollback (transaction, send1.hash ());
ASSERT_FALSE (ledger.rollback (transaction, send1.hash ()));
ASSERT_EQ (0, ledger.weight (transaction, key2.pub));
ASSERT_EQ (0, ledger.weight (transaction, key3.pub));
ASSERT_EQ (nano::genesis_amount - 0, ledger.weight (transaction, nano::test_genesis_key.pub));
@ -2101,7 +2101,7 @@ TEST (ledger, state_rollback_send)
ASSERT_FALSE (store.pending_get (transaction, nano::pending_key (nano::genesis_account, send1.hash ()), info));
ASSERT_EQ (nano::genesis_account, info.source);
ASSERT_EQ (nano::Gxrb_ratio, info.amount.number ());
ledger.rollback (transaction, send1.hash ());
ASSERT_FALSE (ledger.rollback (transaction, send1.hash ()));
ASSERT_FALSE (store.block_exists (transaction, send1.hash ()));
ASSERT_EQ (nano::genesis_amount, ledger.account_balance (transaction, nano::genesis_account));
ASSERT_EQ (nano::genesis_amount, ledger.weight (transaction, nano::genesis_account));
@ -2125,7 +2125,7 @@ TEST (ledger, state_rollback_receive)
nano::state_block receive1 (nano::genesis_account, send1.hash (), nano::genesis_account, nano::genesis_amount, send1.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive1).code);
ASSERT_FALSE (store.pending_exists (transaction, nano::pending_key (nano::genesis_account, receive1.hash ())));
ledger.rollback (transaction, receive1.hash ());
ASSERT_FALSE (ledger.rollback (transaction, receive1.hash ()));
nano::pending_info info;
ASSERT_FALSE (store.pending_get (transaction, nano::pending_key (nano::genesis_account, send1.hash ()), info));
ASSERT_EQ (nano::genesis_account, info.source);
@ -2152,7 +2152,7 @@ TEST (ledger, state_rollback_received_send)
nano::state_block receive1 (key.pub, 0, key.pub, nano::Gxrb_ratio, send1.hash (), key.prv, key.pub, 0);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive1).code);
ASSERT_FALSE (store.pending_exists (transaction, nano::pending_key (nano::genesis_account, receive1.hash ())));
ledger.rollback (transaction, send1.hash ());
ASSERT_FALSE (ledger.rollback (transaction, send1.hash ()));
ASSERT_FALSE (store.pending_exists (transaction, nano::pending_key (nano::genesis_account, send1.hash ())));
ASSERT_FALSE (store.block_exists (transaction, send1.hash ()));
ASSERT_FALSE (store.block_exists (transaction, receive1.hash ()));
@ -2176,7 +2176,7 @@ TEST (ledger, state_rep_change_rollback)
nano::keypair rep;
nano::state_block change1 (nano::genesis_account, genesis.hash (), rep.pub, nano::genesis_amount, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, change1).code);
ledger.rollback (transaction, change1.hash ());
ASSERT_FALSE (ledger.rollback (transaction, change1.hash ()));
ASSERT_FALSE (store.block_exists (transaction, change1.hash ()));
ASSERT_EQ (nano::genesis_amount, ledger.account_balance (transaction, nano::genesis_account));
ASSERT_EQ (nano::genesis_amount, ledger.weight (transaction, nano::genesis_account));
@ -2199,7 +2199,7 @@ TEST (ledger, state_open_rollback)
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send1).code);
nano::state_block open1 (destination.pub, 0, nano::genesis_account, nano::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, open1).code);
ledger.rollback (transaction, open1.hash ());
ASSERT_FALSE (ledger.rollback (transaction, open1.hash ()));
ASSERT_FALSE (store.block_exists (transaction, open1.hash ()));
ASSERT_EQ (0, ledger.account_balance (transaction, destination.pub));
ASSERT_EQ (nano::genesis_amount - nano::Gxrb_ratio, ledger.weight (transaction, nano::genesis_account));
@ -2223,7 +2223,7 @@ TEST (ledger, state_send_change_rollback)
nano::keypair rep;
nano::state_block send1 (nano::genesis_account, genesis.hash (), rep.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::genesis_account, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send1).code);
ledger.rollback (transaction, send1.hash ());
ASSERT_FALSE (ledger.rollback (transaction, send1.hash ()));
ASSERT_FALSE (store.block_exists (transaction, send1.hash ()));
ASSERT_EQ (nano::genesis_amount, ledger.account_balance (transaction, nano::genesis_account));
ASSERT_EQ (nano::genesis_amount, ledger.weight (transaction, nano::genesis_account));
@ -2246,7 +2246,7 @@ TEST (ledger, state_receive_change_rollback)
nano::keypair rep;
nano::state_block receive1 (nano::genesis_account, send1.hash (), rep.pub, nano::genesis_amount, send1.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive1).code);
ledger.rollback (transaction, receive1.hash ());
ASSERT_FALSE (ledger.rollback (transaction, receive1.hash ()));
ASSERT_FALSE (store.block_exists (transaction, receive1.hash ()));
ASSERT_EQ (nano::genesis_amount - nano::Gxrb_ratio, ledger.account_balance (transaction, nano::genesis_account));
ASSERT_EQ (nano::genesis_amount - nano::Gxrb_ratio, ledger.weight (transaction, nano::genesis_account));
@ -2273,7 +2273,7 @@ TEST (ledger, epoch_blocks_general)
nano::account_info genesis_info;
ASSERT_FALSE (ledger.store.account_get (transaction, nano::genesis_account, genesis_info));
ASSERT_EQ (genesis_info.epoch, nano::epoch::epoch_1);
ledger.rollback (transaction, epoch1.hash ());
ASSERT_FALSE (ledger.rollback (transaction, epoch1.hash ()));
ASSERT_FALSE (ledger.store.account_get (transaction, nano::genesis_account, genesis_info));
ASSERT_EQ (genesis_info.epoch, nano::epoch::epoch_0);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch1).code);
@ -2328,7 +2328,7 @@ TEST (ledger, epoch_blocks_receive_upgrade)
nano::account_info destination_info;
ASSERT_FALSE (ledger.store.account_get (transaction, destination.pub, destination_info));
ASSERT_EQ (destination_info.epoch, nano::epoch::epoch_1);
ledger.rollback (transaction, receive2.hash ());
ASSERT_FALSE (ledger.rollback (transaction, receive2.hash ()));
ASSERT_FALSE (ledger.store.account_get (transaction, destination.pub, destination_info));
ASSERT_EQ (destination_info.epoch, nano::epoch::epoch_0);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive2).code);
@ -2587,3 +2587,29 @@ TEST (ledger, unchecked_receive)
ASSERT_EQ (unchecked_count, 0);
}
}
TEST (ledger, confirmation_height_not_updated)
{
bool error (false);
nano::logging logging;
nano::mdb_store store (error, logging, nano::unique_path ());
ASSERT_TRUE (!error);
nano::stat stats;
nano::ledger ledger (store, stats);
auto transaction (store.tx_begin (true));
nano::genesis genesis;
store.initialize (transaction, genesis);
nano::account_info account_info;
ASSERT_FALSE (store.account_get (transaction, nano::test_genesis_key.pub, account_info));
nano::keypair key;
nano::send_block send1 (account_info.head, key.pub, 50, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
ASSERT_EQ (0, account_info.confirmation_height);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send1).code);
ASSERT_FALSE (store.account_get (transaction, nano::test_genesis_key.pub, account_info));
ASSERT_EQ (0, account_info.confirmation_height);
nano::open_block open1 (send1.hash (), nano::genesis_account, key.pub, key.prv, key.pub, 0);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, open1).code);
nano::account_info account_info1;
ASSERT_FALSE (store.account_get (transaction, key.pub, account_info1));
ASSERT_EQ (0, account_info1.confirmation_height);
}

View file

@ -1423,3 +1423,310 @@ TEST (bootstrap, keepalive)
ASSERT_NO_ERROR (system.poll ());
}
}
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 block1 (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 (0)
nano::account_info account_info;
{
auto transaction = system.nodes[0]->store.tx_begin_read ();
ASSERT_FALSE (system.nodes[0]->store.account_get (transaction, nano::test_genesis_key.pub, account_info));
ASSERT_EQ (0, account_info.confirmation_height);
auto transaction1 = system.nodes[1]->store.tx_begin_read ();
ASSERT_FALSE (system.nodes[1]->store.account_get (transaction1, nano::test_genesis_key.pub, account_info));
ASSERT_EQ (0, account_info.confirmation_height);
}
system.nodes[0]->process_active (block1);
system.nodes[0]->block_processor.flush ();
system.nodes[1]->process_active (block1);
system.nodes[1]->block_processor.flush ();
system.deadline_set (10s);
while (system.nodes[0]->balance (key1.pub) != system.nodes[0]->config.receive_minimum.number ())
{
ASSERT_NO_ERROR (system.poll ());
}
// Check confirmation heights after
{
auto transaction = system.nodes[0]->store.tx_begin_write ();
ASSERT_FALSE (system.nodes[0]->store.account_get (transaction, nano::test_genesis_key.pub, account_info));
ASSERT_EQ (2, account_info.confirmation_height);
auto transaction1 = system.nodes[1]->store.tx_begin_read ();
ASSERT_FALSE (system.nodes[1]->store.account_get (transaction1, nano::test_genesis_key.pub, account_info));
ASSERT_EQ (2, account_info.confirmation_height);
// Rollback should fail as this transaction has been cemented
ASSERT_TRUE (system.nodes[0]->ledger.rollback (transaction, block1->hash ()));
}
}
TEST (confirmation_height, multiple)
{
auto amount (std::numeric_limits<nano::uint128_t>::max ());
nano::system system (24000, 2);
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, 300, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
nano::send_block send2 (send1.hash (), key2.pub, 1, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
nano::send_block send3 (send2.hash (), key3.pub, 1, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
// Open all accounts
nano::open_block open1 (send1.hash (), nano::genesis_account, key1.pub, key1.prv, key1.pub, 0);
nano::open_block open2 (send2.hash (), nano::genesis_account, key2.pub, key2.prv, key2.pub, 0);
nano::open_block open3 (send3.hash (), nano::genesis_account, key3.pub, key3.prv, key3.pub, 0);
// Send and recieve various blocks to these accounts
nano::send_block send4 (open1.hash (), key2.pub, 50, key1.prv, key1.pub, 0);
nano::send_block send5 (send4.hash (), key2.pub, 10, key1.prv, key1.pub, 0);
nano::receive_block receive1 (open2.hash (), send4.hash (), key2.prv, key2.pub, 0);
nano::send_block send6 (receive1.hash (), key3.pub, 10, key2.prv, key2.pub, 0);
nano::receive_block receive2 (send6.hash (), send5.hash (), key2.prv, key2.pub, 0);
for (auto & node : system.nodes)
{
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.
nano::account_info account_info;
ASSERT_FALSE (node->store.account_get (transaction, nano::test_genesis_key.pub, account_info));
ASSERT_EQ (0, account_info.confirmation_height);
ASSERT_FALSE (node->store.account_get (transaction, key1.pub, account_info));
ASSERT_EQ (0, account_info.confirmation_height);
ASSERT_FALSE (node->store.account_get (transaction, key2.pub, account_info));
ASSERT_EQ (0, account_info.confirmation_height);
ASSERT_FALSE (node->store.account_get (transaction, key3.pub, account_info));
ASSERT_EQ (0, account_info.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;
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_EQ (4, account_info.confirmation_height);
ASSERT_EQ (4, account_info.block_count);
ASSERT_FALSE (store.account_get (transaction, key1.pub, account_info));
ASSERT_EQ (2, account_info.confirmation_height);
ASSERT_EQ (3, account_info.block_count);
ASSERT_FALSE (store.account_get (transaction, key2.pub, account_info));
ASSERT_EQ (3, account_info.confirmation_height);
ASSERT_EQ (4, account_info.block_count);
ASSERT_FALSE (store.account_get (transaction, key3.pub, account_info));
ASSERT_EQ (2, account_info.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 ()));
}
}
}
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 ();
// 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 ());
auto unchecked_count (node1.store.unchecked_count (transaction));
ASSERT_EQ (unchecked_count, 2);
nano::account_info account_info;
ASSERT_FALSE (node1.store.account_get (transaction, nano::test_genesis_key.pub, account_info));
ASSERT_EQ (0, account_info.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 still be 0 and unchecked should now be 0
{
auto transaction (node1.store.tx_begin ());
auto unchecked_count (node1.store.unchecked_count (transaction));
ASSERT_EQ (unchecked_count, 0);
nano::account_info account_info;
ASSERT_FALSE (node1.store.account_get (transaction, nano::test_genesis_key.pub, account_info));
ASSERT_EQ (0, account_info.confirmation_height);
ASSERT_FALSE (node1.store.account_get (transaction, destination.pub, account_info));
ASSERT_EQ (0, account_info.confirmation_height);
}
}
TEST (confirmation_height, gap_live)
{
nano::system system (24000, 2);
nano::keypair destination;
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 (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));
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));
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));
auto open1 (std::make_shared<nano::open_block> (send1->hash (), destination.pub, destination.pub, destination.prv, destination.pub, 0));
auto receive1 (std::make_shared<nano::receive_block> (open1->hash (), send2->hash (), destination.prv, destination.pub, 0));
auto receive2 (std::make_shared<nano::receive_block> (receive1->hash (), send3->hash (), destination.prv, destination.pub, 0));
for (auto & node : system.nodes)
{
node->work_generate_blocking (*send1);
node->work_generate_blocking (*send2);
node->work_generate_blocking (*send3);
node->work_generate_blocking (*open1);
node->work_generate_blocking (*receive1);
node->work_generate_blocking (*receive2);
node->block_processor.add (send1);
node->block_processor.add (send2);
node->block_processor.add (send3);
node->block_processor.add (receive1);
node->block_processor.flush ();
// 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 ();
nano::account_info account_info;
ASSERT_FALSE (node->store.account_get (transaction, nano::test_genesis_key.pub, account_info));
ASSERT_EQ (0, account_info.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, open1->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 ());
auto unchecked_count (node->store.unchecked_count (transaction));
ASSERT_EQ (unchecked_count, 0);
nano::account_info account_info;
ASSERT_FALSE (node->store.account_get (transaction, nano::test_genesis_key.pub, account_info));
ASSERT_EQ (4, account_info.block_count);
ASSERT_EQ (2, account_info.confirmation_height);
ASSERT_FALSE (node->store.account_get (transaction, destination.pub, account_info));
ASSERT_EQ (1, account_info.confirmation_height);
ASSERT_EQ (3, account_info.block_count);
}
}
}

View file

@ -971,7 +971,7 @@ TEST (rpc, frontier)
{
nano::keypair key;
source[key.pub] = key.prv.data;
system.nodes[0]->store.account_put (transaction, key.pub, nano::account_info (key.prv.data, 0, 0, 0, 0, 0, nano::epoch::epoch_0));
system.nodes[0]->store.account_put (transaction, key.pub, nano::account_info (key.prv.data, 0, 0, 0, 0, 0, 0, nano::epoch::epoch_0));
}
}
nano::keypair key;
@ -1012,7 +1012,7 @@ TEST (rpc, frontier_limited)
{
nano::keypair key;
source[key.pub] = key.prv.data;
system.nodes[0]->store.account_put (transaction, key.pub, nano::account_info (key.prv.data, 0, 0, 0, 0, 0, nano::epoch::epoch_0));
system.nodes[0]->store.account_put (transaction, key.pub, nano::account_info (key.prv.data, 0, 0, 0, 0, 0, 0, nano::epoch::epoch_0));
}
}
nano::keypair key;
@ -1043,7 +1043,7 @@ TEST (rpc, frontier_startpoint)
{
nano::keypair key;
source[key.pub] = key.prv.data;
system.nodes[0]->store.account_put (transaction, key.pub, nano::account_info (key.prv.data, 0, 0, 0, 0, 0, nano::epoch::epoch_0));
system.nodes[0]->store.account_put (transaction, key.pub, nano::account_info (key.prv.data, 0, 0, 0, 0, 0, 0, nano::epoch::epoch_0));
}
}
nano::keypair key;
@ -3357,6 +3357,14 @@ TEST (rpc, account_info)
system.nodes[0]->process (send);
auto time (nano::seconds_since_epoch ());
{
auto transaction = system.nodes[0]->store.tx_begin_write ();
nano::account_info account_info;
ASSERT_FALSE (system.nodes[0]->store.account_get (transaction, nano::test_genesis_key.pub, account_info));
account_info.confirmation_height = 1;
system.nodes[0]->store.account_put (transaction, nano::test_genesis_key.pub, account_info);
}
nano::rpc rpc (system.io_ctx, *system.nodes[0], nano::rpc_config (true));
rpc.start ();
boost::property_tree::ptree request;
@ -3381,6 +3389,8 @@ TEST (rpc, account_info)
ASSERT_LT (std::abs ((long)time - stol (modified_timestamp)), 5);
std::string block_count (response.json.get<std::string> ("block_count"));
ASSERT_EQ ("2", block_count);
std::string confirmation_height (response.json.get<std::string> ("confirmation_height"));
ASSERT_EQ ("1", confirmation_height);
ASSERT_EQ (0, response.json.get<uint8_t> ("account_version"));
boost::optional<std::string> weight (response.json.get_optional<std::string> ("weight"));
ASSERT_FALSE (weight.is_initialized ());
@ -4774,3 +4784,86 @@ TEST (rpc, memory_stats)
ASSERT_EQ (response.json.get_child ("node").get_child ("vote_uniquer").get_child ("votes").get<std::string> ("count"), "1");
}
TEST (rpc, block_confirmed)
{
nano::system system (24000, 1);
auto node = system.nodes.front ();
nano::rpc rpc (system.io_ctx, *node, nano::rpc_config (true));
rpc.start ();
boost::property_tree::ptree request;
request.put ("action", "block_confirmed");
request.put ("hash", "bad_hash1337");
test_response response (request, rpc, system.io_ctx);
while (response.status == 0)
{
system.poll ();
}
ASSERT_EQ (200, response.status);
ASSERT_EQ ("Invalid block hash", response.json.get<std::string> ("error"));
request.put ("hash", "0");
test_response response1 (request, rpc, system.io_ctx);
while (response1.status == 0)
{
system.poll ();
}
ASSERT_EQ (200, response1.status);
ASSERT_EQ ("Block not found", response1.json.get<std::string> ("error"));
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
nano::keypair key;
system.wallet (0)->insert_adhoc (key.prv);
// Open an account directly in the ledger
{
auto transaction = node->store.tx_begin_write ();
nano::block_hash latest (node->latest (nano::test_genesis_key.pub));
nano::send_block send1 (latest, key.pub, 300, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, send1).code);
nano::open_block open1 (send1.hash (), nano::genesis_account, key.pub, key.prv, key.pub, 0);
ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, open1).code);
}
// This should not be confirmed
nano::block_hash latest (node->latest (nano::test_genesis_key.pub));
request.put ("hash", latest.to_string ());
test_response response2 (request, rpc, system.io_ctx);
while (response2.status == 0)
{
system.poll ();
}
ASSERT_EQ (200, response2.status);
ASSERT_FALSE (response2.json.get<bool> ("confirmed"));
// Create and process a new send block
auto send = std::make_shared<nano::send_block> (latest, key.pub, 10, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (latest));
node->process_active (send);
node->block_processor.flush ();
// Wait until it has been confirmed by the network
system.deadline_set (10s);
while (true)
{
auto transaction = node->store.tx_begin_read ();
if (node->ledger.block_confirmed (transaction, send->hash ()))
{
break;
}
ASSERT_NO_ERROR (system.poll ());
}
// Requesting confirmation for this should now succeed
request.put ("hash", send->hash ().to_string ());
test_response response3 (request, rpc, system.io_ctx);
while (response3.status == 0)
{
system.poll ();
}
ASSERT_EQ (200, response3.status);
ASSERT_TRUE (response3.json.get<bool> ("confirmed"));
}

View file

@ -14,7 +14,6 @@ TEST (versioning, account_info_v1)
auto error (false);
nano::mdb_store store (error, logging, file);
ASSERT_FALSE (error);
store.stop ();
auto transaction (store.tx_begin (true));
nano::block_sideband sideband (nano::block_type::open, 0, 0, 0, 0, 0);
store.block_put (transaction, open.hash (), open, sideband);
@ -22,18 +21,92 @@ TEST (versioning, account_info_v1)
ASSERT_EQ (0, status);
store.version_put (transaction, 1);
}
nano::logging logging;
auto error (false);
nano::mdb_store store (error, logging, file);
ASSERT_FALSE (error);
auto transaction (store.tx_begin ());
nano::account_info v_latest;
ASSERT_FALSE (store.account_get (transaction, account, v_latest));
ASSERT_EQ (open.hash (), v_latest.open_block);
ASSERT_EQ (v1.balance, v_latest.balance);
ASSERT_EQ (v1.head, v_latest.head);
ASSERT_EQ (v1.modified, v_latest.modified);
ASSERT_EQ (v1.rep_block, v_latest.rep_block);
ASSERT_EQ (1, v_latest.block_count);
ASSERT_EQ (0, v_latest.confirmation_height);
ASSERT_EQ (nano::epoch::epoch_0, v_latest.epoch);
}
TEST (versioning, account_info_v5)
{
auto file (nano::unique_path ());
nano::account account (1);
nano::open_block open (1, 2, 3, nullptr);
nano::account_info_v5 v5 (open.hash (), open.hash (), open.hash (), 3, 4);
{
nano::logging logging;
auto error (false);
nano::mdb_store store (error, logging, file);
ASSERT_FALSE (error);
auto transaction (store.tx_begin ());
nano::account_info v2;
ASSERT_FALSE (store.account_get (transaction, account, v2));
ASSERT_EQ (open.hash (), v2.open_block);
ASSERT_EQ (v1.balance, v2.balance);
ASSERT_EQ (v1.head, v2.head);
ASSERT_EQ (v1.modified, v2.modified);
ASSERT_EQ (v1.rep_block, v2.rep_block);
auto transaction (store.tx_begin (true));
nano::block_sideband sideband (nano::block_type::open, 0, 0, 0, 0, 0);
store.block_put (transaction, open.hash (), open, sideband);
auto status (mdb_put (store.env.tx (transaction), store.accounts_v0, nano::mdb_val (account), v5.val (), 0));
ASSERT_EQ (0, status);
store.version_put (transaction, 5);
}
nano::logging logging;
auto error (false);
nano::mdb_store store (error, logging, file);
ASSERT_FALSE (error);
auto transaction (store.tx_begin ());
nano::account_info v_latest;
ASSERT_FALSE (store.account_get (transaction, account, v_latest));
ASSERT_EQ (v5.open_block, v_latest.open_block);
ASSERT_EQ (v5.balance, v_latest.balance);
ASSERT_EQ (v5.head, v_latest.head);
ASSERT_EQ (v5.modified, v_latest.modified);
ASSERT_EQ (v5.rep_block, v_latest.rep_block);
ASSERT_EQ (1, v_latest.block_count);
ASSERT_EQ (0, v_latest.confirmation_height);
ASSERT_EQ (nano::epoch::epoch_0, v_latest.epoch);
}
TEST (versioning, account_info_v13)
{
auto file (nano::unique_path ());
nano::account account (1);
nano::open_block open (1, 2, 3, nullptr);
nano::account_info_v13 v13 (open.hash (), open.hash (), open.hash (), 3, 4, 10, nano::epoch::epoch_0);
{
nano::logging logging;
auto error (false);
nano::mdb_store store (error, logging, file);
ASSERT_FALSE (error);
auto transaction (store.tx_begin (true));
nano::block_sideband sideband (nano::block_type::open, 0, 0, 0, 0, 0);
store.block_put (transaction, open.hash (), open, sideband);
auto status (mdb_put (store.env.tx (transaction), store.accounts_v0, nano::mdb_val (account), nano::mdb_val (v13), 0));
ASSERT_EQ (0, status);
store.version_put (transaction, 13);
}
nano::logging logging;
auto error (false);
nano::mdb_store store (error, logging, file);
ASSERT_FALSE (error);
auto transaction (store.tx_begin ());
nano::account_info v_latest;
ASSERT_FALSE (store.account_get (transaction, account, v_latest));
ASSERT_EQ (v13.open_block, v_latest.open_block);
ASSERT_EQ (v13.balance, v_latest.balance);
ASSERT_EQ (v13.head, v_latest.head);
ASSERT_EQ (v13.modified, v_latest.modified);
ASSERT_EQ (v13.rep_block, v_latest.rep_block);
ASSERT_EQ (v13.block_count, v_latest.block_count);
ASSERT_EQ (0, v_latest.confirmation_height);
ASSERT_EQ (v13.epoch, v_latest.epoch);
}

View file

@ -3,6 +3,7 @@
#include <nano/core_test/testutil.hpp>
#include <nano/node/node.hpp>
#include <nano/node/testing.hpp>
#include <nano/secure/versioning.hpp>
#include <boost/polymorphic_cast.hpp>
@ -92,6 +93,12 @@ TEST (wallets, upgrade)
MDB_txn * tx_destination (*boost::polymorphic_downcast<nano::mdb_txn *> (transaction_destination.impl.get ()));
node1->wallets.move_table (id.pub.to_string (), tx_source, tx_destination);
node1->store.version_put (transaction_destination, 11);
nano::account_info info;
ASSERT_FALSE (mdb_store.account_get (transaction_destination, nano::genesis_account, info));
nano::account_info_v13 account_info_v13 (info.head, info.rep_block, info.open_block, info.balance, info.modified, info.block_count, info.epoch);
auto status (mdb_put (mdb_store.env.tx (transaction_destination), mdb_store.get_account_db (info.epoch), nano::mdb_val (nano::test_genesis_key.pub), nano::mdb_val (account_info_v13), 0));
assert (status == 0);
}
nano::node_init init1;
auto node1 (std::make_shared<nano::node> (init1, system.io_ctx, 24001, path, system.alarm, system.logging, system.work));

View file

@ -295,8 +295,14 @@ void nano::block_processor::process_batch (std::unique_lock<std::mutex> & lock_a
// Replace our block with the winner and roll back any dependent blocks
node.logger.always_log (boost::str (boost::format ("Rolling back %1% and replacing with %2%") % successor->hash ().to_string () % hash.to_string ()));
std::vector<nano::block_hash> rollback_list;
node.ledger.rollback (transaction, successor->hash (), rollback_list);
node.logger.always_log (boost::str (boost::format ("%1% blocks rolled back") % rollback_list.size ()));
if (node.ledger.rollback (transaction, successor->hash (), rollback_list))
{
node.logger.always_log (boost::str (boost::format ("Failed to roll back %1% because it or a successor was confirmed") % successor->hash ().to_string ()));
}
else
{
node.logger.always_log (boost::str (boost::format ("%1% blocks rolled back") % rollback_list.size ()));
}
lock_a.lock ();
// Prevent rolled back blocks second insertion
auto inserted (rolled_back.insert (nano::rolled_hash{ std::chrono::steady_clock::now (), successor->hash () }));

View file

@ -36,6 +36,7 @@ void nano::add_node_options (boost::program_options::options_description & descr
("online_weight_clear", "Clear online weight history records")
("peer_clear", "Clear online peers database dump")
("unchecked_clear", "Clear unchecked blocks")
("confirmation_height_clear", "Clear confirmation height")
("diagnostics", "Run internal diagnostics")
("key_create", "Generates a adhoc random keypair and prints it to stdout")
("key_expand", "Derive public key and account number from <key>")
@ -246,6 +247,12 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map
auto transaction (node.node->store.tx_begin_write ());
node.node->store.peer_clear (transaction);
}
if (vm.count ("confirmation_height_clear"))
{
auto transaction (node.node->store.tx_begin_write ());
node.node->store.confirmation_height_clear (transaction);
}
success = node.node->copy_with_compaction (snapshot_path);
}
if (success)
@ -272,7 +279,7 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map
inactive_node node (data_path);
auto transaction (node.node->store.tx_begin_write ());
node.node->store.unchecked_clear (transaction);
std::cerr << "Unchecked blocks deleted" << std::endl;
std::cout << "Unchecked blocks deleted" << std::endl;
}
else if (vm.count ("delete_node_id"))
{
@ -280,7 +287,7 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map
inactive_node node (data_path);
auto transaction (node.node->store.tx_begin_write ());
node.node->store.delete_node_id (transaction);
std::cerr << "Deleted Node ID" << std::endl;
std::cout << "Deleted Node ID" << std::endl;
}
else if (vm.count ("clear_send_ids"))
{
@ -288,7 +295,7 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map
inactive_node node (data_path);
auto transaction (node.node->wallets.tx_begin_write ());
node.node->wallets.clear_send_ids (transaction);
std::cerr << "Send IDs deleted" << std::endl;
std::cout << "Send IDs deleted" << std::endl;
}
else if (vm.count ("online_weight_clear"))
{
@ -296,7 +303,7 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map
inactive_node node (data_path);
auto transaction (node.node->store.tx_begin_write ());
node.node->store.online_weight_clear (transaction);
std::cerr << "Onine weight records are removed" << std::endl;
std::cout << "Onine weight records are removed" << std::endl;
}
else if (vm.count ("peer_clear"))
{
@ -304,7 +311,45 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map
inactive_node node (data_path);
auto transaction (node.node->store.tx_begin_write ());
node.node->store.peer_clear (transaction);
std::cerr << "Database peers are removed" << std::endl;
std::cout << "Database peers are removed" << std::endl;
}
else if (vm.count ("confirmation_height_clear"))
{
boost::filesystem::path data_path = vm.count ("data_path") ? boost::filesystem::path (vm["data_path"].as<std::string> ()) : nano::working_path ();
inactive_node node (data_path);
auto account_it = vm.find ("account");
if (account_it != vm.cend ())
{
auto account_str = account_it->second.as<std::string> ();
nano::account account;
if (!account.decode_account (account_str))
{
nano::account_info account_info;
auto transaction (node.node->store.tx_begin_read ());
if (!node.node->store.account_get (transaction, account, account_info))
{
auto transaction (node.node->store.tx_begin_write ());
node.node->store.confirmation_height_clear (transaction, account, account_info);
std::cout << "Confirmation height of account " << account_str << " is set to 0" << std::endl;
}
else
{
std::cerr << "Could not find account" << std::endl;
ec = nano::error_cli::generic;
}
}
else
{
std::cerr << "Invalid account id\n";
ec = nano::error_cli::invalid_arguments;
}
}
else
{
auto transaction (node.node->store.tx_begin_write ());
node.node->store.confirmation_height_clear (transaction);
std::cout << "Confirmation heights of all accounts are set to 0" << std::endl;
}
}
else if (vm.count ("diagnostics"))
{
@ -342,7 +387,8 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map
}
else
{
std::cout << "Error initializing OpenCL" << std::endl;
std::cerr << "Error initializing OpenCL" << std::endl;
ec = nano::error_cli::generic;
}
}
else if (vm.count ("key_create"))

View file

@ -577,7 +577,7 @@ bool nano::confirm_req::deserialize (nano::stream & stream_a, nano::block_unique
result = block == nullptr;
}
}
catch (const std::runtime_error & error)
catch (const std::runtime_error &)
{
result = true;
}

View file

@ -101,6 +101,11 @@ mdb_val (val_a.db_size (), const_cast<nano::account_info *> (&val_a))
{
}
nano::mdb_val::mdb_val (nano::account_info_v13 const & val_a) :
mdb_val (val_a.db_size (), const_cast<nano::account_info_v13 *> (&val_a))
{
}
nano::mdb_val::mdb_val (nano::pending_info const & val_a) :
mdb_val (sizeof (val_a.source) + sizeof (val_a.amount), const_cast<nano::pending_info *> (&val_a))
{
@ -171,6 +176,15 @@ nano::mdb_val::operator nano::account_info () const
return result;
}
nano::mdb_val::operator nano::account_info_v13 () const
{
nano::account_info_v13 result;
result.epoch = epoch;
assert (value.mv_size == result.db_size ());
std::copy (reinterpret_cast<uint8_t const *> (value.mv_data), reinterpret_cast<uint8_t const *> (value.mv_data) + result.db_size (), reinterpret_cast<uint8_t *> (&result));
return result;
}
nano::mdb_val::operator nano::block_info () const
{
nano::block_info result;
@ -748,7 +762,6 @@ nano::mdb_store::mdb_store (bool & error_a, nano::logging & logging_a, boost::fi
logging (logging_a),
env (error_a, path_a, lmdb_max_dbs)
{
auto slow_upgrade (false);
if (!error_a)
{
auto transaction (tx_begin_write ());
@ -775,34 +788,13 @@ env (error_a, path_a, lmdb_max_dbs)
}
if (!error_a)
{
do_upgrades (transaction, slow_upgrade);
do_upgrades (transaction, batch_size);
if (drop_unchecked)
{
unchecked_clear (transaction);
}
}
}
if (slow_upgrade)
{
upgrades = std::thread ([this, batch_size]() {
nano::thread_role::set (nano::thread_role::name::slow_db_upgrade);
do_slow_upgrades (batch_size);
});
}
}
nano::mdb_store::~mdb_store ()
{
stop ();
}
void nano::mdb_store::stop ()
{
stopped = true;
if (upgrades.joinable ())
{
upgrades.join ();
}
}
nano::transaction nano::mdb_store::tx_begin_write ()
@ -820,6 +812,10 @@ nano::transaction nano::mdb_store::tx_begin (bool write_a)
return env.tx_begin (write_a);
}
/**
* This is only used with testing. If using a different store version than the latest then you may need
* to modify some of the objects in the store to be appropriate for the version before an upgrade.
*/
void nano::mdb_store::initialize (nano::transaction const & transaction_a, nano::genesis const & genesis_a)
{
auto hash_l (genesis_a.hash ());
@ -827,7 +823,7 @@ void nano::mdb_store::initialize (nano::transaction const & transaction_a, nano:
assert (latest_v1_begin (transaction_a) == latest_v1_end ());
nano::block_sideband sideband (nano::block_type::open, nano::genesis_account, 0, nano::genesis_amount, 1, nano::seconds_since_epoch ());
block_put (transaction_a, hash_l, *genesis_a.open, sideband);
account_put (transaction_a, genesis_account, { hash_l, genesis_a.open->hash (), genesis_a.open->hash (), std::numeric_limits<nano::uint128_t>::max (), nano::seconds_since_epoch (), 1, nano::epoch::epoch_0 });
account_put (transaction_a, genesis_account, { hash_l, genesis_a.open->hash (), genesis_a.open->hash (), std::numeric_limits<nano::uint128_t>::max (), nano::seconds_since_epoch (), 1, 0, nano::epoch::epoch_0 });
representation_put (transaction_a, genesis_account, std::numeric_limits<nano::uint128_t>::max ());
frontier_put (transaction_a, hash_l, genesis_account);
}
@ -851,7 +847,7 @@ void nano::mdb_store::version_put (nano::transaction const & transaction_a, int
}
}
int nano::mdb_store::version_get (nano::transaction const & transaction_a)
int nano::mdb_store::version_get (nano::transaction const & transaction_a) const
{
nano::uint256_union version_key (1);
nano::mdb_val data;
@ -866,7 +862,7 @@ int nano::mdb_store::version_get (nano::transaction const & transaction_a)
return result;
}
nano::raw_key nano::mdb_store::get_node_id (nano::transaction const & transaction_a)
nano::raw_key nano::mdb_store::get_node_id (nano::transaction const & transaction_a) const
{
nano::uint256_union node_id_mdb_key (3);
nano::raw_key node_id;
@ -941,7 +937,7 @@ nano::store_iterator<nano::endpoint_key, nano::no_value> nano::mdb_store::peers_
return result;
}
void nano::mdb_store::do_upgrades (nano::transaction const & transaction_a, bool & slow_upgrade)
void nano::mdb_store::do_upgrades (nano::transaction const & transaction_a, size_t batch_size)
{
switch (version_get (transaction_a))
{
@ -966,13 +962,12 @@ void nano::mdb_store::do_upgrades (nano::transaction const & transaction_a, bool
case 10:
upgrade_v10_to_v11 (transaction_a);
case 11:
// Signal the start of sideband upgrade
upgrade_v11_to_v12 (transaction_a);
// [[fallthrough]];
case 12:
slow_upgrade = true;
break;
upgrade_v12_to_v13 (transaction_a, batch_size);
case 13:
upgrade_v13_to_v14 (transaction_a);
case 14:
break;
default:
assert (false);
@ -1089,7 +1084,7 @@ void nano::mdb_store::upgrade_v4_to_v5 (nano::transaction const & transaction_a)
void nano::mdb_store::upgrade_v5_to_v6 (nano::transaction const & transaction_a)
{
version_put (transaction_a, 6);
std::deque<std::pair<nano::account, nano::account_info>> headers;
std::deque<std::pair<nano::account, nano::account_info_v13>> headers;
for (auto i (nano::store_iterator<nano::account, nano::account_info_v5> (std::make_unique<nano::mdb_iterator<nano::account, nano::account_info_v5>> (transaction_a, accounts_v0))), n (nano::store_iterator<nano::account, nano::account_info_v5> (nullptr)); i != n; ++i)
{
nano::account account (i->first);
@ -1103,12 +1098,12 @@ void nano::mdb_store::upgrade_v5_to_v6 (nano::transaction const & transaction_a)
assert (block != nullptr);
hash = block->previous ();
}
nano::account_info info (info_old.head, info_old.rep_block, info_old.open_block, info_old.balance, info_old.modified, block_count, nano::epoch::epoch_0);
headers.push_back (std::make_pair (account, info));
headers.emplace_back (account, nano::account_info_v13{ info_old.head, info_old.rep_block, info_old.open_block, info_old.balance, info_old.modified, block_count, nano::epoch::epoch_0 });
}
for (auto i (headers.begin ()), n (headers.end ()); i != n; ++i)
{
account_put (transaction_a, i->first, i->second);
auto status (mdb_put (env.tx (transaction_a), accounts_v0, nano::mdb_val (i->first), nano::mdb_val (i->second), 0));
release_assert (status == 0);
}
}
@ -1164,39 +1159,6 @@ void nano::mdb_store::upgrade_v10_to_v11 (nano::transaction const & transaction_
mdb_drop (env.tx (transaction_a), unsynced, 1);
}
void nano::mdb_store::do_slow_upgrades (size_t const batch_size)
{
int version;
{
nano::transaction transaction (tx_begin_read ());
version = version_get (transaction);
}
switch (version)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
break;
case 12:
upgrade_v12_to_v13 (batch_size);
break;
case 13:
break;
default:
assert (false);
break;
}
}
void nano::mdb_store::upgrade_v11_to_v12 (nano::transaction const & transaction_a)
{
version_put (transaction_a, 12);
@ -1207,19 +1169,19 @@ void nano::mdb_store::upgrade_v11_to_v12 (nano::transaction const & transaction_
mdb_drop (env.tx (transaction_a), checksum, 1);
}
void nano::mdb_store::upgrade_v12_to_v13 (size_t const batch_size)
void nano::mdb_store::upgrade_v12_to_v13 (nano::transaction const & transaction_a, size_t const batch_size)
{
size_t cost (0);
nano::account account (0);
auto transaction (tx_begin_write ());
auto const & not_an_account (nano::not_an_account ());
while (!stopped && account != not_an_account)
while (account != not_an_account)
{
nano::account first (0);
nano::account_info second;
nano::account_info_v13 second;
{
auto current (latest_begin (transaction, account));
if (current != latest_end ())
nano::store_iterator<nano::account, nano::account_info_v13> current (std::make_unique<nano::mdb_merge_iterator<nano::account, nano::account_info_v13>> (transaction_a, accounts_v0, accounts_v1, nano::mdb_val (account)));
nano::store_iterator<nano::account, nano::account_info_v13> end (nullptr);
if (current != end)
{
first = current->first;
second = current->second;
@ -1230,12 +1192,12 @@ void nano::mdb_store::upgrade_v12_to_v13 (size_t const batch_size)
auto hash (second.open_block);
uint64_t height (1);
nano::block_sideband sideband;
while (!stopped && !hash.is_zero ())
while (!hash.is_zero ())
{
if (cost >= batch_size)
{
logging.logger.always_log (boost::str (boost::format ("Upgrading sideband information for account %1%... height %2%") % first.to_account ().substr (0, 24) % std::to_string (height)));
auto tx (boost::polymorphic_downcast<nano::mdb_txn *> (transaction.impl.get ()));
auto tx (boost::polymorphic_downcast<nano::mdb_txn *> (transaction_a.impl.get ()));
auto status0 (mdb_txn_commit (*tx));
release_assert (status0 == MDB_SUCCESS);
std::this_thread::yield ();
@ -1243,12 +1205,12 @@ void nano::mdb_store::upgrade_v12_to_v13 (size_t const batch_size)
release_assert (status1 == MDB_SUCCESS);
cost = 0;
}
auto block (block_get (transaction, hash, &sideband));
auto block (block_get (transaction_a, hash, &sideband));
assert (block != nullptr);
if (sideband.height == 0)
{
sideband.height = height;
block_put (transaction, hash, *block, sideband, block_version (transaction, hash));
block_put (transaction_a, hash, *block, sideband, block_version (transaction_a, hash));
cost += 16;
}
else
@ -1268,10 +1230,34 @@ void nano::mdb_store::upgrade_v12_to_v13 (size_t const batch_size)
if (account == not_an_account)
{
logging.logger.always_log (boost::str (boost::format ("Completed sideband upgrade")));
version_put (transaction, 13);
version_put (transaction_a, 13);
}
}
void nano::mdb_store::upgrade_v13_to_v14 (nano::transaction const & transaction_a)
{
// Upgrade all accounts to have a confirmation of 0
version_put (transaction_a, 14);
nano::store_iterator<nano::account, nano::account_info_v13> i (std::make_unique<nano::mdb_merge_iterator<nano::account, nano::account_info_v13>> (transaction_a, accounts_v0, accounts_v1));
nano::store_iterator<nano::account, nano::account_info_v13> n (nullptr);
constexpr uint64_t zeroed_confirmation_height (0);
std::vector<std::pair<nano::account, nano::account_info>> account_infos;
account_infos.reserve (account_count (transaction_a));
for (; i != n; ++i)
{
nano::account_info_v13 account_info_v13 (i->second);
account_infos.emplace_back (i->first, nano::account_info{ account_info_v13.head, account_info_v13.rep_block, account_info_v13.open_block, account_info_v13.balance, account_info_v13.modified, account_info_v13.block_count, zeroed_confirmation_height, account_info_v13.epoch });
}
for (auto const & account_info : account_infos)
{
account_put (transaction_a, account_info.first, account_info.second);
}
logging.logger.always_log (boost::str (boost::format ("Completed confirmation height upgrade")));
}
void nano::mdb_store::clear (MDB_dbi db_a)
{
auto transaction (tx_begin_write ());
@ -1305,7 +1291,7 @@ nano::uint128_t nano::mdb_store::block_balance (nano::transaction const & transa
return result;
}
nano::uint128_t nano::mdb_store::block_balance_computed (nano::transaction const & transaction_a, nano::block_hash const & hash_a)
nano::uint128_t nano::mdb_store::block_balance_computed (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const
{
assert (!full_sideband (transaction_a));
summation_visitor visitor (transaction_a, *this);
@ -1396,7 +1382,7 @@ void nano::mdb_store::block_put (nano::transaction const & transaction_a, nano::
assert (block_a.previous ().is_zero () || block_successor (transaction_a, block_a.previous ()) == hash_a);
}
boost::optional<MDB_val> nano::mdb_store::block_raw_get_by_type (nano::transaction const & transaction_a, nano::block_hash const & hash_a, nano::block_type & type_a)
boost::optional<MDB_val> nano::mdb_store::block_raw_get_by_type (nano::transaction const & transaction_a, nano::block_hash const & hash_a, nano::block_type & type_a) const
{
nano::mdb_val value;
auto status (MDB_NOTFOUND);
@ -1448,7 +1434,7 @@ boost::optional<MDB_val> nano::mdb_store::block_raw_get_by_type (nano::transacti
return result;
}
MDB_val nano::mdb_store::block_raw_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a, nano::block_type & type_a)
MDB_val nano::mdb_store::block_raw_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a, nano::block_type & type_a) const
{
nano::mdb_val result;
// Table lookups are ordered by match probability
@ -1532,17 +1518,17 @@ std::shared_ptr<nano::block> nano::mdb_store::block_random (nano::transaction co
return result;
}
bool nano::mdb_store::full_sideband (nano::transaction const & transaction_a)
bool nano::mdb_store::full_sideband (nano::transaction const & transaction_a) const
{
return version_get (transaction_a) > 12;
}
bool nano::mdb_store::entry_has_sideband (MDB_val entry_a, nano::block_type type_a)
bool nano::mdb_store::entry_has_sideband (MDB_val entry_a, nano::block_type type_a) const
{
return entry_a.mv_size == nano::block::size (type_a) + nano::block_sideband::size (type_a);
}
size_t nano::mdb_store::block_successor_offset (nano::transaction const & transaction_a, MDB_val entry_a, nano::block_type type_a)
size_t nano::mdb_store::block_successor_offset (nano::transaction const & transaction_a, MDB_val entry_a, nano::block_type type_a) const
{
size_t result;
if (full_sideband (transaction_a) || entry_has_sideband (entry_a, type_a))
@ -1558,7 +1544,7 @@ size_t nano::mdb_store::block_successor_offset (nano::transaction const & transa
return result;
}
nano::block_hash nano::mdb_store::block_successor (nano::transaction const & transaction_a, nano::block_hash const & hash_a)
nano::block_hash nano::mdb_store::block_successor (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const
{
nano::block_type type;
auto value (block_raw_get (transaction_a, hash_a, type));
@ -1588,7 +1574,16 @@ void nano::mdb_store::block_successor_clear (nano::transaction const & transacti
block_raw_put (transaction_a, block_database (type, version), hash_a, nano::mdb_val (data.size (), data.data ()));
}
std::shared_ptr<nano::block> nano::mdb_store::block_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a, nano::block_sideband * sideband_a)
// Converts a block hash to a block height
uint64_t nano::mdb_store::block_account_height (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const
{
nano::block_sideband sideband;
auto block = block_get (transaction_a, hash_a, &sideband);
assert (block != nullptr);
return sideband.height;
}
std::shared_ptr<nano::block> nano::mdb_store::block_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a, nano::block_sideband * sideband_a) const
{
nano::block_type type;
auto value (block_raw_get (transaction_a, hash_a, type));
@ -1760,7 +1755,7 @@ bool nano::mdb_store::source_exists (nano::transaction const & transaction_a, na
return block_exists (transaction_a, nano::block_type::state, source_a) || block_exists (transaction_a, nano::block_type::send, source_a);
}
nano::account nano::mdb_store::block_account (nano::transaction const & transaction_a, nano::block_hash const & hash_a)
nano::account nano::mdb_store::block_account (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const
{
nano::block_sideband sideband;
auto block (block_get (transaction_a, hash_a, &sideband));
@ -1774,7 +1769,7 @@ nano::account nano::mdb_store::block_account (nano::transaction const & transact
}
// Return account containing hash
nano::account nano::mdb_store::block_account_computed (nano::transaction const & transaction_a, nano::block_hash const & hash_a)
nano::account nano::mdb_store::block_account_computed (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const
{
assert (!full_sideband (transaction_a));
nano::account result (0);
@ -1861,7 +1856,7 @@ bool nano::mdb_store::account_get (nano::transaction const & transaction_a, nano
{
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.data ()), value.size ());
info_a.epoch = epoch;
info_a.deserialize (stream);
result = info_a.deserialize (stream);
}
return result;
}
@ -1872,7 +1867,7 @@ void nano::mdb_store::frontier_put (nano::transaction const & transaction_a, nan
release_assert (status == 0);
}
nano::account nano::mdb_store::frontier_get (nano::transaction const & transaction_a, nano::block_hash const & block_a)
nano::account nano::mdb_store::frontier_get (nano::transaction const & transaction_a, nano::block_hash const & block_a) const
{
nano::mdb_val value;
auto status (mdb_get (env.tx (transaction_a), frontiers, nano::mdb_val (block_a), value));
@ -1903,10 +1898,10 @@ size_t nano::mdb_store::account_count (nano::transaction const & transaction_a)
return result;
}
void nano::mdb_store::account_put (nano::transaction const & transaction_a, nano::account const & account_a, nano::account_info const & info_a)
MDB_dbi nano::mdb_store::get_account_db (nano::epoch epoch_a) const
{
MDB_dbi db;
switch (info_a.epoch)
switch (epoch_a)
{
case nano::epoch::invalid:
case nano::epoch::unspecified:
@ -1918,14 +1913,13 @@ void nano::mdb_store::account_put (nano::transaction const & transaction_a, nano
db = accounts_v1;
break;
}
auto status (mdb_put (env.tx (transaction_a), db, nano::mdb_val (account_a), nano::mdb_val (info_a), 0));
release_assert (status == 0);
return db;
}
void nano::mdb_store::pending_put (nano::transaction const & transaction_a, nano::pending_key const & key_a, nano::pending_info const & pending_a)
MDB_dbi nano::mdb_store::get_pending_db (nano::epoch epoch_a) const
{
MDB_dbi db;
switch (pending_a.epoch)
switch (epoch_a)
{
case nano::epoch::invalid:
case nano::epoch::unspecified:
@ -1937,7 +1931,36 @@ void nano::mdb_store::pending_put (nano::transaction const & transaction_a, nano
db = pending_v1;
break;
}
auto status (mdb_put (env.tx (transaction_a), db, nano::mdb_val (key_a), nano::mdb_val (pending_a), 0));
return db;
}
void nano::mdb_store::account_put (nano::transaction const & transaction_a, nano::account const & account_a, nano::account_info const & info_a)
{
auto status (mdb_put (env.tx (transaction_a), get_account_db (info_a.epoch), nano::mdb_val (account_a), nano::mdb_val (info_a), 0));
release_assert (status == 0);
}
void nano::mdb_store::confirmation_height_clear (nano::transaction const & transaction_a, nano::account const & account, nano::account_info const & account_info)
{
nano::account_info info_copy (account_info);
if (info_copy.confirmation_height > 0)
{
info_copy.confirmation_height = 0;
account_put (transaction_a, account, info_copy);
}
}
void nano::mdb_store::confirmation_height_clear (nano::transaction const & transaction_a)
{
for (auto i (latest_begin (transaction_a)), n (latest_end ()); i != n; ++i)
{
confirmation_height_clear (transaction_a, i->first, i->second);
}
}
void nano::mdb_store::pending_put (nano::transaction const & transaction_a, nano::pending_key const & key_a, nano::pending_info const & pending_a)
{
auto status (mdb_put (env.tx (transaction_a), get_pending_db (pending_a.epoch), nano::mdb_val (key_a), nano::mdb_val (pending_a), 0));
release_assert (status == 0);
}
@ -1986,7 +2009,7 @@ bool nano::mdb_store::pending_get (nano::transaction const & transaction_a, nano
{
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.data ()), value.size ());
pending_a.epoch = epoch;
pending_a.deserialize (stream);
result = pending_a.deserialize (stream);
}
return result;
}
@ -2045,7 +2068,7 @@ nano::store_iterator<nano::pending_key, nano::pending_info> nano::mdb_store::pen
return result;
}
bool nano::mdb_store::block_info_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a, nano::block_info & block_info_a)
bool nano::mdb_store::block_info_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a, nano::block_info & block_info_a) const
{
assert (!full_sideband (transaction_a));
nano::mdb_val value;
@ -2133,12 +2156,6 @@ std::vector<nano::unchecked_info> nano::mdb_store::unchecked_get (nano::transact
return result;
}
bool nano::mdb_store::unchecked_exists (nano::transaction const & transaction_a, nano::unchecked_key const & key_a)
{
auto iterator (unchecked_begin (transaction_a, key_a));
return iterator != unchecked_end () && nano::unchecked_key (iterator->first) == key_a;
}
void nano::mdb_store::unchecked_del (nano::transaction const & transaction_a, nano::unchecked_key const & key_a)
{
auto status (mdb_del (env.tx (transaction_a), unchecked, nano::mdb_val (key_a), nullptr));

View file

@ -14,6 +14,7 @@
namespace nano
{
class mdb_env;
class account_info_v13;
class mdb_txn : public transaction_impl
{
public:
@ -48,6 +49,7 @@ class mdb_val
public:
mdb_val (nano::epoch = nano::epoch::unspecified);
mdb_val (nano::account_info const &);
mdb_val (nano::account_info_v13 const &);
mdb_val (nano::block_info const &);
mdb_val (MDB_val const &, nano::epoch = nano::epoch::unspecified);
mdb_val (nano::pending_info const &);
@ -63,6 +65,7 @@ public:
void * data () const;
size_t size () const;
explicit operator nano::account_info () const;
explicit operator nano::account_info_v13 () const;
explicit operator nano::block_info () const;
explicit operator nano::pending_info () const;
explicit operator nano::pending_key () const;
@ -151,18 +154,15 @@ class mdb_store : public block_store
public:
mdb_store (bool &, nano::logging &, boost::filesystem::path const &, int lmdb_max_dbs = 128, bool drop_unchecked = false, size_t batch_size = 512);
~mdb_store ();
nano::transaction tx_begin_write () override;
nano::transaction tx_begin_read () override;
nano::transaction tx_begin (bool write = false) override;
void initialize (nano::transaction const &, nano::genesis const &) override;
void block_put (nano::transaction const &, nano::block_hash const &, nano::block const &, nano::block_sideband const &, nano::epoch version = nano::epoch::epoch_0) override;
size_t block_successor_offset (nano::transaction const &, MDB_val, nano::block_type);
nano::block_hash block_successor (nano::transaction const &, nano::block_hash const &) override;
nano::block_hash block_successor (nano::transaction const &, nano::block_hash const &) const override;
void block_successor_clear (nano::transaction const &, nano::block_hash const &) override;
std::shared_ptr<nano::block> block_get (nano::transaction const &, nano::block_hash const &, nano::block_sideband * = nullptr) override;
std::shared_ptr<nano::block> block_get (nano::transaction const &, nano::block_hash const &, nano::block_sideband * = nullptr) const override;
std::shared_ptr<nano::block> block_random (nano::transaction const &) override;
void block_del (nano::transaction const &, nano::block_hash const &) override;
bool block_exists (nano::transaction const &, nano::block_hash const &) override;
@ -170,10 +170,10 @@ public:
nano::block_counts block_count (nano::transaction const &) override;
bool root_exists (nano::transaction const &, nano::uint256_union const &) override;
bool source_exists (nano::transaction const &, nano::block_hash const &) override;
nano::account block_account (nano::transaction const &, nano::block_hash const &) override;
nano::account block_account (nano::transaction const &, nano::block_hash const &) const override;
void frontier_put (nano::transaction const &, nano::block_hash const &, nano::account const &) override;
nano::account frontier_get (nano::transaction const &, nano::block_hash const &) override;
nano::account frontier_get (nano::transaction const &, nano::block_hash const &) const override;
void frontier_del (nano::transaction const &, nano::block_hash const &) override;
void account_put (nano::transaction const &, nano::account const &, nano::account_info const &) override;
@ -181,6 +181,8 @@ public:
void account_del (nano::transaction const &, nano::account const &) override;
bool account_exists (nano::transaction const &, nano::account const &) override;
size_t account_count (nano::transaction const &) override;
void confirmation_height_clear (nano::transaction const &, nano::account const & account, nano::account_info const & account_info) override;
void confirmation_height_clear (nano::transaction const &) override;
nano::store_iterator<nano::account, nano::account_info> latest_v0_begin (nano::transaction const &, nano::account const &) override;
nano::store_iterator<nano::account, nano::account_info> latest_v0_begin (nano::transaction const &) override;
nano::store_iterator<nano::account, nano::account_info> latest_v0_end () override;
@ -205,7 +207,7 @@ public:
nano::store_iterator<nano::pending_key, nano::pending_info> pending_begin (nano::transaction const &) override;
nano::store_iterator<nano::pending_key, nano::pending_info> pending_end () override;
bool block_info_get (nano::transaction const &, nano::block_hash const &, nano::block_info &) override;
bool block_info_get (nano::transaction const &, nano::block_hash const &, nano::block_info &) const override;
nano::uint128_t block_balance (nano::transaction const &, nano::block_hash const &) override;
nano::epoch block_version (nano::transaction const &, nano::block_hash const &) override;
@ -219,7 +221,6 @@ public:
void unchecked_put (nano::transaction const &, nano::unchecked_key const &, nano::unchecked_info const &) override;
void unchecked_put (nano::transaction const &, nano::block_hash const &, std::shared_ptr<nano::block> const &) override;
std::vector<nano::unchecked_info> unchecked_get (nano::transaction const &, nano::block_hash const &) override;
bool unchecked_exists (nano::transaction const &, nano::unchecked_key const &) override;
void unchecked_del (nano::transaction const &, nano::unchecked_key const &) override;
nano::store_iterator<nano::unchecked_key, nano::unchecked_info> unchecked_begin (nano::transaction const &) override;
nano::store_iterator<nano::unchecked_key, nano::unchecked_info> unchecked_begin (nano::transaction const &, nano::unchecked_key const &) override;
@ -251,25 +252,10 @@ public:
std::unordered_map<nano::account, std::shared_ptr<nano::vote>> vote_cache_l2;
void version_put (nano::transaction const &, int) override;
int version_get (nano::transaction const &) override;
void do_upgrades (nano::transaction const &, bool &);
void upgrade_v1_to_v2 (nano::transaction const &);
void upgrade_v2_to_v3 (nano::transaction const &);
void upgrade_v3_to_v4 (nano::transaction const &);
void upgrade_v4_to_v5 (nano::transaction const &);
void upgrade_v5_to_v6 (nano::transaction const &);
void upgrade_v6_to_v7 (nano::transaction const &);
void upgrade_v7_to_v8 (nano::transaction const &);
void upgrade_v8_to_v9 (nano::transaction const &);
void upgrade_v9_to_v10 (nano::transaction const &);
void upgrade_v10_to_v11 (nano::transaction const &);
void upgrade_v11_to_v12 (nano::transaction const &);
void do_slow_upgrades (size_t const);
void upgrade_v12_to_v13 (size_t const);
bool full_sideband (nano::transaction const &);
int version_get (nano::transaction const &) const override;
// Requires a write transaction
nano::raw_key get_node_id (nano::transaction const &) override;
nano::raw_key get_node_id (nano::transaction const &) const override;
/** Deletes the node ID from the store */
void delete_node_id (nano::transaction const &) override;
@ -283,7 +269,11 @@ public:
nano::store_iterator<nano::endpoint_key, nano::no_value> peers_begin (nano::transaction const & transaction_a) override;
nano::store_iterator<nano::endpoint_key, nano::no_value> peers_end () override;
void stop ();
uint64_t block_account_height (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const override;
bool full_sideband (nano::transaction const &) const;
MDB_dbi get_account_db (nano::epoch epoch_a) const;
size_t block_successor_offset (nano::transaction const &, MDB_val, nano::block_type) const;
nano::logging & logging;
@ -398,18 +388,31 @@ public:
MDB_dbi peers{ 0 };
private:
bool entry_has_sideband (MDB_val, nano::block_type);
nano::account block_account_computed (nano::transaction const &, nano::block_hash const &);
nano::uint128_t block_balance_computed (nano::transaction const &, nano::block_hash const &);
bool entry_has_sideband (MDB_val, nano::block_type) const;
nano::account block_account_computed (nano::transaction const &, nano::block_hash const &) const;
nano::uint128_t block_balance_computed (nano::transaction const &, nano::block_hash const &) const;
MDB_dbi block_database (nano::block_type, nano::epoch);
template <typename T>
std::shared_ptr<nano::block> block_random (nano::transaction const &, MDB_dbi);
MDB_val block_raw_get (nano::transaction const &, nano::block_hash const &, nano::block_type &);
boost::optional<MDB_val> block_raw_get_by_type (nano::transaction const &, nano::block_hash const &, nano::block_type &);
MDB_val block_raw_get (nano::transaction const &, nano::block_hash const &, nano::block_type &) const;
boost::optional<MDB_val> block_raw_get_by_type (nano::transaction const &, nano::block_hash const &, nano::block_type &) const;
void block_raw_put (nano::transaction const &, MDB_dbi, nano::block_hash const &, MDB_val);
void clear (MDB_dbi);
std::atomic<bool> stopped{ false };
std::thread upgrades;
void do_upgrades (nano::transaction const &, size_t);
void upgrade_v1_to_v2 (nano::transaction const &);
void upgrade_v2_to_v3 (nano::transaction const &);
void upgrade_v3_to_v4 (nano::transaction const &);
void upgrade_v4_to_v5 (nano::transaction const &);
void upgrade_v5_to_v6 (nano::transaction const &);
void upgrade_v6_to_v7 (nano::transaction const &);
void upgrade_v7_to_v8 (nano::transaction const &);
void upgrade_v8_to_v9 (nano::transaction const &);
void upgrade_v9_to_v10 (nano::transaction const &);
void upgrade_v10_to_v11 (nano::transaction const &);
void upgrade_v11_to_v12 (nano::transaction const &);
void upgrade_v12_to_v13 (nano::transaction const &, size_t);
void upgrade_v13_to_v14 (nano::transaction const &);
MDB_dbi get_pending_db (nano::epoch epoch_a) const;
};
class wallet_value
{

View file

@ -2669,6 +2669,11 @@ void nano::node::process_confirmed (std::shared_ptr<nano::block> block_a, uint8_
auto hash (block_a->hash ());
if (ledger.block_exists (block_a->type (), hash))
{
{
auto transaction (store.tx_begin_write ());
add_confirmation_heights (transaction, hash);
}
auto transaction (store.tx_begin_read ());
confirmed_visitor visitor (transaction, *this, block_a, hash);
block_a->visit (visitor);
@ -3737,6 +3742,86 @@ std::unique_ptr<seq_con_info_component> collect_seq_con_info (active_transaction
return composite;
}
}
/**
* For all the blocks below this height which have been implicitly confirmed check if they
* are open/receive blocks, and if so follow the source blocks and iteratively repeat to genesis.
*/
void nano::node::add_confirmation_heights (nano::transaction const & transaction, nano::block_hash const & hash)
{
std::stack<nano::block_hash, std::vector<nano::block_hash>> open_receive_blocks;
auto current = hash;
nano::genesis genesis;
do
{
if (!open_receive_blocks.empty ())
{
current = open_receive_blocks.top ();
open_receive_blocks.pop ();
auto block (store.block_get (transaction, current));
if (block != nullptr)
{
nano::block_hash source_hash = block->source ();
auto source_block (store.block_get (transaction, source_hash));
if (source_block != nullptr)
{
current = source_block->hash ();
}
}
}
auto hash (current);
auto block_height (store.block_account_height (transaction, hash));
assert (block_height >= 0);
nano::account_info account_info;
nano::account account (ledger.account (transaction, hash));
release_assert (!store.account_get (transaction, account, account_info));
auto confirmation_height = account_info.confirmation_height;
if (block_height > confirmation_height)
{
account_info.confirmation_height = block_height;
store.account_put (transaction, account, account_info);
// Get the difference and check if any of these are recieve blocks
auto num_confirmed_blocks = block_height - confirmation_height;
// Start from the most recent one and work our way through
for (uint64_t i = 0; i < num_confirmed_blocks && !current.is_zero (); ++i)
{
auto block (store.block_get (transaction, current));
if (block != nullptr)
{
// First check legacy receive/open
if (block->type () == nano::block_type::receive || (block->type () == nano::block_type::open && current != genesis.hash ()))
{
open_receive_blocks.push (block->source ());
}
else
{
// Then check state blocks
auto state = std::dynamic_pointer_cast<nano::state_block> (block);
if (state != nullptr)
{
nano::block_hash previous (state->hashables.previous);
if (!previous.is_zero ())
{
if (state->hashables.balance > ledger.balance (transaction, previous))
{
open_receive_blocks.push (state->hashables.link);
}
}
}
}
current = block->previous ();
}
}
}
} while (!open_receive_blocks.empty ());
}
int nano::node::store_version ()
{
auto transaction (store.tx_begin_read ());

View file

@ -529,6 +529,9 @@ public:
static std::chrono::seconds constexpr peer_interval = search_pending_interval;
static std::chrono::hours constexpr unchecked_cleanup_interval = std::chrono::hours (1);
static std::chrono::milliseconds constexpr process_confirmed_interval = nano::is_test_network ? std::chrono::milliseconds (50) : std::chrono::milliseconds (500);
private:
void add_confirmation_heights (nano::transaction const & transaction, nano::block_hash const & hash);
};
std::unique_ptr<seq_con_info_component> collect_seq_con_info (node & node, const std::string & name);

View file

@ -491,6 +491,7 @@ void nano::rpc_handler::account_info ()
response_l.put ("modified_timestamp", std::to_string (info.modified));
response_l.put ("block_count", std::to_string (info.block_count));
response_l.put ("account_version", info.epoch == nano::epoch::epoch_1 ? "1" : "0");
response_l.put ("confirmation_height", std::to_string (info.confirmation_height));
if (representative)
{
auto block (node.store.block_get (transaction, info.rep_block));
@ -1070,6 +1071,25 @@ void nano::rpc_handler::block_account ()
response_errors ();
}
void nano::rpc_handler::block_confirmed ()
{
auto hash (hash_impl ());
if (!ec)
{
auto transaction (node.store.tx_begin_read ());
if (node.store.block_exists (transaction, hash))
{
auto confirmed (node.ledger.block_confirmed (transaction, hash));
response_l.put ("confirmed", confirmed);
}
else
{
ec = nano::error_blocks::not_found;
}
}
response_errors ();
}
void nano::rpc_handler::block_count ()
{
auto transaction (node.store.tx_begin_read ());
@ -4655,6 +4675,7 @@ rpc_handler_no_arg_func_map create_rpc_handler_no_arg_func_map ()
no_arg_funcs.emplace ("blocks", &nano::rpc_handler::blocks);
no_arg_funcs.emplace ("blocks_info", &nano::rpc_handler::blocks_info);
no_arg_funcs.emplace ("block_account", &nano::rpc_handler::block_account);
no_arg_funcs.emplace ("block_confirmed", &nano::rpc_handler::block_confirmed);
no_arg_funcs.emplace ("block_count", &nano::rpc_handler::block_count);
no_arg_funcs.emplace ("block_count_type", &nano::rpc_handler::block_count_type);
no_arg_funcs.emplace ("block_create", &nano::rpc_handler::block_create);

View file

@ -113,6 +113,7 @@ public:
void blocks ();
void blocks_info ();
void block_account ();
void block_confirmed ();
void block_count ();
void block_count_type ();
void block_create ();

View file

@ -178,7 +178,8 @@ void nano::system::generate_rollback (nano::node & node_a, std::vector<nano::acc
{
accounts_a[index] = accounts_a[accounts_a.size () - 1];
accounts_a.pop_back ();
node_a.ledger.rollback (transaction, hash);
auto error = node_a.ledger.rollback (transaction, hash);
assert (!error);
}
}
}

View file

@ -88,7 +88,7 @@ bool nano::block_sideband::deserialize (nano::stream & stream_a)
return result;
}
nano::summation_visitor::summation_visitor (nano::transaction const & transaction_a, nano::block_store & store_a) :
nano::summation_visitor::summation_visitor (nano::transaction const & transaction_a, nano::block_store const & store_a) :
transaction (transaction_a),
store (store_a)
{

View file

@ -62,7 +62,7 @@ class summation_visitor : public nano::block_visitor
};
public:
summation_visitor (nano::transaction const &, nano::block_store &);
summation_visitor (nano::transaction const &, nano::block_store const &);
virtual ~summation_visitor () = default;
/** Computes the balance as of \p block_hash */
nano::uint128_t compute_balance (nano::block_hash const & block_hash);
@ -71,7 +71,7 @@ public:
protected:
nano::transaction const & transaction;
nano::block_store & store;
nano::block_store const & store;
/** The final result */
nano::uint128_t result{ 0 };
@ -209,9 +209,9 @@ public:
virtual ~block_store () = default;
virtual void initialize (nano::transaction const &, nano::genesis const &) = 0;
virtual void block_put (nano::transaction const &, nano::block_hash const &, nano::block const &, nano::block_sideband const &, nano::epoch version = nano::epoch::epoch_0) = 0;
virtual nano::block_hash block_successor (nano::transaction const &, nano::block_hash const &) = 0;
virtual nano::block_hash block_successor (nano::transaction const &, nano::block_hash const &) const = 0;
virtual void block_successor_clear (nano::transaction const &, nano::block_hash const &) = 0;
virtual std::shared_ptr<nano::block> block_get (nano::transaction const &, nano::block_hash const &, nano::block_sideband * = nullptr) = 0;
virtual std::shared_ptr<nano::block> block_get (nano::transaction const &, nano::block_hash const &, nano::block_sideband * = nullptr) const = 0;
virtual std::shared_ptr<nano::block> block_random (nano::transaction const &) = 0;
virtual void block_del (nano::transaction const &, nano::block_hash const &) = 0;
virtual bool block_exists (nano::transaction const &, nano::block_hash const &) = 0;
@ -219,10 +219,10 @@ public:
virtual nano::block_counts block_count (nano::transaction const &) = 0;
virtual bool root_exists (nano::transaction const &, nano::uint256_union const &) = 0;
virtual bool source_exists (nano::transaction const &, nano::block_hash const &) = 0;
virtual nano::account block_account (nano::transaction const &, nano::block_hash const &) = 0;
virtual nano::account block_account (nano::transaction const &, nano::block_hash const &) const = 0;
virtual void frontier_put (nano::transaction const &, nano::block_hash const &, nano::account const &) = 0;
virtual nano::account frontier_get (nano::transaction const &, nano::block_hash const &) = 0;
virtual nano::account frontier_get (nano::transaction const &, nano::block_hash const &) const = 0;
virtual void frontier_del (nano::transaction const &, nano::block_hash const &) = 0;
virtual void account_put (nano::transaction const &, nano::account const &, nano::account_info const &) = 0;
@ -230,6 +230,8 @@ public:
virtual void account_del (nano::transaction const &, nano::account const &) = 0;
virtual bool account_exists (nano::transaction const &, nano::account const &) = 0;
virtual size_t account_count (nano::transaction const &) = 0;
virtual void confirmation_height_clear (nano::transaction const &, nano::account const & account, nano::account_info const & account_info) = 0;
virtual void confirmation_height_clear (nano::transaction const &) = 0;
virtual nano::store_iterator<nano::account, nano::account_info> latest_v0_begin (nano::transaction const &, nano::account const &) = 0;
virtual nano::store_iterator<nano::account, nano::account_info> latest_v0_begin (nano::transaction const &) = 0;
virtual nano::store_iterator<nano::account, nano::account_info> latest_v0_end () = 0;
@ -254,7 +256,7 @@ public:
virtual nano::store_iterator<nano::pending_key, nano::pending_info> pending_begin (nano::transaction const &) = 0;
virtual nano::store_iterator<nano::pending_key, nano::pending_info> pending_end () = 0;
virtual bool block_info_get (nano::transaction const &, nano::block_hash const &, nano::block_info &) = 0;
virtual bool block_info_get (nano::transaction const &, nano::block_hash const &, nano::block_info &) const = 0;
virtual nano::uint128_t block_balance (nano::transaction const &, nano::block_hash const &) = 0;
virtual nano::epoch block_version (nano::transaction const &, nano::block_hash const &) = 0;
@ -268,7 +270,6 @@ public:
virtual void unchecked_put (nano::transaction const &, nano::unchecked_key const &, nano::unchecked_info const &) = 0;
virtual void unchecked_put (nano::transaction const &, nano::block_hash const &, std::shared_ptr<nano::block> const &) = 0;
virtual std::vector<nano::unchecked_info> unchecked_get (nano::transaction const &, nano::block_hash const &) = 0;
virtual bool unchecked_exists (nano::transaction const &, nano::unchecked_key const &) = 0;
virtual void unchecked_del (nano::transaction const &, nano::unchecked_key const &) = 0;
virtual nano::store_iterator<nano::unchecked_key, nano::unchecked_info> unchecked_begin (nano::transaction const &) = 0;
virtual nano::store_iterator<nano::unchecked_key, nano::unchecked_info> unchecked_begin (nano::transaction const &, nano::unchecked_key const &) = 0;
@ -296,7 +297,7 @@ public:
virtual void online_weight_clear (nano::transaction const &) = 0;
virtual void version_put (nano::transaction const &, int) = 0;
virtual int version_get (nano::transaction const &) = 0;
virtual int version_get (nano::transaction const &) const = 0;
virtual void peer_put (nano::transaction const & transaction_a, nano::endpoint_key const & endpoint_a) = 0;
virtual void peer_del (nano::transaction const & transaction_a, nano::endpoint_key const & endpoint_a) = 0;
@ -306,8 +307,10 @@ public:
virtual nano::store_iterator<nano::endpoint_key, nano::no_value> peers_begin (nano::transaction const & transaction_a) = 0;
virtual nano::store_iterator<nano::endpoint_key, nano::no_value> peers_end () = 0;
virtual uint64_t block_account_height (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const = 0;
// Requires a write transaction
virtual nano::raw_key get_node_id (nano::transaction const &) = 0;
virtual nano::raw_key get_node_id (nano::transaction const &) const = 0;
/** Deletes the node ID from the store */
virtual void delete_node_id (nano::transaction const &) = 0;

View file

@ -150,13 +150,14 @@ void nano::serialize_block (nano::stream & stream_a, nano::block const & block_a
block_a.serialize (stream_a);
}
nano::account_info::account_info (nano::block_hash const & head_a, nano::block_hash const & rep_block_a, nano::block_hash const & open_block_a, nano::amount const & balance_a, uint64_t modified_a, uint64_t block_count_a, nano::epoch epoch_a) :
nano::account_info::account_info (nano::block_hash const & head_a, nano::block_hash const & rep_block_a, nano::block_hash const & open_block_a, nano::amount const & balance_a, uint64_t modified_a, uint64_t block_count_a, uint64_t confirmation_height_a, nano::epoch epoch_a) :
head (head_a),
rep_block (rep_block_a),
open_block (open_block_a),
balance (balance_a),
modified (modified_a),
block_count (block_count_a),
confirmation_height (confirmation_height_a),
epoch (epoch_a)
{
}
@ -172,6 +173,7 @@ bool nano::account_info::deserialize (nano::stream & stream_a)
nano::read (stream_a, balance.bytes);
nano::read (stream_a, modified);
nano::read (stream_a, block_count);
nano::read (stream_a, confirmation_height);
}
catch (std::runtime_error const &)
{
@ -183,7 +185,7 @@ bool nano::account_info::deserialize (nano::stream & stream_a)
bool nano::account_info::operator== (nano::account_info const & other_a) const
{
return head == other_a.head && rep_block == other_a.rep_block && open_block == other_a.open_block && balance == other_a.balance && modified == other_a.modified && block_count == other_a.block_count && epoch == other_a.epoch;
return head == other_a.head && rep_block == other_a.rep_block && open_block == other_a.open_block && balance == other_a.balance && modified == other_a.modified && block_count == other_a.block_count && confirmation_height == other_a.confirmation_height && epoch == other_a.epoch;
}
bool nano::account_info::operator!= (nano::account_info const & other_a) const
@ -199,7 +201,8 @@ size_t nano::account_info::db_size () const
assert (reinterpret_cast<const uint8_t *> (&open_block) + sizeof (open_block) == reinterpret_cast<const uint8_t *> (&balance));
assert (reinterpret_cast<const uint8_t *> (&balance) + sizeof (balance) == reinterpret_cast<const uint8_t *> (&modified));
assert (reinterpret_cast<const uint8_t *> (&modified) + sizeof (modified) == reinterpret_cast<const uint8_t *> (&block_count));
return sizeof (head) + sizeof (rep_block) + sizeof (open_block) + sizeof (balance) + sizeof (modified) + sizeof (block_count);
assert (reinterpret_cast<const uint8_t *> (&block_count) + sizeof (block_count) == reinterpret_cast<const uint8_t *> (&confirmation_height));
return sizeof (head) + sizeof (rep_block) + sizeof (open_block) + sizeof (balance) + sizeof (modified) + sizeof (block_count) + sizeof (confirmation_height);
}
size_t nano::block_counts::sum () const

View file

@ -79,7 +79,7 @@ class account_info
{
public:
account_info () = default;
account_info (nano::block_hash const &, nano::block_hash const &, nano::block_hash const &, nano::amount const &, uint64_t, uint64_t, epoch);
account_info (nano::block_hash const &, nano::block_hash const &, nano::block_hash const &, nano::amount const &, uint64_t, uint64_t, uint64_t, epoch);
bool deserialize (nano::stream &);
bool operator== (nano::account_info const &) const;
bool operator!= (nano::account_info const &) const;
@ -91,6 +91,7 @@ public:
/** Seconds since posix epoch */
uint64_t modified{ 0 };
uint64_t block_count{ 0 };
uint64_t confirmation_height{ 0 };
nano::epoch epoch{ nano::epoch::epoch_0 };
};

View file

@ -23,21 +23,24 @@ public:
auto hash (block_a.hash ());
nano::pending_info pending;
nano::pending_key key (block_a.hashables.destination, hash);
while (ledger.store.pending_get (transaction, key, pending))
while (!error && ledger.store.pending_get (transaction, key, pending))
{
ledger.rollback (transaction, ledger.latest (transaction, block_a.hashables.destination), list);
error = ledger.rollback (transaction, ledger.latest (transaction, block_a.hashables.destination), list);
}
if (!error)
{
nano::account_info info;
auto error (ledger.store.account_get (transaction, pending.source, info));
assert (!error);
ledger.store.pending_del (transaction, key);
ledger.store.representation_add (transaction, ledger.representative (transaction, hash), pending.amount.number ());
ledger.change_latest (transaction, pending.source, block_a.hashables.previous, info.rep_block, ledger.balance (transaction, block_a.hashables.previous), info.block_count - 1);
ledger.store.block_del (transaction, hash);
ledger.store.frontier_del (transaction, hash);
ledger.store.frontier_put (transaction, block_a.hashables.previous, pending.source);
ledger.store.block_successor_clear (transaction, block_a.hashables.previous);
ledger.stats.inc (nano::stat::type::rollback, nano::stat::detail::send);
}
nano::account_info info;
auto error (ledger.store.account_get (transaction, pending.source, info));
assert (!error);
ledger.store.pending_del (transaction, key);
ledger.store.representation_add (transaction, ledger.representative (transaction, hash), pending.amount.number ());
ledger.change_latest (transaction, pending.source, block_a.hashables.previous, info.rep_block, ledger.balance (transaction, block_a.hashables.previous), info.block_count - 1);
ledger.store.block_del (transaction, hash);
ledger.store.frontier_del (transaction, hash);
ledger.store.frontier_put (transaction, block_a.hashables.previous, pending.source);
ledger.store.block_successor_clear (transaction, block_a.hashables.previous);
ledger.stats.inc (nano::stat::type::rollback, nano::stat::detail::send);
}
void receive_block (nano::receive_block const & block_a) override
{
@ -113,9 +116,9 @@ public:
if (is_send)
{
nano::pending_key key (block_a.hashables.link, hash);
while (!ledger.store.pending_exists (transaction, key))
while (!error && !ledger.store.pending_exists (transaction, key))
{
ledger.rollback (transaction, ledger.latest (transaction, block_a.hashables.link), list);
error = ledger.rollback (transaction, ledger.latest (transaction, block_a.hashables.link), list);
}
ledger.store.pending_del (transaction, key);
ledger.stats.inc (nano::stat::type::rollback, nano::stat::detail::send);
@ -150,6 +153,7 @@ public:
nano::transaction const & transaction;
nano::ledger & ledger;
std::vector<nano::block_hash> & list;
bool error{ false };
};
class ledger_processor : public nano::block_visitor
@ -666,7 +670,7 @@ epoch_signer (epoch_signer_a)
}
// Balance for account containing hash
nano::uint128_t nano::ledger::balance (nano::transaction const & transaction_a, nano::block_hash const & hash_a)
nano::uint128_t nano::ledger::balance (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const
{
return hash_a.is_zero () ? 0 : store.block_balance (transaction_a, hash_a);
}
@ -753,7 +757,7 @@ std::string nano::ledger::block_text (nano::block_hash const & hash_a)
return result;
}
bool nano::ledger::is_send (nano::transaction const & transaction_a, nano::state_block const & block_a)
bool nano::ledger::is_send (nano::transaction const & transaction_a, nano::state_block const & block_a) const
{
bool result (false);
nano::block_hash previous (block_a.hashables.previous);
@ -825,31 +829,42 @@ nano::uint128_t nano::ledger::weight (nano::transaction const & transaction_a, n
return store.representation_get (transaction_a, account_a);
}
// Rollback blocks until `block_a' doesn't exist
void nano::ledger::rollback (nano::transaction const & transaction_a, nano::block_hash const & block_a, std::vector<nano::block_hash> & list_a)
// Rollback blocks until `block_a' doesn't exist or it tries to penetrate the confirmation height
bool nano::ledger::rollback (nano::transaction const & transaction_a, nano::block_hash const & block_a, std::vector<nano::block_hash> & list_a)
{
assert (store.block_exists (transaction_a, block_a));
auto account_l (account (transaction_a, block_a));
auto block_account_height (store.block_account_height (transaction_a, block_a));
rollback_visitor rollback (transaction_a, *this, list_a);
nano::account_info info;
while (store.block_exists (transaction_a, block_a))
nano::account_info account_info;
auto error (false);
while (!error && store.block_exists (transaction_a, block_a))
{
auto latest_error (store.account_get (transaction_a, account_l, info));
auto latest_error (store.account_get (transaction_a, account_l, account_info));
assert (!latest_error);
auto block (store.block_get (transaction_a, info.head));
list_a.push_back (info.head);
block->visit (rollback);
if (block_account_height > account_info.confirmation_height)
{
auto block (store.block_get (transaction_a, account_info.head));
list_a.push_back (account_info.head);
block->visit (rollback);
error = rollback.error;
}
else
{
error = true;
}
}
return error;
}
void nano::ledger::rollback (nano::transaction const & transaction_a, nano::block_hash const & block_a)
bool nano::ledger::rollback (nano::transaction const & transaction_a, nano::block_hash const & block_a)
{
std::vector<nano::block_hash> rollback_list;
rollback (transaction_a, block_a, rollback_list);
return rollback (transaction_a, block_a, rollback_list);
}
// Return account containing hash
nano::account nano::ledger::account (nano::transaction const & transaction_a, nano::block_hash const & hash_a)
nano::account nano::ledger::account (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const
{
return store.block_account (transaction_a, hash_a);
}
@ -1031,6 +1046,20 @@ std::shared_ptr<nano::block> nano::ledger::forked_block (nano::transaction const
return result;
}
bool nano::ledger::block_confirmed (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const
{
auto confirmed (false);
auto block_height (store.block_account_height (transaction_a, hash_a));
if (block_height) // 0 indicates that the block doesn't exist
{
auto account_l (account (transaction_a, hash_a));
nano::account_info account_info;
release_assert (!store.account_get (transaction_a, account_l, account_info));
confirmed = (account_info.confirmation_height >= block_height);
}
return confirmed;
}
namespace nano
{
std::unique_ptr<seq_con_info_component> collect_seq_con_info (ledger & ledger, const std::string & name)

View file

@ -18,14 +18,15 @@ class ledger
{
public:
ledger (nano::block_store &, nano::stat &, nano::uint256_union const & = 1, nano::account const & = 0);
nano::account account (nano::transaction const &, nano::block_hash const &);
nano::account account (nano::transaction const &, nano::block_hash const &) const;
nano::uint128_t amount (nano::transaction const &, nano::block_hash const &);
nano::uint128_t balance (nano::transaction const &, nano::block_hash const &);
nano::uint128_t balance (nano::transaction const &, nano::block_hash const &) const;
nano::uint128_t account_balance (nano::transaction const &, nano::account const &);
nano::uint128_t account_pending (nano::transaction const &, nano::account const &);
nano::uint128_t weight (nano::transaction const &, nano::account const &);
std::shared_ptr<nano::block> successor (nano::transaction const &, nano::uint512_union const &);
std::shared_ptr<nano::block> forked_block (nano::transaction const &, nano::block const &);
bool block_confirmed (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const;
nano::block_hash latest (nano::transaction const &, nano::account const &);
nano::block_hash latest_root (nano::transaction const &, nano::account const &);
nano::block_hash representative (nano::transaction const &, nano::block_hash const &);
@ -34,12 +35,12 @@ public:
bool block_exists (nano::block_type, nano::block_hash const &);
std::string block_text (char const *);
std::string block_text (nano::block_hash const &);
bool is_send (nano::transaction const &, nano::state_block const &);
bool is_send (nano::transaction const &, nano::state_block const &) const;
nano::block_hash block_destination (nano::transaction const &, nano::block const &);
nano::block_hash block_source (nano::transaction const &, nano::block const &);
nano::process_return process (nano::transaction const &, nano::block const &, nano::signature_verification = nano::signature_verification::unknown);
void rollback (nano::transaction const &, nano::block_hash const &, std::vector<nano::block_hash> &);
void rollback (nano::transaction const &, nano::block_hash const &);
bool rollback (nano::transaction const &, nano::block_hash const &, std::vector<nano::block_hash> &);
bool rollback (nano::transaction const &, nano::block_hash const &);
void change_latest (nano::transaction const &, nano::account const &, nano::block_hash const &, nano::account const &, nano::uint128_union const &, uint64_t, bool = false, nano::epoch = nano::epoch::epoch_0);
void dump_account_chain (nano::account const &);
bool could_fit (nano::transaction const &, nano::block const &);

View file

@ -59,3 +59,25 @@ nano::mdb_val nano::account_info_v5::val () const
{
return nano::mdb_val (sizeof (*this), const_cast<nano::account_info_v5 *> (this));
}
nano::account_info_v13::account_info_v13 (nano::block_hash const & head_a, nano::block_hash const & rep_block_a, nano::block_hash const & open_block_a, nano::amount const & balance_a, uint64_t modified_a, uint64_t block_count_a, nano::epoch epoch_a) :
head (head_a),
rep_block (rep_block_a),
open_block (open_block_a),
balance (balance_a),
modified (modified_a),
block_count (block_count_a),
epoch (epoch_a)
{
}
size_t nano::account_info_v13::db_size () const
{
assert (reinterpret_cast<const uint8_t *> (this) == reinterpret_cast<const uint8_t *> (&head));
assert (reinterpret_cast<const uint8_t *> (&head) + sizeof (head) == reinterpret_cast<const uint8_t *> (&rep_block));
assert (reinterpret_cast<const uint8_t *> (&rep_block) + sizeof (rep_block) == reinterpret_cast<const uint8_t *> (&open_block));
assert (reinterpret_cast<const uint8_t *> (&open_block) + sizeof (open_block) == reinterpret_cast<const uint8_t *> (&balance));
assert (reinterpret_cast<const uint8_t *> (&balance) + sizeof (balance) == reinterpret_cast<const uint8_t *> (&modified));
assert (reinterpret_cast<const uint8_t *> (&modified) + sizeof (modified) == reinterpret_cast<const uint8_t *> (&block_count));
return sizeof (head) + sizeof (rep_block) + sizeof (open_block) + sizeof (balance) + sizeof (modified) + sizeof (block_count);
}

View file

@ -29,7 +29,6 @@ public:
nano::amount amount{ 0 };
nano::account destination{ 0 };
};
// Latest information about an account
class account_info_v5
{
public:
@ -43,4 +42,18 @@ public:
nano::amount balance{ 0 };
uint64_t modified{ 0 };
};
class account_info_v13
{
public:
account_info_v13 () = default;
account_info_v13 (nano::block_hash const &, nano::block_hash const &, nano::block_hash const &, nano::amount const &, uint64_t, uint64_t block_count, nano::epoch epoch_a);
size_t db_size () const;
nano::block_hash head{ 0 };
nano::block_hash rep_block{ 0 };
nano::block_hash open_block{ 0 };
nano::amount balance{ 0 };
uint64_t modified{ 0 };
uint64_t block_count{ 0 };
nano::epoch epoch{ nano::epoch::epoch_0 };
};
}