Moved the account LMDB table handlers to their store class

This commit is contained in:
Thiago Silva 2022-04-11 16:22:31 -03:00
commit d57bdf2722
4 changed files with 341 additions and 283 deletions

View file

@ -24,13 +24,16 @@
using namespace std::chrono_literals;
namespace
namespace nano
{
void modify_account_info_to_v14 (nano::lmdb::store & store, nano::transaction const & transaction_a, nano::account const & account_a, uint64_t confirmation_height, nano::block_hash const & rep_block);
void modify_confirmation_height_to_v15 (nano::lmdb::store & store, nano::transaction const & transaction, nano::account const & account, uint64_t confirmation_height);
void write_sideband_v14 (nano::lmdb::store & store_a, nano::transaction & transaction_a, nano::block const & block_a, MDB_dbi db_a);
void write_sideband_v15 (nano::lmdb::store & store_a, nano::transaction & transaction_a, nano::block const & block_a);
void write_block_w_sideband_v18 (nano::lmdb::store & store_a, MDB_dbi database, nano::write_transaction & transaction_a, nano::block const & block_a);
namespace lmdb
{
void modify_account_info_to_v14 (nano::lmdb::store & store, nano::transaction const & transaction_a, nano::account const & account_a, uint64_t confirmation_height, nano::block_hash const & rep_block);
void modify_confirmation_height_to_v15 (nano::lmdb::store & store, nano::transaction const & transaction, nano::account const & account, uint64_t confirmation_height);
void write_sideband_v14 (nano::lmdb::store & store_a, nano::transaction & transaction_a, nano::block const & block_a, MDB_dbi db_a);
void write_sideband_v15 (nano::lmdb::store & store_a, nano::transaction & transaction_a, nano::block const & block_a);
void write_block_w_sideband_v18 (nano::lmdb::store & store_a, MDB_dbi database, nano::write_transaction & transaction_a, nano::block const & block_a);
}
}
TEST (block_store, construction)
@ -688,55 +691,63 @@ TEST (block_store, latest_find)
ASSERT_EQ (second, find3);
}
TEST (mdb_block_store, supported_version_upgrades)
namespace nano
{
if (nano::rocksdb_config::using_rocksdb_in_tests ())
namespace lmdb
{
TEST (mdb_block_store, supported_version_upgrades)
{
// Don't test this in rocksdb mode
return;
}
// Check that upgrading from an unsupported version is not supported
auto path (nano::unique_path ());
nano::logger_mt logger;
{
nano::lmdb::store store (logger, path, nano::dev::constants);
nano::stat stats;
nano::ledger ledger (store, stats, nano::dev::constants);
auto transaction (store.tx_begin_write ());
store.initialize (transaction, ledger.cache, nano::dev::constants);
// Lower the database to the max version unsupported for upgrades
store.version.put (transaction, store.version_minimum - 1);
}
if (nano::rocksdb_config::using_rocksdb_in_tests ())
{
// Don't test this in rocksdb mode
return;
}
// Check that upgrading from an unsupported version is not supported
auto path (nano::unique_path ());
nano::logger_mt logger;
{
nano::lmdb::store store (logger, path, nano::dev::constants);
nano::stat stats;
nano::ledger ledger (store, stats, nano::dev::constants);
auto transaction (store.tx_begin_write ());
store.initialize (transaction, ledger.cache, nano::dev::constants);
// Lower the database to the max version unsupported for upgrades
store.version.put (transaction, store.version_minimum - 1);
}
// Upgrade should fail
{
nano::lmdb::store store (logger, path, nano::dev::constants);
ASSERT_TRUE (store.init_error ());
}
// Upgrade should fail
{
nano::lmdb::store store (logger, path, nano::dev::constants);
ASSERT_TRUE (store.init_error ());
}
auto path1 (nano::unique_path ());
// Now try with the minimum version
{
nano::lmdb::store store (logger, path1, nano::dev::constants);
nano::stat stats;
nano::ledger ledger (store, stats, nano::dev::constants);
auto transaction (store.tx_begin_write ());
store.initialize (transaction, ledger.cache, nano::dev::constants);
// Lower the database version to the minimum version supported for upgrade.
store.version.put (transaction, store.version_minimum);
store.confirmation_height.del (transaction, nano::dev::genesis->account ());
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "accounts_v1", MDB_CREATE, &store.accounts_v1_handle));
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "open", MDB_CREATE, &store.open_blocks_handle));
modify_account_info_to_v14 (store, transaction, nano::dev::genesis->account (), 1, nano::dev::genesis->hash ());
write_block_w_sideband_v18 (store, store.open_blocks_handle, transaction, *nano::dev::genesis);
}
auto path1 (nano::unique_path ());
// Now try with the minimum version
{
nano::lmdb::store store (logger, path1, nano::dev::constants);
nano::stat stats;
nano::ledger ledger (store, stats, nano::dev::constants);
auto transaction (store.tx_begin_write ());
store.initialize (transaction, ledger.cache, nano::dev::constants);
// Lower the database version to the minimum version supported for upgrade.
store.version.put (transaction, store.version_minimum);
store.confirmation_height.del (transaction, nano::dev::genesis->account ());
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "accounts_v1", MDB_CREATE,
&store.account_store.accounts_v1_handle));
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "open", MDB_CREATE, &store.open_blocks_handle));
modify_account_info_to_v14 (store, transaction, nano::dev::genesis->account (), 1,
nano::dev::genesis->hash ());
write_block_w_sideband_v18 (store, store.open_blocks_handle, transaction, *nano::dev::genesis);
}
// Upgrade should work
{
nano::lmdb::store store (logger, path1, nano::dev::constants);
ASSERT_FALSE (store.init_error ());
// Upgrade should work
{
nano::lmdb::store store (logger, path1, nano::dev::constants);
ASSERT_FALSE (store.init_error ());
}
}
}
}
TEST (mdb_block_store, bad_path)
{
@ -1275,160 +1286,197 @@ TEST (block_store, pruned_blocks)
ASSERT_EQ (store->pruned.count (store->tx_begin_read ()), 0);
}
TEST (mdb_block_store, upgrade_v14_v15)
namespace nano
{
if (nano::rocksdb_config::using_rocksdb_in_tests ())
{
// Don't test this in rocksdb mode
return;
}
// Extract confirmation height to a separate database
auto path (nano::unique_path ());
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
nano::send_block send (nano::dev::genesis->hash (), nano::dev::genesis_key.pub, nano::dev::constants.genesis_amount - nano::Gxrb_ratio, nano::dev::genesis_key.prv, nano::dev::genesis_key.pub, *pool.generate (nano::dev::genesis->hash ()));
nano::state_block epoch (nano::dev::genesis_key.pub, send.hash (), nano::dev::genesis_key.pub, nano::dev::constants.genesis_amount - nano::Gxrb_ratio, nano::dev::network_params.ledger.epochs.link (nano::epoch::epoch_1), nano::dev::genesis_key.prv, nano::dev::genesis_key.pub, *pool.generate (send.hash ()));
nano::state_block state_send (nano::dev::genesis_key.pub, epoch.hash (), nano::dev::genesis_key.pub, nano::dev::constants.genesis_amount - nano::Gxrb_ratio * 2, nano::dev::genesis_key.pub, nano::dev::genesis_key.prv, nano::dev::genesis_key.pub, *pool.generate (epoch.hash ()));
namespace lmdb
{
TEST (mdb_block_store, upgrade_v14_v15)
{
if (nano::rocksdb_config::using_rocksdb_in_tests ())
{
// Don't test this in rocksdb mode
return;
}
// Extract confirmation height to a separate database
auto path (nano::unique_path ());
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
nano::send_block send (nano::dev::genesis->hash (), nano::dev::genesis_key.pub,
nano::dev::constants.genesis_amount - nano::Gxrb_ratio, nano::dev::genesis_key.prv, nano::dev::genesis_key.pub, *pool.generate (nano::dev::genesis->hash ()));
nano::state_block epoch (nano::dev::genesis_key.pub, send.hash (), nano::dev::genesis_key.pub,
nano::dev::constants.genesis_amount - nano::Gxrb_ratio, nano::dev::network_params.ledger.epochs.link (nano::epoch::epoch_1), nano::dev::genesis_key.prv, nano::dev::genesis_key.pub, *pool.generate (send.hash ()));
nano::state_block state_send (nano::dev::genesis_key.pub, epoch.hash (), nano::dev::genesis_key.pub,
nano::dev::constants.genesis_amount - nano::Gxrb_ratio * 2, nano::dev::genesis_key.pub, nano::dev::genesis_key.prv, nano::dev::genesis_key.pub, *pool.generate (epoch.hash ()));
{
nano::logger_mt logger;
nano::lmdb::store store (logger, path, nano::dev::constants);
nano::stat stats;
nano::ledger ledger (store, stats, nano::dev::constants);
auto transaction (store.tx_begin_write ());
store.initialize (transaction, ledger.cache, nano::dev::constants);
nano::account_info account_info;
ASSERT_FALSE (store.account.get (transaction, nano::dev::genesis->account (), account_info));
nano::confirmation_height_info confirmation_height_info;
ASSERT_FALSE (store.confirmation_height.get (transaction, nano::dev::genesis->account (),
confirmation_height_info));
ASSERT_EQ (confirmation_height_info.height, 1);
ASSERT_EQ (confirmation_height_info.frontier, nano::dev::genesis->hash ());
// These databases get removed after an upgrade, so readd them
ASSERT_FALSE (
mdb_dbi_open (store.env.tx (transaction), "state_v1", MDB_CREATE, &store.state_blocks_v1_handle));
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "accounts_v1", MDB_CREATE,
&store.account_store.accounts_v1_handle));
ASSERT_FALSE (
mdb_dbi_open (store.env.tx (transaction), "pending_v1", MDB_CREATE, &store.pending_v1_handle));
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "open", MDB_CREATE, &store.open_blocks_handle));
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "send", MDB_CREATE, &store.send_blocks_handle));
ASSERT_FALSE (
mdb_dbi_open (store.env.tx (transaction), "state_blocks", MDB_CREATE,
&store.state_blocks_handle));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send).code);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch).code);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, state_send).code);
// Lower the database to the previous version
store.version.put (transaction, 14);
store.confirmation_height.del (transaction, nano::dev::genesis->account ());
modify_account_info_to_v14 (store, transaction, nano::dev::genesis->account (),
confirmation_height_info.height, state_send.hash ());
store.pending.del (transaction, nano::pending_key (nano::dev::genesis->account (), state_send.hash ()));
write_sideband_v14 (store, transaction, state_send, store.state_blocks_v1_handle);
write_sideband_v14 (store, transaction, epoch, store.state_blocks_v1_handle);
write_block_w_sideband_v18 (store, store.open_blocks_handle, transaction, *nano::dev::genesis);
write_block_w_sideband_v18 (store, store.send_blocks_handle, transaction, send);
// Remove from blocks table
store.block.del (transaction, state_send.hash ());
store.block.del (transaction, epoch.hash ());
// Turn pending into v14
ASSERT_FALSE (mdb_put (store.env.tx (transaction), store.pending_v0_handle,
nano::mdb_val (nano::pending_key (nano::dev::genesis_key.pub, send.hash ())),
nano::mdb_val (
nano::pending_info_v14 (nano::dev::genesis->account (), nano::Gxrb_ratio,
nano::epoch::epoch_0)),
0));
ASSERT_FALSE (mdb_put (store.env.tx (transaction), store.pending_v1_handle,
nano::mdb_val (nano::pending_key (nano::dev::genesis_key.pub, state_send.hash ())),
nano::mdb_val (
nano::pending_info_v14 (nano::dev::genesis->account (), nano::Gxrb_ratio,
nano::epoch::epoch_1)),
0));
// This should fail as sizes are no longer correct for account_info
nano::mdb_val value;
ASSERT_FALSE (mdb_get (store.env.tx (transaction), store.account_store.accounts_v1_handle,
nano::mdb_val (nano::dev::genesis->account ()), value));
nano::account_info info;
ASSERT_NE (value.size (), info.db_size ());
store.account.del (transaction, nano::dev::genesis->account ());
// Confirmation height for the account should be deleted
ASSERT_TRUE (mdb_get (store.env.tx (transaction), store.confirmation_height_handle,
nano::mdb_val (nano::dev::genesis->account ()), value));
}
// Now do the upgrade
nano::logger_mt logger;
nano::lmdb::store store (logger, path, nano::dev::constants);
nano::stat stats;
nano::ledger ledger (store, stats, nano::dev::constants);
auto transaction (store.tx_begin_write ());
store.initialize (transaction, ledger.cache, nano::dev::constants);
nano::account_info account_info;
ASSERT_FALSE (store.account.get (transaction, nano::dev::genesis->account (), account_info));
ASSERT_FALSE (store.init_error ());
auto transaction (store.tx_begin_read ());
// Size of account_info should now equal that set in db
nano::mdb_val value;
ASSERT_FALSE (mdb_get (store.env.tx (transaction), store.account_store.accounts_handle,
nano::mdb_val (nano::dev::genesis->account ()), value));
nano::account_info info (value);
ASSERT_EQ (value.size (), info.db_size ());
// Confirmation height should exist
nano::confirmation_height_info confirmation_height_info;
ASSERT_FALSE (store.confirmation_height.get (transaction, nano::dev::genesis->account (), confirmation_height_info));
ASSERT_FALSE (
store.confirmation_height.get (transaction, nano::dev::genesis->account (),
confirmation_height_info));
ASSERT_EQ (confirmation_height_info.height, 1);
ASSERT_EQ (confirmation_height_info.frontier, nano::dev::genesis->hash ());
// These databases get removed after an upgrade, so readd them
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "state_v1", MDB_CREATE, &store.state_blocks_v1_handle));
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "accounts_v1", MDB_CREATE, &store.accounts_v1_handle));
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "pending_v1", MDB_CREATE, &store.pending_v1_handle));
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "open", MDB_CREATE, &store.open_blocks_handle));
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "send", MDB_CREATE, &store.send_blocks_handle));
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "state_blocks", MDB_CREATE, &store.state_blocks_handle));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send).code);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch).code);
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, state_send).code);
// Lower the database to the previous version
store.version.put (transaction, 14);
store.confirmation_height.del (transaction, nano::dev::genesis->account ());
modify_account_info_to_v14 (store, transaction, nano::dev::genesis->account (), confirmation_height_info.height, state_send.hash ());
store.pending.del (transaction, nano::pending_key (nano::dev::genesis->account (), state_send.hash ()));
// accounts_v1, state_blocks_v1 & pending_v1 tables should be deleted
auto error_get_accounts_v1 (mdb_get (store.env.tx (transaction), store.account_store.accounts_v1_handle,
nano::mdb_val (nano::dev::genesis->account ()), value));
ASSERT_NE (error_get_accounts_v1, MDB_SUCCESS);
auto error_get_pending_v1 (mdb_get (store.env.tx (transaction), store.pending_v1_handle, nano::mdb_val (nano::pending_key (nano::dev::genesis_key.pub, state_send.hash ())), value));
ASSERT_NE (error_get_pending_v1, MDB_SUCCESS);
auto error_get_state_v1 (
mdb_get (store.env.tx (transaction), store.state_blocks_v1_handle, nano::mdb_val (state_send.hash ()),
value));
ASSERT_NE (error_get_state_v1, MDB_SUCCESS);
write_sideband_v14 (store, transaction, state_send, store.state_blocks_v1_handle);
write_sideband_v14 (store, transaction, epoch, store.state_blocks_v1_handle);
write_block_w_sideband_v18 (store, store.open_blocks_handle, transaction, *nano::dev::genesis);
write_block_w_sideband_v18 (store, store.send_blocks_handle, transaction, send);
// Check that the epochs are set correctly for the sideband, accounts and pending entries
auto block = store.block.get (transaction, state_send.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_1);
block = store.block.get (transaction, send.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_0);
ASSERT_EQ (info.epoch (), nano::epoch::epoch_1);
nano::pending_info pending_info;
store.pending.get (transaction, nano::pending_key (nano::dev::genesis_key.pub, send.hash ()), pending_info);
ASSERT_EQ (pending_info.epoch, nano::epoch::epoch_0);
store.pending.get (transaction, nano::pending_key (nano::dev::genesis_key.pub, state_send.hash ()),
pending_info);
ASSERT_EQ (pending_info.epoch, nano::epoch::epoch_1);
// Remove from blocks table
store.block.del (transaction, state_send.hash ());
store.block.del (transaction, epoch.hash ());
// Version should be correct
ASSERT_LT (14, store.version.get (transaction));
}
// Turn pending into v14
ASSERT_FALSE (mdb_put (store.env.tx (transaction), store.pending_v0_handle, nano::mdb_val (nano::pending_key (nano::dev::genesis_key.pub, send.hash ())), nano::mdb_val (nano::pending_info_v14 (nano::dev::genesis->account (), nano::Gxrb_ratio, nano::epoch::epoch_0)), 0));
ASSERT_FALSE (mdb_put (store.env.tx (transaction), store.pending_v1_handle, nano::mdb_val (nano::pending_key (nano::dev::genesis_key.pub, state_send.hash ())), nano::mdb_val (nano::pending_info_v14 (nano::dev::genesis->account (), nano::Gxrb_ratio, nano::epoch::epoch_1)), 0));
// This should fail as sizes are no longer correct for account_info
TEST (mdb_block_store, upgrade_v15_v16)
{
if (nano::rocksdb_config::using_rocksdb_in_tests ())
{
// Don't test this in rocksdb mode
return;
}
auto path (nano::unique_path ());
nano::mdb_val value;
ASSERT_FALSE (mdb_get (store.env.tx (transaction), store.accounts_v1_handle, nano::mdb_val (nano::dev::genesis->account ()), value));
nano::account_info info;
ASSERT_NE (value.size (), info.db_size ());
store.account.del (transaction, nano::dev::genesis->account ());
{
nano::logger_mt logger;
nano::lmdb::store store (logger, path, nano::dev::constants);
nano::stat stats;
nano::ledger ledger (store, stats, nano::dev::constants);
auto transaction (store.tx_begin_write ());
store.initialize (transaction, ledger.cache, nano::dev::constants);
// The representation table should get removed after, so readd it so that we can later confirm this actually happens
auto txn = store.env.tx (transaction);
ASSERT_FALSE (
mdb_dbi_open (txn, "representation", MDB_CREATE, &store.account_store.representation_handle));
auto weight = ledger.cache.rep_weights.representation_get (nano::dev::genesis->account ());
ASSERT_EQ (MDB_SUCCESS, mdb_put (txn, store.account_store.representation_handle, nano::mdb_val (nano::dev::genesis->account ()), nano::mdb_val (nano::uint128_union (weight)), 0));
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "open", MDB_CREATE, &store.open_blocks_handle));
write_block_w_sideband_v18 (store, store.open_blocks_handle, transaction, *nano::dev::genesis);
// Lower the database to the previous version
store.version.put (transaction, 15);
// Confirm the rep weight exists in the database
ASSERT_EQ (MDB_SUCCESS, mdb_get (store.env.tx (transaction), store.account_store.representation_handle, nano::mdb_val (nano::dev::genesis->account ()), value));
store.confirmation_height.del (transaction, nano::dev::genesis->account ());
}
// Confirmation height for the account should be deleted
ASSERT_TRUE (mdb_get (store.env.tx (transaction), store.confirmation_height_handle, nano::mdb_val (nano::dev::genesis->account ()), value));
}
// Now do the upgrade
nano::logger_mt logger;
nano::lmdb::store store (logger, path, nano::dev::constants);
ASSERT_FALSE (store.init_error ());
auto transaction (store.tx_begin_read ());
// Size of account_info should now equal that set in db
nano::mdb_val value;
ASSERT_FALSE (mdb_get (store.env.tx (transaction), store.accounts_handle, nano::mdb_val (nano::dev::genesis->account ()), value));
nano::account_info info (value);
ASSERT_EQ (value.size (), info.db_size ());
// Confirmation height should exist
nano::confirmation_height_info confirmation_height_info;
ASSERT_FALSE (store.confirmation_height.get (transaction, nano::dev::genesis->account (), confirmation_height_info));
ASSERT_EQ (confirmation_height_info.height, 1);
ASSERT_EQ (confirmation_height_info.frontier, nano::dev::genesis->hash ());
// accounts_v1, state_blocks_v1 & pending_v1 tables should be deleted
auto error_get_accounts_v1 (mdb_get (store.env.tx (transaction), store.accounts_v1_handle, nano::mdb_val (nano::dev::genesis->account ()), value));
ASSERT_NE (error_get_accounts_v1, MDB_SUCCESS);
auto error_get_pending_v1 (mdb_get (store.env.tx (transaction), store.pending_v1_handle, nano::mdb_val (nano::pending_key (nano::dev::genesis_key.pub, state_send.hash ())), value));
ASSERT_NE (error_get_pending_v1, MDB_SUCCESS);
auto error_get_state_v1 (mdb_get (store.env.tx (transaction), store.state_blocks_v1_handle, nano::mdb_val (state_send.hash ()), value));
ASSERT_NE (error_get_state_v1, MDB_SUCCESS);
// Check that the epochs are set correctly for the sideband, accounts and pending entries
auto block = store.block.get (transaction, state_send.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_1);
block = store.block.get (transaction, send.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_0);
ASSERT_EQ (info.epoch (), nano::epoch::epoch_1);
nano::pending_info pending_info;
store.pending.get (transaction, nano::pending_key (nano::dev::genesis_key.pub, send.hash ()), pending_info);
ASSERT_EQ (pending_info.epoch, nano::epoch::epoch_0);
store.pending.get (transaction, nano::pending_key (nano::dev::genesis_key.pub, state_send.hash ()), pending_info);
ASSERT_EQ (pending_info.epoch, nano::epoch::epoch_1);
// Version should be correct
ASSERT_LT (14, store.version.get (transaction));
}
TEST (mdb_block_store, upgrade_v15_v16)
{
if (nano::rocksdb_config::using_rocksdb_in_tests ())
{
// Don't test this in rocksdb mode
return;
}
auto path (nano::unique_path ());
nano::mdb_val value;
{
// Now do the upgrade
nano::logger_mt logger;
nano::lmdb::store store (logger, path, nano::dev::constants);
nano::stat stats;
nano::ledger ledger (store, stats, nano::dev::constants);
auto transaction (store.tx_begin_write ());
store.initialize (transaction, ledger.cache, nano::dev::constants);
// The representation table should get removed after, so readd it so that we can later confirm this actually happens
auto txn = store.env.tx (transaction);
ASSERT_FALSE (mdb_dbi_open (txn, "representation", MDB_CREATE, &store.representation_handle));
auto weight = ledger.cache.rep_weights.representation_get (nano::dev::genesis->account ());
ASSERT_EQ (MDB_SUCCESS, mdb_put (txn, store.representation_handle, nano::mdb_val (nano::dev::genesis->account ()), nano::mdb_val (nano::uint128_union (weight)), 0));
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "open", MDB_CREATE, &store.open_blocks_handle));
write_block_w_sideband_v18 (store, store.open_blocks_handle, transaction, *nano::dev::genesis);
// Lower the database to the previous version
store.version.put (transaction, 15);
// Confirm the rep weight exists in the database
ASSERT_EQ (MDB_SUCCESS, mdb_get (store.env.tx (transaction), store.representation_handle, nano::mdb_val (nano::dev::genesis->account ()), value));
store.confirmation_height.del (transaction, nano::dev::genesis->account ());
ASSERT_FALSE (store.init_error ());
auto transaction (store.tx_begin_read ());
// The representation table should now be deleted
auto error_get_representation (mdb_get (store.env.tx (transaction), store.account_store.representation_handle,
nano::mdb_val (nano::dev::genesis->account ()), value));
ASSERT_NE (MDB_SUCCESS, error_get_representation);
ASSERT_EQ (store.account_store.representation_handle, 0);
// Version should be correct
ASSERT_LT (15, store.version.get (transaction));
}
// Now do the upgrade
nano::logger_mt logger;
nano::lmdb::store store (logger, path, nano::dev::constants);
ASSERT_FALSE (store.init_error ());
auto transaction (store.tx_begin_read ());
// The representation table should now be deleted
auto error_get_representation (mdb_get (store.env.tx (transaction), store.representation_handle, nano::mdb_val (nano::dev::genesis->account ()), value));
ASSERT_NE (MDB_SUCCESS, error_get_representation);
ASSERT_EQ (store.representation_handle, 0);
// Version should be correct
ASSERT_LT (15, store.version.get (transaction));
}
}
TEST (mdb_block_store, upgrade_v16_v17)
@ -2067,75 +2115,78 @@ TEST (rocksdb_block_store, tombstone_count)
}
}
namespace
namespace nano
{
void write_sideband_v14 (nano::lmdb::store & store_a, nano::transaction & transaction_a, nano::block const & block_a, MDB_dbi db_a)
namespace lmdb
{
auto block = store_a.block.get (transaction_a, block_a.hash ());
ASSERT_NE (block, nullptr);
nano::block_sideband_v14 sideband_v14 (block->type (), block->sideband ().account, block->sideband ().successor, block->sideband ().balance, block->sideband ().timestamp, block->sideband ().height);
std::vector<uint8_t> data;
void write_sideband_v14 (nano::lmdb::store & store_a, nano::transaction & transaction_a, nano::block const & block_a, MDB_dbi db_a)
{
nano::vectorstream stream (data);
block_a.serialize (stream);
sideband_v14.serialize (stream);
auto block = store_a.block.get (transaction_a, block_a.hash ());
ASSERT_NE (block, nullptr);
nano::block_sideband_v14 sideband_v14 (block->type (), block->sideband ().account, block->sideband ().successor, block->sideband ().balance, block->sideband ().timestamp, block->sideband ().height);
std::vector<uint8_t> data;
{
nano::vectorstream stream (data);
block_a.serialize (stream);
sideband_v14.serialize (stream);
}
MDB_val val{ data.size (), data.data () };
ASSERT_FALSE (mdb_put (store_a.env.tx (transaction_a), block->sideband ().details.epoch == nano::epoch::epoch_0 ? store_a.state_blocks_v0_handle : store_a.state_blocks_v1_handle, nano::mdb_val (block_a.hash ()), &val, 0));
}
MDB_val val{ data.size (), data.data () };
ASSERT_FALSE (mdb_put (store_a.env.tx (transaction_a), block->sideband ().details.epoch == nano::epoch::epoch_0 ? store_a.state_blocks_v0_handle : store_a.state_blocks_v1_handle, nano::mdb_val (block_a.hash ()), &val, 0));
}
void write_sideband_v15 (nano::lmdb::store & store_a, nano::transaction & transaction_a, nano::block const & block_a)
{
auto block = store_a.block.get (transaction_a, block_a.hash ());
ASSERT_NE (block, nullptr);
ASSERT_LE (block->sideband ().details.epoch, nano::epoch::max);
// Simulated by writing 0 on every of the most significant bits, leaving out epoch only, as if pre-upgrade
nano::block_sideband_v18 sideband_v15 (block->sideband ().account, block->sideband ().successor, block->sideband ().balance, block->sideband ().timestamp, block->sideband ().height, block->sideband ().details.epoch, false, false, false);
std::vector<uint8_t> data;
void write_sideband_v15 (nano::lmdb::store & store_a, nano::transaction & transaction_a, nano::block const & block_a)
{
nano::vectorstream stream (data);
block_a.serialize (stream);
sideband_v15.serialize (stream, block_a.type ());
auto block = store_a.block.get (transaction_a, block_a.hash ());
ASSERT_NE (block, nullptr);
ASSERT_LE (block->sideband ().details.epoch, nano::epoch::max);
// Simulated by writing 0 on every of the most significant bits, leaving out epoch only, as if pre-upgrade
nano::block_sideband_v18 sideband_v15 (block->sideband ().account, block->sideband ().successor, block->sideband ().balance, block->sideband ().timestamp, block->sideband ().height, block->sideband ().details.epoch, false, false, false);
std::vector<uint8_t> data;
{
nano::vectorstream stream (data);
block_a.serialize (stream);
sideband_v15.serialize (stream, block_a.type ());
}
MDB_val val{ data.size (), data.data () };
ASSERT_FALSE (mdb_put (store_a.env.tx (transaction_a), store_a.state_blocks_handle, nano::mdb_val (block_a.hash ()), &val, 0));
}
MDB_val val{ data.size (), data.data () };
ASSERT_FALSE (mdb_put (store_a.env.tx (transaction_a), store_a.state_blocks_handle, nano::mdb_val (block_a.hash ()), &val, 0));
}
void write_block_w_sideband_v18 (nano::lmdb::store & store_a, MDB_dbi database, nano::write_transaction & transaction_a, nano::block const & block_a)
{
auto block = store_a.block.get (transaction_a, block_a.hash ());
ASSERT_NE (block, nullptr);
auto new_sideband (block->sideband ());
nano::block_sideband_v18 sideband_v18 (new_sideband.account, new_sideband.successor, new_sideband.balance, new_sideband.height, new_sideband.timestamp, new_sideband.details.epoch, new_sideband.details.is_send, new_sideband.details.is_receive, new_sideband.details.is_epoch);
std::vector<uint8_t> data;
void write_block_w_sideband_v18 (nano::lmdb::store & store_a, MDB_dbi database, nano::write_transaction & transaction_a, nano::block const & block_a)
{
nano::vectorstream stream (data);
block->serialize (stream);
sideband_v18.serialize (stream, block->type ());
auto block = store_a.block.get (transaction_a, block_a.hash ());
ASSERT_NE (block, nullptr);
auto new_sideband (block->sideband ());
nano::block_sideband_v18 sideband_v18 (new_sideband.account, new_sideband.successor, new_sideband.balance, new_sideband.height, new_sideband.timestamp, new_sideband.details.epoch, new_sideband.details.is_send, new_sideband.details.is_receive, new_sideband.details.is_epoch);
std::vector<uint8_t> data;
{
nano::vectorstream stream (data);
block->serialize (stream);
sideband_v18.serialize (stream, block->type ());
}
MDB_val val{ data.size (), data.data () };
ASSERT_FALSE (mdb_put (store_a.env.tx (transaction_a), database, nano::mdb_val (block_a.hash ()), &val, 0));
store_a.del (transaction_a, nano::tables::blocks, nano::mdb_val (block_a.hash ()));
}
MDB_val val{ data.size (), data.data () };
ASSERT_FALSE (mdb_put (store_a.env.tx (transaction_a), database, nano::mdb_val (block_a.hash ()), &val, 0));
store_a.del (transaction_a, nano::tables::blocks, nano::mdb_val (block_a.hash ()));
}
void modify_account_info_to_v14 (nano::lmdb::store & store, nano::transaction const & transaction, nano::account const & account, uint64_t confirmation_height, nano::block_hash const & rep_block)
{
nano::account_info info;
ASSERT_FALSE (store.account.get (transaction, account, info));
nano::account_info_v14 account_info_v14 (info.head, rep_block, info.open_block, info.balance, info.modified, info.block_count, confirmation_height, info.epoch ());
auto status (mdb_put (store.env.tx (transaction), info.epoch () == nano::epoch::epoch_0 ? store.account_store.accounts_v0_handle : store.account_store.accounts_v1_handle, nano::mdb_val (account), nano::mdb_val (account_info_v14), 0));
ASSERT_EQ (status, 0);
}
void modify_account_info_to_v14 (nano::lmdb::store & store, nano::transaction const & transaction, nano::account const & account, uint64_t confirmation_height, nano::block_hash const & rep_block)
{
nano::account_info info;
ASSERT_FALSE (store.account.get (transaction, account, info));
nano::account_info_v14 account_info_v14 (info.head, rep_block, info.open_block, info.balance, info.modified, info.block_count, confirmation_height, info.epoch ());
auto status (mdb_put (store.env.tx (transaction), info.epoch () == nano::epoch::epoch_0 ? store.accounts_v0_handle : store.accounts_v1_handle, nano::mdb_val (account), nano::mdb_val (account_info_v14), 0));
ASSERT_EQ (status, 0);
}
void modify_confirmation_height_to_v15 (nano::lmdb::store & store, nano::transaction const & transaction, nano::account const & account, uint64_t confirmation_height)
{
auto status (mdb_put (store.env.tx (transaction), store.confirmation_height_handle, nano::mdb_val (account), nano::mdb_val (confirmation_height), 0));
ASSERT_EQ (status, 0);
void modify_confirmation_height_to_v15 (nano::lmdb::store & store, nano::transaction const & transaction, nano::account const & account, uint64_t confirmation_height)
{
auto status (mdb_put (store.env.tx (transaction), store.confirmation_height_handle, nano::mdb_val (account), nano::mdb_val (confirmation_height), 0));
ASSERT_EQ (status, 0);
}
}
}

View file

@ -2,6 +2,8 @@
#include <nano/secure/store.hpp>
#include <lmdb/libraries/liblmdb/lmdb.h>
namespace nano
{
namespace lmdb
@ -24,6 +26,30 @@ namespace lmdb
nano::store_iterator<nano::account, nano::account_info> rbegin (nano::transaction const & transaction_a) const override;
nano::store_iterator<nano::account, nano::account_info> end () const override;
void for_each_par (std::function<void (nano::read_transaction const &, nano::store_iterator<nano::account, nano::account_info>, nano::store_iterator<nano::account, nano::account_info>)> const & action_a) const override;
/**
* Maps account v1 to account information, head, rep, open, balance, timestamp and block count. (Removed)
* nano::account -> nano::block_hash, nano::block_hash, nano::block_hash, nano::amount, uint64_t, uint64_t
*/
MDB_dbi accounts_v0_handle{ 0 };
/**
* Maps account v0 to account information, head, rep, open, balance, timestamp and block count. (Removed)
* nano::account -> nano::block_hash, nano::block_hash, nano::block_hash, nano::amount, uint64_t, uint64_t
*/
MDB_dbi accounts_v1_handle{ 0 };
/**
* Maps account v0 to account information, head, rep, open, balance, timestamp, block count and epoch
* nano::account -> nano::block_hash, nano::block_hash, nano::block_hash, nano::amount, uint64_t, uint64_t, nano::epoch
*/
MDB_dbi accounts_handle{ 0 };
/**
* Representative weights. (Removed)
* nano::account -> nano::uint128_t
*/
MDB_dbi representation_handle{ 0 };
};
}
}

View file

@ -217,8 +217,8 @@ void nano::lmdb::store::open_databases (bool & error_a, nano::transaction const
error_a |= mdb_dbi_open (env.tx (transaction_a), "peers", flags, &peers_handle) != 0;
error_a |= mdb_dbi_open (env.tx (transaction_a), "pruned", flags, &pruned_handle) != 0;
error_a |= mdb_dbi_open (env.tx (transaction_a), "confirmation_height", flags, &confirmation_height_handle) != 0;
error_a |= mdb_dbi_open (env.tx (transaction_a), "accounts", flags, &accounts_v0_handle) != 0;
accounts_handle = accounts_v0_handle;
error_a |= mdb_dbi_open (env.tx (transaction_a), "accounts", flags, &account_store.accounts_v0_handle) != 0;
account_store.accounts_handle = account_store.accounts_v0_handle;
error_a |= mdb_dbi_open (env.tx (transaction_a), "pending", flags, &pending_v0_handle) != 0;
pending_handle = pending_v0_handle;
error_a |= mdb_dbi_open (env.tx (transaction_a), "final_votes", flags, &final_votes_handle) != 0;
@ -245,7 +245,7 @@ void nano::lmdb::store::open_databases (bool & error_a, nano::transaction const
if (version_l < 16)
{
// The representation database is no longer used, but needs opening so that it can be deleted during an upgrade
error_a |= mdb_dbi_open (env.tx (transaction_a), "representation", flags, &representation_handle) != 0;
error_a |= mdb_dbi_open (env.tx (transaction_a), "representation", flags, &account_store.representation_handle) != 0;
}
if (version_l < 15)
@ -253,7 +253,7 @@ void nano::lmdb::store::open_databases (bool & error_a, nano::transaction const
// These databases are no longer used, but need opening so they can be deleted during an upgrade
error_a |= mdb_dbi_open (env.tx (transaction_a), "state", flags, &state_blocks_v0_handle) != 0;
state_blocks_handle = state_blocks_v0_handle;
error_a |= mdb_dbi_open (env.tx (transaction_a), "accounts_v1", flags, &accounts_v1_handle) != 0;
error_a |= mdb_dbi_open (env.tx (transaction_a), "accounts_v1", flags, &account_store.accounts_v1_handle) != 0;
error_a |= mdb_dbi_open (env.tx (transaction_a), "pending_v1", flags, &pending_v1_handle) != 0;
error_a |= mdb_dbi_open (env.tx (transaction_a), "state_v1", flags, &state_blocks_v1_handle) != 0;
}
@ -320,10 +320,10 @@ void nano::lmdb::store::upgrade_v14_to_v15 (nano::write_transaction & transactio
logger.always_log ("Preparing v14 to v15 database upgrade...");
std::vector<std::pair<nano::account, nano::account_info>> account_infos;
upgrade_counters account_counters (count (transaction_a, accounts_v0_handle), count (transaction_a, accounts_v1_handle));
upgrade_counters account_counters (count (transaction_a, account_store.accounts_v0_handle), count (transaction_a, account_store.accounts_v1_handle));
account_infos.reserve (account_counters.before_v0 + account_counters.before_v1);
nano::mdb_merge_iterator<nano::account, nano::account_info_v14> i_account (transaction_a, accounts_v0_handle, accounts_v1_handle);
nano::mdb_merge_iterator<nano::account, nano::account_info_v14> i_account (transaction_a, account_store.accounts_v0_handle, account_store.accounts_v1_handle);
nano::mdb_merge_iterator<nano::account, nano::account_info_v14> n_account{};
for (; i_account != n_account; ++i_account)
{
@ -343,13 +343,13 @@ void nano::lmdb::store::upgrade_v14_to_v15 (nano::write_transaction & transactio
debug_assert (account_counters.are_equal ());
// No longer need accounts_v1, keep v0 but clear it
mdb_drop (env.tx (transaction_a), accounts_v1_handle, 1);
mdb_drop (env.tx (transaction_a), accounts_v0_handle, 0);
mdb_drop (env.tx (transaction_a), account_store.accounts_v1_handle, 1);
mdb_drop (env.tx (transaction_a), account_store.accounts_v0_handle, 0);
for (auto const & account_account_info_pair : account_infos)
{
auto const & account_info (account_account_info_pair.second);
mdb_put (env.tx (transaction_a), accounts_handle, nano::mdb_val (account_account_info_pair.first), nano::mdb_val (account_info), MDB_APPEND);
mdb_put (env.tx (transaction_a), account_store.accounts_handle, nano::mdb_val (account_account_info_pair.first), nano::mdb_val (account_info), MDB_APPEND);
}
logger.always_log ("Epoch merge upgrade: Finished accounts, now doing state blocks");
@ -436,12 +436,12 @@ void nano::lmdb::store::upgrade_v14_to_v15 (nano::write_transaction & transactio
void nano::lmdb::store::upgrade_v15_to_v16 (nano::write_transaction const & transaction_a)
{
// Representation table is no longer used
debug_assert (representation_handle != 0);
if (representation_handle != 0)
debug_assert (account_store.representation_handle != 0);
if (account_store.representation_handle != 0)
{
auto status (mdb_drop (env.tx (transaction_a), representation_handle, 1));
auto status (mdb_drop (env.tx (transaction_a), account_store.representation_handle, 1));
release_assert (status == MDB_SUCCESS);
representation_handle = 0;
account_store.representation_handle = 0;
}
version.put (transaction_a, 16);
}
@ -863,7 +863,7 @@ MDB_dbi nano::lmdb::store::table_to_dbi (tables table_a) const
case tables::frontiers:
return frontier_store.frontiers_handle;
case tables::accounts:
return accounts_handle;
return account_store.accounts_handle;
case tables::blocks:
return blocks_handle;
case tables::pending:
@ -916,7 +916,7 @@ bool nano::lmdb::store::copy_db (boost::filesystem::path const & destination_fil
void nano::lmdb::store::rebuild_db (nano::write_transaction const & transaction_a)
{
// Tables with uint256_union key
std::vector<MDB_dbi> tables = { accounts_handle, blocks_handle, pruned_handle, confirmation_height_handle };
std::vector<MDB_dbi> tables = { account_store.accounts_handle, blocks_handle, pruned_handle, confirmation_height_handle };
for (auto const & table : tables)
{
MDB_dbi temp;

View file

@ -94,24 +94,6 @@ namespace lmdb
public:
nano::mdb_env env;
/**
* Maps account v1 to account information, head, rep, open, balance, timestamp and block count. (Removed)
* nano::account -> nano::block_hash, nano::block_hash, nano::block_hash, nano::amount, uint64_t, uint64_t
*/
MDB_dbi accounts_v0_handle{ 0 };
/**
* Maps account v0 to account information, head, rep, open, balance, timestamp and block count. (Removed)
* nano::account -> nano::block_hash, nano::block_hash, nano::block_hash, nano::amount, uint64_t, uint64_t
*/
MDB_dbi accounts_v1_handle{ 0 };
/**
* Maps account v0 to account information, head, rep, open, balance, timestamp, block count and epoch
* nano::account -> nano::block_hash, nano::block_hash, nano::block_hash, nano::amount, uint64_t, uint64_t, nano::epoch
*/
MDB_dbi accounts_handle{ 0 };
/**
* Maps block hash to send block. (Removed)
* nano::block_hash -> nano::send_block
@ -172,12 +154,6 @@ namespace lmdb
*/
MDB_dbi pending_handle{ 0 };
/**
* Representative weights. (Removed)
* nano::account -> nano::uint128_t
*/
MDB_dbi representation_handle{ 0 };
/**
* Unchecked bootstrap blocks info.
* nano::block_hash -> nano::unchecked_info
@ -311,6 +287,11 @@ namespace lmdb
uint64_t after_v0{ 0 };
uint64_t after_v1{ 0 };
};
friend class mdb_block_store_supported_version_upgrades_Test;
friend class mdb_block_store_upgrade_v14_v15_Test;
friend class mdb_block_store_upgrade_v15_v16_Test;
friend void modify_account_info_to_v14 (nano::lmdb::store &, nano::transaction const &, nano::account const &, uint64_t, nano::block_hash const &);
};
}