Refactor database code to allow easier reuse with different backends (#2136)
This commit is contained in:
parent
243fa1c988
commit
53384d7342
4 changed files with 827 additions and 862 deletions
|
@ -9,6 +9,28 @@
|
|||
|
||||
#include <queue>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
template <>
|
||||
void * mdb_val::data () const
|
||||
{
|
||||
return value.mv_data;
|
||||
}
|
||||
|
||||
template <>
|
||||
size_t mdb_val::size () const
|
||||
{
|
||||
return value.mv_size;
|
||||
}
|
||||
|
||||
template <>
|
||||
mdb_val::db_val (nano::DB_val const & value_a, nano::epoch epoch_a) :
|
||||
value ({ value_a.size, value_a.data }),
|
||||
epoch (epoch_a)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
nano::mdb_env::mdb_env (bool & error_a, boost::filesystem::path const & path_a, int max_dbs_a, bool use_no_mem_init_a, size_t map_size_a)
|
||||
{
|
||||
boost::system::error_code error_mkdir, error_chmod;
|
||||
|
@ -160,333 +182,6 @@ void * nano::write_mdb_txn::get_handle () const
|
|||
return handle;
|
||||
}
|
||||
|
||||
nano::mdb_val::mdb_val (nano::epoch epoch_a) :
|
||||
value ({ 0, nullptr }),
|
||||
epoch (epoch_a)
|
||||
{
|
||||
}
|
||||
|
||||
nano::mdb_val::mdb_val (MDB_val const & value_a, nano::epoch epoch_a) :
|
||||
value (value_a),
|
||||
epoch (epoch_a)
|
||||
{
|
||||
}
|
||||
|
||||
nano::mdb_val::mdb_val (size_t size_a, void * data_a) :
|
||||
value ({ size_a, data_a })
|
||||
{
|
||||
}
|
||||
|
||||
nano::mdb_val::mdb_val (nano::uint128_union const & val_a) :
|
||||
mdb_val (sizeof (val_a), const_cast<nano::uint128_union *> (&val_a))
|
||||
{
|
||||
}
|
||||
|
||||
nano::mdb_val::mdb_val (nano::uint256_union const & val_a) :
|
||||
mdb_val (sizeof (val_a), const_cast<nano::uint256_union *> (&val_a))
|
||||
{
|
||||
}
|
||||
|
||||
nano::mdb_val::mdb_val (nano::account_info const & val_a) :
|
||||
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))
|
||||
{
|
||||
static_assert (std::is_standard_layout<nano::pending_info>::value, "Standard layout is required");
|
||||
}
|
||||
|
||||
nano::mdb_val::mdb_val (nano::pending_key const & val_a) :
|
||||
mdb_val (sizeof (val_a), const_cast<nano::pending_key *> (&val_a))
|
||||
{
|
||||
static_assert (std::is_standard_layout<nano::pending_key>::value, "Standard layout is required");
|
||||
}
|
||||
|
||||
nano::mdb_val::mdb_val (nano::unchecked_info const & val_a) :
|
||||
buffer (std::make_shared<std::vector<uint8_t>> ())
|
||||
{
|
||||
{
|
||||
nano::vectorstream stream (*buffer);
|
||||
val_a.serialize (stream);
|
||||
}
|
||||
value = { buffer->size (), const_cast<uint8_t *> (buffer->data ()) };
|
||||
}
|
||||
|
||||
nano::mdb_val::mdb_val (nano::block_info const & val_a) :
|
||||
mdb_val (sizeof (val_a), const_cast<nano::block_info *> (&val_a))
|
||||
{
|
||||
static_assert (std::is_standard_layout<nano::block_info>::value, "Standard layout is required");
|
||||
}
|
||||
|
||||
nano::mdb_val::mdb_val (nano::endpoint_key const & val_a) :
|
||||
mdb_val (sizeof (val_a), const_cast<nano::endpoint_key *> (&val_a))
|
||||
{
|
||||
static_assert (std::is_standard_layout<nano::endpoint_key>::value, "Standard layout is required");
|
||||
}
|
||||
|
||||
nano::mdb_val::mdb_val (std::shared_ptr<nano::block> const & val_a) :
|
||||
buffer (std::make_shared<std::vector<uint8_t>> ())
|
||||
{
|
||||
{
|
||||
nano::vectorstream stream (*buffer);
|
||||
nano::serialize_block (stream, *val_a);
|
||||
}
|
||||
value = { buffer->size (), const_cast<uint8_t *> (buffer->data ()) };
|
||||
}
|
||||
|
||||
nano::mdb_val::mdb_val (uint64_t val_a) :
|
||||
buffer (std::make_shared<std::vector<uint8_t>> ())
|
||||
{
|
||||
{
|
||||
boost::endian::native_to_big_inplace (val_a);
|
||||
nano::vectorstream stream (*buffer);
|
||||
nano::write (stream, val_a);
|
||||
}
|
||||
value = { buffer->size (), const_cast<uint8_t *> (buffer->data ()) };
|
||||
}
|
||||
|
||||
void * nano::mdb_val::data () const
|
||||
{
|
||||
return value.mv_data;
|
||||
}
|
||||
|
||||
size_t nano::mdb_val::size () const
|
||||
{
|
||||
return value.mv_size;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator nano::account_info () const
|
||||
{
|
||||
nano::account_info 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::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;
|
||||
assert (value.mv_size == sizeof (result));
|
||||
static_assert (sizeof (nano::block_info::account) + sizeof (nano::block_info::balance) == sizeof (result), "Packed class");
|
||||
std::copy (reinterpret_cast<uint8_t const *> (value.mv_data), reinterpret_cast<uint8_t const *> (value.mv_data) + sizeof (result), reinterpret_cast<uint8_t *> (&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator nano::pending_info () const
|
||||
{
|
||||
nano::pending_info result;
|
||||
result.epoch = epoch;
|
||||
std::copy (reinterpret_cast<uint8_t const *> (value.mv_data), reinterpret_cast<uint8_t const *> (value.mv_data) + sizeof (nano::pending_info::source) + sizeof (nano::pending_info::amount), reinterpret_cast<uint8_t *> (&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator nano::pending_key () const
|
||||
{
|
||||
nano::pending_key result;
|
||||
assert (value.mv_size == sizeof (result));
|
||||
static_assert (sizeof (nano::pending_key::account) + sizeof (nano::pending_key::hash) == sizeof (result), "Packed class");
|
||||
std::copy (reinterpret_cast<uint8_t const *> (value.mv_data), reinterpret_cast<uint8_t const *> (value.mv_data) + sizeof (result), reinterpret_cast<uint8_t *> (&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator nano::unchecked_info () const
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.mv_data), value.mv_size);
|
||||
nano::unchecked_info result;
|
||||
bool error (result.deserialize (stream));
|
||||
assert (!error);
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator nano::uint128_union () const
|
||||
{
|
||||
nano::uint128_union result;
|
||||
assert (size () == sizeof (result));
|
||||
std::copy (reinterpret_cast<uint8_t const *> (data ()), reinterpret_cast<uint8_t const *> (data ()) + sizeof (result), result.bytes.data ());
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator nano::uint256_union () const
|
||||
{
|
||||
nano::uint256_union result;
|
||||
assert (size () == sizeof (result));
|
||||
std::copy (reinterpret_cast<uint8_t const *> (data ()), reinterpret_cast<uint8_t const *> (data ()) + sizeof (result), result.bytes.data ());
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator std::array<char, 64> () const
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.mv_data), value.mv_size);
|
||||
std::array<char, 64> result;
|
||||
auto error = nano::try_read (stream, result);
|
||||
assert (!error);
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator nano::endpoint_key () const
|
||||
{
|
||||
nano::endpoint_key result;
|
||||
std::copy (reinterpret_cast<uint8_t const *> (value.mv_data), reinterpret_cast<uint8_t const *> (value.mv_data) + sizeof (result), reinterpret_cast<uint8_t *> (&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator nano::no_value () const
|
||||
{
|
||||
return no_value::dummy;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator std::shared_ptr<nano::block> () const
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.mv_data), value.mv_size);
|
||||
std::shared_ptr<nano::block> result (nano::deserialize_block (stream));
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator std::shared_ptr<nano::send_block> () const
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.mv_data), value.mv_size);
|
||||
auto error (false);
|
||||
std::shared_ptr<nano::send_block> result (std::make_shared<nano::send_block> (error, stream));
|
||||
assert (!error);
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator std::shared_ptr<nano::receive_block> () const
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.mv_data), value.mv_size);
|
||||
auto error (false);
|
||||
std::shared_ptr<nano::receive_block> result (std::make_shared<nano::receive_block> (error, stream));
|
||||
assert (!error);
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator std::shared_ptr<nano::open_block> () const
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.mv_data), value.mv_size);
|
||||
auto error (false);
|
||||
std::shared_ptr<nano::open_block> result (std::make_shared<nano::open_block> (error, stream));
|
||||
assert (!error);
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator std::shared_ptr<nano::change_block> () const
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.mv_data), value.mv_size);
|
||||
auto error (false);
|
||||
std::shared_ptr<nano::change_block> result (std::make_shared<nano::change_block> (error, stream));
|
||||
assert (!error);
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator std::shared_ptr<nano::state_block> () const
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.mv_data), value.mv_size);
|
||||
auto error (false);
|
||||
std::shared_ptr<nano::state_block> result (std::make_shared<nano::state_block> (error, stream));
|
||||
assert (!error);
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator std::shared_ptr<nano::vote> () const
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.mv_data), value.mv_size);
|
||||
auto error (false);
|
||||
auto result (nano::make_shared<nano::vote> (error, stream));
|
||||
assert (!error);
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator uint64_t () const
|
||||
{
|
||||
uint64_t result;
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.mv_data), value.mv_size);
|
||||
auto error (nano::try_read (stream, result));
|
||||
assert (!error);
|
||||
boost::endian::big_to_native_inplace (result);
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::mdb_val::operator MDB_val * () const
|
||||
{
|
||||
// Allow passing a temporary to a non-c++ function which doesn't have constness
|
||||
return const_cast<MDB_val *> (&value);
|
||||
}
|
||||
|
||||
nano::mdb_val::operator MDB_val const & () const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
/**
|
||||
* Fill in our predecessors
|
||||
*/
|
||||
class block_predecessor_set : public nano::block_visitor
|
||||
{
|
||||
public:
|
||||
block_predecessor_set (nano::transaction const & transaction_a, nano::mdb_store & store_a) :
|
||||
transaction (transaction_a),
|
||||
store (store_a)
|
||||
{
|
||||
}
|
||||
virtual ~block_predecessor_set () = default;
|
||||
void fill_value (nano::block const & block_a)
|
||||
{
|
||||
auto hash (block_a.hash ());
|
||||
nano::block_type type;
|
||||
auto value (store.block_raw_get (transaction, block_a.previous (), type));
|
||||
auto version (store.block_version (transaction, block_a.previous ()));
|
||||
assert (value.mv_size != 0);
|
||||
std::vector<uint8_t> data (static_cast<uint8_t *> (value.mv_data), static_cast<uint8_t *> (value.mv_data) + value.mv_size);
|
||||
std::copy (hash.bytes.begin (), hash.bytes.end (), data.begin () + store.block_successor_offset (transaction, value, type));
|
||||
store.block_raw_put (transaction, store.block_database (type, version), block_a.previous (), nano::mdb_val (data.size (), data.data ()));
|
||||
}
|
||||
void send_block (nano::send_block const & block_a) override
|
||||
{
|
||||
fill_value (block_a);
|
||||
}
|
||||
void receive_block (nano::receive_block const & block_a) override
|
||||
{
|
||||
fill_value (block_a);
|
||||
}
|
||||
void open_block (nano::open_block const & block_a) override
|
||||
{
|
||||
// Open blocks don't have a predecessor
|
||||
}
|
||||
void change_block (nano::change_block const & block_a) override
|
||||
{
|
||||
fill_value (block_a);
|
||||
}
|
||||
void state_block (nano::state_block const & block_a) override
|
||||
{
|
||||
if (!block_a.previous ().is_zero ())
|
||||
{
|
||||
fill_value (block_a);
|
||||
}
|
||||
}
|
||||
nano::transaction const & transaction;
|
||||
nano::mdb_store & store;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
nano::mdb_iterator<T, U>::mdb_iterator (nano::transaction const & transaction_a, MDB_dbi db_a, nano::epoch epoch_a) :
|
||||
cursor (nullptr)
|
||||
|
@ -912,22 +607,6 @@ nano::mdb_txn_callbacks nano::mdb_store::create_txn_callbacks ()
|
|||
return mdb_txn_callbacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ());
|
||||
assert (latest_v0_begin (transaction_a) == latest_v0_end ());
|
||||
assert (latest_v1_begin (transaction_a) == latest_v1_end ());
|
||||
nano::block_sideband sideband (nano::block_type::open, network_params.ledger.genesis_account, 0, network_params.ledger.genesis_amount, 1, nano::seconds_since_epoch ());
|
||||
block_put (transaction_a, hash_l, *genesis_a.open, sideband);
|
||||
account_put (transaction_a, network_params.ledger.genesis_account, { hash_l, genesis_a.open->hash (), genesis_a.open->hash (), std::numeric_limits<nano::uint128_t>::max (), nano::seconds_since_epoch (), 1, 1, nano::epoch::epoch_0 });
|
||||
representation_put (transaction_a, network_params.ledger.genesis_account, std::numeric_limits<nano::uint128_t>::max ());
|
||||
frontier_put (transaction_a, hash_l, network_params.ledger.genesis_account);
|
||||
}
|
||||
|
||||
void nano::mdb_store::open_databases (bool & error_a, nano::transaction const & transaction_a, unsigned flags)
|
||||
{
|
||||
error_a |= mdb_dbi_open (env.tx (transaction_a), "frontiers", flags, &frontiers) != 0;
|
||||
|
@ -1010,10 +689,7 @@ bool nano::mdb_store::peer_exists (nano::transaction const & transaction_a, nano
|
|||
|
||||
size_t nano::mdb_store::peer_count (nano::transaction const & transaction_a) const
|
||||
{
|
||||
MDB_stat stats;
|
||||
auto status (mdb_stat (env.tx (transaction_a), peers, &stats));
|
||||
release_assert (status == 0);
|
||||
return stats.ms_entries;
|
||||
return count (transaction_a, peers);
|
||||
}
|
||||
|
||||
void nano::mdb_store::peer_clear (nano::transaction const & transaction_a)
|
||||
|
@ -1165,16 +841,16 @@ void nano::mdb_store::upgrade_v4_to_v5 (nano::transaction const & transaction_a)
|
|||
block->serialize (stream);
|
||||
nano::write (stream, successor.bytes);
|
||||
}
|
||||
block_raw_put (transaction_a, block_database (block->type (), nano::epoch::epoch_0), hash, { vector.size (), vector.data () });
|
||||
block_raw_put (transaction_a, vector, block->type (), nano::epoch::epoch_0, hash);
|
||||
if (!block->previous ().is_zero ())
|
||||
{
|
||||
nano::block_type type;
|
||||
auto value (block_raw_get (transaction_a, block->previous (), type));
|
||||
auto version (block_version (transaction_a, block->previous ()));
|
||||
assert (value.mv_size != 0);
|
||||
std::vector<uint8_t> data (static_cast<uint8_t *> (value.mv_data), static_cast<uint8_t *> (value.mv_data) + value.mv_size);
|
||||
assert (value.size () != 0);
|
||||
std::vector<uint8_t> data (static_cast<uint8_t *> (value.data ()), static_cast<uint8_t *> (value.data ()) + value.size ());
|
||||
std::copy (hash.bytes.begin (), hash.bytes.end (), data.end () - nano::block_sideband::size (type));
|
||||
block_raw_put (transaction_a, block_database (type, version), block->previous (), nano::mdb_val (data.size (), data.data ()));
|
||||
block_raw_put (transaction_a, data, type, version, block->previous ());
|
||||
}
|
||||
}
|
||||
successor = hash;
|
||||
|
@ -1372,21 +1048,6 @@ void nano::mdb_store::clear (MDB_dbi db_a)
|
|||
release_assert (status == 0);
|
||||
}
|
||||
|
||||
nano::uint128_t nano::mdb_store::block_balance (nano::transaction const & transaction_a, nano::block_hash const & hash_a)
|
||||
{
|
||||
nano::block_sideband sideband;
|
||||
auto block (block_get (transaction_a, hash_a, &sideband));
|
||||
nano::uint128_t result (block_balance_calculated (block, sideband));
|
||||
return result;
|
||||
}
|
||||
|
||||
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);
|
||||
return visitor.compute_balance (hash_a);
|
||||
}
|
||||
|
||||
nano::epoch nano::mdb_store::block_version (nano::transaction const & transaction_a, nano::block_hash const & hash_a)
|
||||
{
|
||||
nano::mdb_val value;
|
||||
|
@ -1395,15 +1056,6 @@ nano::epoch nano::mdb_store::block_version (nano::transaction const & transactio
|
|||
return status == 0 ? nano::epoch::epoch_1 : nano::epoch::epoch_0;
|
||||
}
|
||||
|
||||
void nano::mdb_store::representation_add (nano::transaction const & transaction_a, nano::block_hash const & source_a, nano::uint128_t const & amount_a)
|
||||
{
|
||||
auto source_block (block_get (transaction_a, source_a));
|
||||
assert (source_block != nullptr);
|
||||
auto source_rep (source_block->representative ());
|
||||
auto source_previous (representation_get (transaction_a, source_rep));
|
||||
representation_put (transaction_a, source_rep, source_previous + amount_a);
|
||||
}
|
||||
|
||||
MDB_dbi nano::mdb_store::block_database (nano::block_type type_a, nano::epoch epoch_a)
|
||||
{
|
||||
if (type_a == nano::block_type::state)
|
||||
|
@ -1449,29 +1101,15 @@ MDB_dbi nano::mdb_store::block_database (nano::block_type type_a, nano::epoch ep
|
|||
return result;
|
||||
}
|
||||
|
||||
void nano::mdb_store::block_raw_put (nano::transaction const & transaction_a, MDB_dbi database_a, nano::block_hash const & hash_a, MDB_val value_a)
|
||||
void nano::mdb_store::block_raw_put (nano::transaction const & transaction_a, std::vector<uint8_t> const & data, nano::block_type block_type_a, nano::epoch epoch_a, nano::block_hash const & hash_a)
|
||||
{
|
||||
auto status2 (mdb_put (env.tx (transaction_a), database_a, nano::mdb_val (hash_a), &value_a, 0));
|
||||
MDB_dbi database_a = block_database (block_type_a, epoch_a);
|
||||
MDB_val value{ data.size (), (void *)data.data () };
|
||||
auto status2 (mdb_put (env.tx (transaction_a), database_a, nano::mdb_val (hash_a), &value, 0));
|
||||
release_assert (status2 == 0);
|
||||
}
|
||||
|
||||
void nano::mdb_store::block_put (nano::transaction const & transaction_a, nano::block_hash const & hash_a, nano::block const & block_a, nano::block_sideband const & sideband_a, nano::epoch epoch_a)
|
||||
{
|
||||
assert (block_a.type () == sideband_a.type);
|
||||
assert (sideband_a.successor.is_zero () || block_exists (transaction_a, sideband_a.successor));
|
||||
std::vector<uint8_t> vector;
|
||||
{
|
||||
nano::vectorstream stream (vector);
|
||||
block_a.serialize (stream);
|
||||
sideband_a.serialize (stream);
|
||||
}
|
||||
block_raw_put (transaction_a, block_database (block_a.type (), epoch_a), hash_a, { vector.size (), vector.data () });
|
||||
nano::block_predecessor_set predecessor (transaction_a, *this);
|
||||
block_a.visit (predecessor);
|
||||
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) const
|
||||
boost::optional<nano::DB_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);
|
||||
|
@ -1514,29 +1152,10 @@ boost::optional<MDB_val> nano::mdb_store::block_raw_get_by_type (nano::transacti
|
|||
}
|
||||
|
||||
release_assert (status == MDB_SUCCESS || status == MDB_NOTFOUND);
|
||||
boost::optional<MDB_val> result;
|
||||
boost::optional<DB_val> result;
|
||||
if (status == MDB_SUCCESS)
|
||||
{
|
||||
result = value;
|
||||
}
|
||||
|
||||
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) const
|
||||
{
|
||||
nano::mdb_val result;
|
||||
// Table lookups are ordered by match probability
|
||||
nano::block_type block_types[]{ nano::block_type::state, nano::block_type::send, nano::block_type::receive, nano::block_type::open, nano::block_type::change };
|
||||
for (auto current_type : block_types)
|
||||
{
|
||||
auto mdb_val (block_raw_get_by_type (transaction_a, hash_a, current_type));
|
||||
if (mdb_val.is_initialized ())
|
||||
{
|
||||
type_a = current_type;
|
||||
result = mdb_val.get ();
|
||||
break;
|
||||
}
|
||||
result = nano::DB_val (value.size (), value.data ());
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1607,103 +1226,6 @@ 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) const
|
||||
{
|
||||
return version_get (transaction_a) > 12;
|
||||
}
|
||||
|
||||
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) const
|
||||
{
|
||||
size_t result;
|
||||
if (full_sideband (transaction_a) || entry_has_sideband (entry_a, type_a))
|
||||
{
|
||||
result = entry_a.mv_size - nano::block_sideband::size (type_a);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read old successor-only sideband
|
||||
assert (entry_a.mv_size == nano::block::size (type_a) + sizeof (nano::uint256_union));
|
||||
result = entry_a.mv_size - sizeof (nano::uint256_union);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
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));
|
||||
nano::block_hash result;
|
||||
if (value.mv_size != 0)
|
||||
{
|
||||
assert (value.mv_size >= result.bytes.size ());
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.mv_data) + block_successor_offset (transaction_a, value, type), result.bytes.size ());
|
||||
auto error (nano::try_read (stream, result.bytes));
|
||||
assert (!error);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.clear ();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void nano::mdb_store::block_successor_clear (nano::transaction const & transaction_a, nano::block_hash const & hash_a)
|
||||
{
|
||||
nano::block_type type;
|
||||
auto value (block_raw_get (transaction_a, hash_a, type));
|
||||
auto version (block_version (transaction_a, hash_a));
|
||||
assert (value.mv_size != 0);
|
||||
std::vector<uint8_t> data (static_cast<uint8_t *> (value.mv_data), static_cast<uint8_t *> (value.mv_data) + value.mv_size);
|
||||
std::fill_n (data.begin () + block_successor_offset (transaction_a, value, type), sizeof (nano::uint256_union), 0);
|
||||
block_raw_put (transaction_a, block_database (type, version), hash_a, nano::mdb_val (data.size (), data.data ()));
|
||||
}
|
||||
|
||||
// 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));
|
||||
std::shared_ptr<nano::block> result;
|
||||
if (value.mv_size != 0)
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.mv_data), value.mv_size);
|
||||
result = nano::deserialize_block (stream, type);
|
||||
assert (result != nullptr);
|
||||
if (sideband_a)
|
||||
{
|
||||
sideband_a->type = type;
|
||||
if (full_sideband (transaction_a) || entry_has_sideband (value, type))
|
||||
{
|
||||
auto error (sideband_a->deserialize (stream));
|
||||
assert (!error);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reconstruct sideband data for block.
|
||||
sideband_a->account = block_account_computed (transaction_a, hash_a);
|
||||
sideband_a->balance = block_balance_computed (transaction_a, hash_a);
|
||||
sideband_a->successor = block_successor (transaction_a, hash_a);
|
||||
sideband_a->height = 0;
|
||||
sideband_a->timestamp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void nano::mdb_store::block_del (nano::transaction const & transaction_a, nano::block_hash const & hash_a)
|
||||
{
|
||||
auto status (mdb_del (env.tx (transaction_a), state_blocks_v1, nano::mdb_val (hash_a), nullptr));
|
||||
|
@ -1791,112 +1313,15 @@ bool nano::mdb_store::block_exists (nano::transaction const & transaction_a, nan
|
|||
return exists;
|
||||
}
|
||||
|
||||
bool nano::mdb_store::block_exists (nano::transaction const & tx_a, nano::block_hash const & hash_a)
|
||||
{
|
||||
// Table lookups are ordered by match probability
|
||||
// clang-format off
|
||||
return
|
||||
block_exists (tx_a, nano::block_type::state, hash_a) ||
|
||||
block_exists (tx_a, nano::block_type::send, hash_a) ||
|
||||
block_exists (tx_a, nano::block_type::receive, hash_a) ||
|
||||
block_exists (tx_a, nano::block_type::open, hash_a) ||
|
||||
block_exists (tx_a, nano::block_type::change, hash_a);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
nano::block_counts nano::mdb_store::block_count (nano::transaction const & transaction_a)
|
||||
{
|
||||
nano::block_counts result;
|
||||
MDB_stat send_stats;
|
||||
auto status1 (mdb_stat (env.tx (transaction_a), send_blocks, &send_stats));
|
||||
release_assert (status1 == 0);
|
||||
MDB_stat receive_stats;
|
||||
auto status2 (mdb_stat (env.tx (transaction_a), receive_blocks, &receive_stats));
|
||||
release_assert (status2 == 0);
|
||||
MDB_stat open_stats;
|
||||
auto status3 (mdb_stat (env.tx (transaction_a), open_blocks, &open_stats));
|
||||
release_assert (status3 == 0);
|
||||
MDB_stat change_stats;
|
||||
auto status4 (mdb_stat (env.tx (transaction_a), change_blocks, &change_stats));
|
||||
release_assert (status4 == 0);
|
||||
MDB_stat state_v0_stats;
|
||||
auto status5 (mdb_stat (env.tx (transaction_a), state_blocks_v0, &state_v0_stats));
|
||||
release_assert (status5 == 0);
|
||||
MDB_stat state_v1_stats;
|
||||
auto status6 (mdb_stat (env.tx (transaction_a), state_blocks_v1, &state_v1_stats));
|
||||
release_assert (status6 == 0);
|
||||
result.send = send_stats.ms_entries;
|
||||
result.receive = receive_stats.ms_entries;
|
||||
result.open = open_stats.ms_entries;
|
||||
result.change = change_stats.ms_entries;
|
||||
result.state_v0 = state_v0_stats.ms_entries;
|
||||
result.state_v1 = state_v1_stats.ms_entries;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool nano::mdb_store::root_exists (nano::transaction const & transaction_a, nano::uint256_union const & root_a)
|
||||
{
|
||||
return block_exists (transaction_a, root_a) || account_exists (transaction_a, root_a);
|
||||
}
|
||||
|
||||
bool nano::mdb_store::source_exists (nano::transaction const & transaction_a, nano::block_hash const & source_a)
|
||||
{
|
||||
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) const
|
||||
{
|
||||
nano::block_sideband sideband;
|
||||
auto block (block_get (transaction_a, hash_a, &sideband));
|
||||
nano::account result (block->account ());
|
||||
if (result.is_zero ())
|
||||
{
|
||||
result = sideband.account;
|
||||
}
|
||||
assert (!result.is_zero ());
|
||||
return result;
|
||||
}
|
||||
|
||||
// Return account containing hash
|
||||
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);
|
||||
auto hash (hash_a);
|
||||
while (result.is_zero ())
|
||||
{
|
||||
auto block (block_get (transaction_a, hash));
|
||||
assert (block);
|
||||
result = block->account ();
|
||||
if (result.is_zero ())
|
||||
{
|
||||
auto type (nano::block_type::invalid);
|
||||
auto value (block_raw_get (transaction_a, block->previous (), type));
|
||||
if (entry_has_sideband (value, type))
|
||||
{
|
||||
result = block_account (transaction_a, block->previous ());
|
||||
}
|
||||
else
|
||||
{
|
||||
nano::block_info block_info;
|
||||
if (!block_info_get (transaction_a, hash, block_info))
|
||||
{
|
||||
result = block_info.account;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = frontier_get (transaction_a, hash);
|
||||
if (result.is_zero ())
|
||||
{
|
||||
auto successor (block_successor (transaction_a, hash));
|
||||
assert (!successor.is_zero ());
|
||||
hash = successor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert (!result.is_zero ());
|
||||
result.send = count (transaction_a, send_blocks);
|
||||
result.receive = count (transaction_a, receive_blocks);
|
||||
result.open = count (transaction_a, open_blocks);
|
||||
result.change = count (transaction_a, change_blocks);
|
||||
result.state_v0 = count (transaction_a, state_blocks_v0);
|
||||
result.state_v1 = count (transaction_a, state_blocks_v1);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1911,12 +1336,6 @@ void nano::mdb_store::account_del (nano::transaction const & transaction_a, nano
|
|||
}
|
||||
}
|
||||
|
||||
bool nano::mdb_store::account_exists (nano::transaction const & transaction_a, nano::account const & account_a)
|
||||
{
|
||||
auto iterator (latest_begin (transaction_a, account_a));
|
||||
return iterator != latest_end () && nano::account (iterator->first) == account_a;
|
||||
}
|
||||
|
||||
bool nano::mdb_store::account_get (nano::transaction const & transaction_a, nano::account const & account_a, nano::account_info & info_a)
|
||||
{
|
||||
nano::mdb_val value;
|
||||
|
@ -1977,14 +1396,7 @@ void nano::mdb_store::frontier_del (nano::transaction const & transaction_a, nan
|
|||
|
||||
size_t nano::mdb_store::account_count (nano::transaction const & transaction_a)
|
||||
{
|
||||
MDB_stat stats1;
|
||||
auto status1 (mdb_stat (env.tx (transaction_a), accounts_v0, &stats1));
|
||||
release_assert (status1 == 0);
|
||||
MDB_stat stats2;
|
||||
auto status2 (mdb_stat (env.tx (transaction_a), accounts_v1, &stats2));
|
||||
release_assert (status2 == 0);
|
||||
auto result (stats1.ms_entries + stats2.ms_entries);
|
||||
return result;
|
||||
return count (transaction_a, { accounts_v0, accounts_v1 });
|
||||
}
|
||||
|
||||
MDB_dbi nano::mdb_store::get_account_db (nano::epoch epoch_a) const
|
||||
|
@ -2029,35 +1441,6 @@ void nano::mdb_store::account_put (nano::transaction const & transaction_a, nano
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t nano::mdb_store::cemented_count (nano::transaction const & transaction_a)
|
||||
{
|
||||
uint64_t sum = 0;
|
||||
for (auto i (latest_begin (transaction_a)), n (latest_end ()); i != n; ++i)
|
||||
{
|
||||
nano::account_info const & info (i->second);
|
||||
sum += info.confirmation_height;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
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));
|
||||
|
@ -2075,12 +1458,6 @@ void nano::mdb_store::pending_del (nano::transaction const & transaction_a, nano
|
|||
}
|
||||
}
|
||||
|
||||
bool nano::mdb_store::pending_exists (nano::transaction const & transaction_a, nano::pending_key const & key_a)
|
||||
{
|
||||
auto iterator (pending_begin (transaction_a, key_a));
|
||||
return iterator != pending_end () && nano::pending_key (iterator->first) == key_a;
|
||||
}
|
||||
|
||||
bool nano::mdb_store::pending_get (nano::transaction const & transaction_a, nano::pending_key const & key_a, nano::pending_info & pending_a)
|
||||
{
|
||||
nano::mdb_val value;
|
||||
|
@ -2224,13 +1601,6 @@ void nano::mdb_store::unchecked_put (nano::transaction const & transaction_a, na
|
|||
release_assert (status == 0);
|
||||
}
|
||||
|
||||
void nano::mdb_store::unchecked_put (nano::transaction const & transaction_a, nano::block_hash const & hash_a, std::shared_ptr<nano::block> const & block_a)
|
||||
{
|
||||
nano::unchecked_key key (hash_a, block_a->hash ());
|
||||
nano::unchecked_info info (block_a, block_a->account (), nano::seconds_since_epoch (), nano::signature_verification::unknown);
|
||||
unchecked_put (transaction_a, key, info);
|
||||
}
|
||||
|
||||
std::shared_ptr<nano::vote> nano::mdb_store::vote_get (nano::transaction const & transaction_a, nano::account const & account_a)
|
||||
{
|
||||
nano::mdb_val value;
|
||||
|
@ -2245,17 +1615,6 @@ std::shared_ptr<nano::vote> nano::mdb_store::vote_get (nano::transaction const &
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<nano::unchecked_info> nano::mdb_store::unchecked_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a)
|
||||
{
|
||||
std::vector<nano::unchecked_info> result;
|
||||
for (auto i (unchecked_begin (transaction_a, nano::unchecked_key (hash_a, 0))), n (unchecked_end ()); i != n && nano::block_hash (i->first.key ()) == hash_a; ++i)
|
||||
{
|
||||
nano::unchecked_info const & unchecked_info (i->second);
|
||||
result.push_back (unchecked_info);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
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));
|
||||
|
@ -2264,11 +1623,15 @@ void nano::mdb_store::unchecked_del (nano::transaction const & transaction_a, na
|
|||
|
||||
size_t nano::mdb_store::unchecked_count (nano::transaction const & transaction_a)
|
||||
{
|
||||
MDB_stat unchecked_stats;
|
||||
auto status (mdb_stat (env.tx (transaction_a), unchecked, &unchecked_stats));
|
||||
return count (transaction_a, unchecked);
|
||||
}
|
||||
|
||||
size_t nano::mdb_store::count (nano::transaction const & transaction_a, MDB_dbi db_a) const
|
||||
{
|
||||
MDB_stat stats;
|
||||
auto status (mdb_stat (env.tx (transaction_a), db_a, &stats));
|
||||
release_assert (status == 0);
|
||||
auto result (unchecked_stats.ms_entries);
|
||||
return result;
|
||||
return (stats.ms_entries);
|
||||
}
|
||||
|
||||
void nano::mdb_store::online_weight_put (nano::transaction const & transaction_a, uint64_t time_a, nano::amount const & amount_a)
|
||||
|
@ -2295,10 +1658,7 @@ nano::store_iterator<uint64_t, nano::amount> nano::mdb_store::online_weight_end
|
|||
|
||||
size_t nano::mdb_store::online_weight_count (nano::transaction const & transaction_a) const
|
||||
{
|
||||
MDB_stat online_weight_stats;
|
||||
auto status1 (mdb_stat (env.tx (transaction_a), online_weight, &online_weight_stats));
|
||||
release_assert (status1 == 0);
|
||||
return online_weight_stats.ms_entries;
|
||||
return count (transaction_a, online_weight);
|
||||
}
|
||||
|
||||
void nano::mdb_store::online_weight_clear (nano::transaction const & transaction_a)
|
||||
|
@ -2325,62 +1685,15 @@ void nano::mdb_store::flush (nano::transaction const & transaction_a)
|
|||
release_assert (status1 == 0);
|
||||
}
|
||||
}
|
||||
std::shared_ptr<nano::vote> nano::mdb_store::vote_current (nano::transaction const & transaction_a, nano::account const & account_a)
|
||||
{
|
||||
assert (!cache_mutex.try_lock ());
|
||||
std::shared_ptr<nano::vote> result;
|
||||
auto existing (vote_cache_l1.find (account_a));
|
||||
auto have_existing (true);
|
||||
if (existing == vote_cache_l1.end ())
|
||||
{
|
||||
existing = vote_cache_l2.find (account_a);
|
||||
if (existing == vote_cache_l2.end ())
|
||||
{
|
||||
have_existing = false;
|
||||
}
|
||||
}
|
||||
if (have_existing)
|
||||
{
|
||||
result = existing->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = vote_get (transaction_a, account_a);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<nano::vote> nano::mdb_store::vote_generate (nano::transaction const & transaction_a, nano::account const & account_a, nano::raw_key const & key_a, std::shared_ptr<nano::block> block_a)
|
||||
size_t nano::mdb_store::count (nano::transaction const & transaction_a, std::initializer_list<MDB_dbi> dbs_a) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (cache_mutex);
|
||||
auto result (vote_current (transaction_a, account_a));
|
||||
uint64_t sequence ((result ? result->sequence : 0) + 1);
|
||||
result = std::make_shared<nano::vote> (account_a, key_a, sequence, block_a);
|
||||
vote_cache_l1[account_a] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<nano::vote> nano::mdb_store::vote_generate (nano::transaction const & transaction_a, nano::account const & account_a, nano::raw_key const & key_a, std::vector<nano::block_hash> blocks_a)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (cache_mutex);
|
||||
auto result (vote_current (transaction_a, account_a));
|
||||
uint64_t sequence ((result ? result->sequence : 0) + 1);
|
||||
result = std::make_shared<nano::vote> (account_a, key_a, sequence, blocks_a);
|
||||
vote_cache_l1[account_a] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<nano::vote> nano::mdb_store::vote_max (nano::transaction const & transaction_a, std::shared_ptr<nano::vote> vote_a)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (cache_mutex);
|
||||
auto current (vote_current (transaction_a, vote_a->account));
|
||||
auto result (vote_a);
|
||||
if (current != nullptr && current->sequence > result->sequence)
|
||||
size_t total_count = 0;
|
||||
for (auto db : dbs_a)
|
||||
{
|
||||
result = current;
|
||||
total_count += count (transaction_a, db);
|
||||
}
|
||||
vote_cache_l1[vote_a->account] = result;
|
||||
return result;
|
||||
return total_count;
|
||||
}
|
||||
|
||||
nano::store_iterator<nano::account, nano::account_info> nano::mdb_store::latest_begin (nano::transaction const & transaction_a, nano::account const & account_a)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <nano/node/lmdb_txn_tracker.hpp>
|
||||
#include <nano/secure/blockstore.hpp>
|
||||
#include <nano/secure/common.hpp>
|
||||
#include <nano/secure/versioning.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
@ -18,7 +19,6 @@
|
|||
namespace nano
|
||||
{
|
||||
class mdb_env;
|
||||
class account_info_v13;
|
||||
|
||||
class mdb_txn_callbacks
|
||||
{
|
||||
|
@ -70,55 +70,7 @@ public:
|
|||
MDB_env * environment;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encapsulates MDB_val and provides uint256_union conversion of the data.
|
||||
*/
|
||||
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 &);
|
||||
mdb_val (nano::pending_key const &);
|
||||
mdb_val (nano::unchecked_info const &);
|
||||
mdb_val (size_t, void *);
|
||||
mdb_val (nano::uint128_union const &);
|
||||
mdb_val (nano::uint256_union const &);
|
||||
mdb_val (nano::endpoint_key const &);
|
||||
mdb_val (std::shared_ptr<nano::block> const &);
|
||||
mdb_val (std::shared_ptr<nano::vote> const &);
|
||||
mdb_val (uint64_t);
|
||||
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;
|
||||
explicit operator nano::unchecked_info () const;
|
||||
explicit operator nano::uint128_union () const;
|
||||
explicit operator nano::uint256_union () const;
|
||||
explicit operator std::array<char, 64> () const;
|
||||
explicit operator nano::endpoint_key () const;
|
||||
explicit operator nano::no_value () const;
|
||||
explicit operator std::shared_ptr<nano::block> () const;
|
||||
explicit operator std::shared_ptr<nano::send_block> () const;
|
||||
explicit operator std::shared_ptr<nano::receive_block> () const;
|
||||
explicit operator std::shared_ptr<nano::open_block> () const;
|
||||
explicit operator std::shared_ptr<nano::change_block> () const;
|
||||
explicit operator std::shared_ptr<nano::state_block> () const;
|
||||
explicit operator std::shared_ptr<nano::vote> () const;
|
||||
explicit operator uint64_t () const;
|
||||
operator MDB_val * () const;
|
||||
operator MDB_val const & () const;
|
||||
MDB_val value;
|
||||
std::shared_ptr<std::vector<uint8_t>> buffer;
|
||||
nano::epoch epoch{ nano::epoch::unspecified };
|
||||
};
|
||||
class block_store;
|
||||
using mdb_val = db_val<MDB_val>;
|
||||
|
||||
template <typename T, typename U>
|
||||
class mdb_iterator : public store_iterator_impl<T, U>
|
||||
|
@ -177,28 +129,20 @@ class logging_mt;
|
|||
/**
|
||||
* mdb implementation of the block store
|
||||
*/
|
||||
class mdb_store : public block_store
|
||||
class mdb_store : public block_store_partial<MDB_val>
|
||||
{
|
||||
friend class nano::block_predecessor_set;
|
||||
|
||||
public:
|
||||
using block_store_partial::block_exists;
|
||||
using block_store_partial::unchecked_put;
|
||||
|
||||
mdb_store (bool &, nano::logger_mt &, boost::filesystem::path const &, nano::txn_tracking_config const & txn_tracking_config_a = nano::txn_tracking_config{}, std::chrono::milliseconds block_processor_batch_max_time_a = std::chrono::milliseconds (5000), int lmdb_max_dbs = 128, bool drop_unchecked = false, size_t batch_size = 512);
|
||||
nano::write_transaction tx_begin_write () override;
|
||||
nano::read_transaction tx_begin_read () 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;
|
||||
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) 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;
|
||||
bool block_exists (nano::transaction const &, nano::block_type, nano::block_hash const &) override;
|
||||
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 &) 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 &) const override;
|
||||
|
@ -207,11 +151,7 @@ public:
|
|||
void account_put (nano::transaction const &, nano::account const &, nano::account_info const &) override;
|
||||
bool account_get (nano::transaction const &, nano::account const &, nano::account_info &) override;
|
||||
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;
|
||||
uint64_t cemented_count (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;
|
||||
|
@ -225,7 +165,6 @@ public:
|
|||
void pending_put (nano::transaction const &, nano::pending_key const &, nano::pending_info const &) override;
|
||||
void pending_del (nano::transaction const &, nano::pending_key const &) override;
|
||||
bool pending_get (nano::transaction const &, nano::pending_key const &, nano::pending_info &) override;
|
||||
bool pending_exists (nano::transaction const &, nano::pending_key const &) override;
|
||||
nano::store_iterator<nano::pending_key, nano::pending_info> pending_v0_begin (nano::transaction const &, nano::pending_key const &) override;
|
||||
nano::store_iterator<nano::pending_key, nano::pending_info> pending_v0_begin (nano::transaction const &) override;
|
||||
nano::store_iterator<nano::pending_key, nano::pending_info> pending_v0_end () override;
|
||||
|
@ -237,19 +176,15 @@ public:
|
|||
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 &) 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;
|
||||
|
||||
nano::uint128_t representation_get (nano::transaction const &, nano::account const &) override;
|
||||
void representation_put (nano::transaction const &, nano::account const &, nano::uint128_t const &) override;
|
||||
void representation_add (nano::transaction const &, nano::account const &, nano::uint128_t const &) override;
|
||||
nano::store_iterator<nano::account, nano::uint128_union> representation_begin (nano::transaction const &) override;
|
||||
nano::store_iterator<nano::account, nano::uint128_union> representation_end () override;
|
||||
|
||||
void unchecked_clear (nano::transaction const &) override;
|
||||
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;
|
||||
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;
|
||||
|
@ -258,13 +193,6 @@ public:
|
|||
|
||||
// Return latest vote for an account from store
|
||||
std::shared_ptr<nano::vote> vote_get (nano::transaction const &, nano::account const &) override;
|
||||
// Populate vote with the next sequence number
|
||||
std::shared_ptr<nano::vote> vote_generate (nano::transaction const &, nano::account const &, nano::raw_key const &, std::shared_ptr<nano::block>) override;
|
||||
std::shared_ptr<nano::vote> vote_generate (nano::transaction const &, nano::account const &, nano::raw_key const &, std::vector<nano::block_hash>) override;
|
||||
// Return either vote or the stored vote with a higher sequence number
|
||||
std::shared_ptr<nano::vote> vote_max (nano::transaction const &, std::shared_ptr<nano::vote>) override;
|
||||
// Return latest vote for an account considering the vote cache
|
||||
std::shared_ptr<nano::vote> vote_current (nano::transaction const &, nano::account const &) override;
|
||||
void flush (nano::transaction const &) override;
|
||||
nano::store_iterator<nano::account, std::shared_ptr<nano::vote>> vote_begin (nano::transaction const &) override;
|
||||
nano::store_iterator<nano::account, std::shared_ptr<nano::vote>> vote_end () override;
|
||||
|
@ -276,10 +204,6 @@ public:
|
|||
size_t online_weight_count (nano::transaction const &) const override;
|
||||
void online_weight_clear (nano::transaction const &) override;
|
||||
|
||||
std::mutex cache_mutex;
|
||||
std::unordered_map<nano::account, std::shared_ptr<nano::vote>> vote_cache_l1;
|
||||
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 &) const override;
|
||||
|
||||
|
@ -292,11 +216,7 @@ 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;
|
||||
|
||||
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;
|
||||
void serialize_mdb_tracker (boost::property_tree::ptree &, std::chrono::milliseconds, std::chrono::milliseconds) override;
|
||||
|
||||
nano::logger_mt & logger;
|
||||
|
@ -412,16 +332,11 @@ public:
|
|||
MDB_dbi peers{ 0 };
|
||||
|
||||
private:
|
||||
nano::network_params network_params;
|
||||
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 &) 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);
|
||||
boost::optional<DB_val> block_raw_get_by_type (nano::transaction const &, nano::block_hash const &, nano::block_type &) const override;
|
||||
void block_raw_put (nano::transaction const & transaction_a, std::vector<uint8_t> const & data, nano::block_type block_type_a, nano::epoch epoch_a, nano::block_hash const & hash_a) override;
|
||||
void clear (MDB_dbi);
|
||||
bool do_upgrades (nano::write_transaction &, size_t);
|
||||
void upgrade_v1_to_v2 (nano::transaction const &);
|
||||
|
@ -443,6 +358,9 @@ private:
|
|||
nano::mdb_txn_callbacks create_txn_callbacks ();
|
||||
bool txn_tracking_enabled;
|
||||
static int constexpr version{ 14 };
|
||||
|
||||
size_t count (nano::transaction const &, MDB_dbi) const;
|
||||
size_t count (nano::transaction const &, std::initializer_list<MDB_dbi>) const;
|
||||
};
|
||||
class wallet_value
|
||||
{
|
||||
|
|
|
@ -365,30 +365,6 @@ void nano::representative_visitor::state_block (nano::state_block const & block_
|
|||
result = block_a.hash ();
|
||||
}
|
||||
|
||||
nano::uint128_t nano::block_store::block_balance_calculated (std::shared_ptr<nano::block> block_a, nano::block_sideband const & sideband_a) const
|
||||
{
|
||||
nano::uint128_t result;
|
||||
switch (block_a->type ())
|
||||
{
|
||||
case nano::block_type::open:
|
||||
case nano::block_type::receive:
|
||||
case nano::block_type::change:
|
||||
result = sideband_a.balance.number ();
|
||||
break;
|
||||
case nano::block_type::send:
|
||||
result = boost::polymorphic_downcast<nano::send_block *> (block_a.get ())->hashables.balance.number ();
|
||||
break;
|
||||
case nano::block_type::state:
|
||||
result = boost::polymorphic_downcast<nano::state_block *> (block_a.get ())->hashables.balance.number ();
|
||||
break;
|
||||
case nano::block_type::invalid:
|
||||
case nano::block_type::not_a_block:
|
||||
release_assert (false);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::read_transaction::read_transaction (std::unique_ptr<nano::read_transaction_impl> read_transaction_impl) :
|
||||
impl (std::move (read_transaction_impl))
|
||||
{
|
||||
|
|
|
@ -1,12 +1,304 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/lib/config.hpp>
|
||||
#include <nano/lib/memory.hpp>
|
||||
#include <nano/secure/common.hpp>
|
||||
#include <nano/secure/versioning.hpp>
|
||||
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/polymorphic_cast.hpp>
|
||||
|
||||
#include <stack>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
// Generic container to be used when templated db types cannot
|
||||
class DB_val
|
||||
{
|
||||
public:
|
||||
DB_val () = default;
|
||||
DB_val (size_t size_a, void * data_a) :
|
||||
size (size_a),
|
||||
data (data_a)
|
||||
{
|
||||
}
|
||||
|
||||
size_t size;
|
||||
void * data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encapsulates database specific container and provides uint256_union conversion of the data.
|
||||
*/
|
||||
template <typename Val>
|
||||
class db_val
|
||||
{
|
||||
public:
|
||||
db_val (nano::epoch epoch_a = nano::epoch::unspecified) :
|
||||
value ({ 0, nullptr }),
|
||||
epoch (epoch_a)
|
||||
{
|
||||
}
|
||||
|
||||
db_val (Val const & value_a, nano::epoch epoch_a = nano::epoch::unspecified) :
|
||||
value (value_a),
|
||||
epoch (epoch_a)
|
||||
{
|
||||
}
|
||||
|
||||
db_val (DB_val const & value_a, nano::epoch epoch_a = nano::epoch::unspecified);
|
||||
|
||||
db_val (size_t size_a, void * data_a) :
|
||||
value ({ size_a, data_a })
|
||||
{
|
||||
}
|
||||
|
||||
db_val (nano::uint128_union const & val_a) :
|
||||
db_val (sizeof (val_a), const_cast<nano::uint128_union *> (&val_a))
|
||||
{
|
||||
}
|
||||
|
||||
db_val (nano::uint256_union const & val_a) :
|
||||
db_val (sizeof (val_a), const_cast<nano::uint256_union *> (&val_a))
|
||||
{
|
||||
}
|
||||
|
||||
db_val (nano::account_info const & val_a) :
|
||||
db_val (val_a.db_size (), const_cast<nano::account_info *> (&val_a))
|
||||
{
|
||||
}
|
||||
|
||||
db_val (nano::account_info_v13 const & val_a) :
|
||||
db_val (val_a.db_size (), const_cast<nano::account_info_v13 *> (&val_a))
|
||||
{
|
||||
}
|
||||
|
||||
db_val (nano::pending_info const & val_a) :
|
||||
db_val (sizeof (val_a.source) + sizeof (val_a.amount), const_cast<nano::pending_info *> (&val_a))
|
||||
{
|
||||
static_assert (std::is_standard_layout<nano::pending_info>::value, "Standard layout is required");
|
||||
}
|
||||
|
||||
db_val (nano::pending_key const & val_a) :
|
||||
db_val (sizeof (val_a), const_cast<nano::pending_key *> (&val_a))
|
||||
{
|
||||
static_assert (std::is_standard_layout<nano::pending_key>::value, "Standard layout is required");
|
||||
}
|
||||
|
||||
db_val (nano::unchecked_info const & val_a) :
|
||||
buffer (std::make_shared<std::vector<uint8_t>> ())
|
||||
{
|
||||
{
|
||||
nano::vectorstream stream (*buffer);
|
||||
val_a.serialize (stream);
|
||||
}
|
||||
value = { buffer->size (), const_cast<uint8_t *> (buffer->data ()) };
|
||||
}
|
||||
|
||||
db_val (nano::block_info const & val_a) :
|
||||
db_val (sizeof (val_a), const_cast<nano::block_info *> (&val_a))
|
||||
{
|
||||
static_assert (std::is_standard_layout<nano::block_info>::value, "Standard layout is required");
|
||||
}
|
||||
|
||||
db_val (nano::endpoint_key const & val_a) :
|
||||
db_val (sizeof (val_a), const_cast<nano::endpoint_key *> (&val_a))
|
||||
{
|
||||
static_assert (std::is_standard_layout<nano::endpoint_key>::value, "Standard layout is required");
|
||||
}
|
||||
|
||||
db_val (std::shared_ptr<nano::block> const & val_a) :
|
||||
buffer (std::make_shared<std::vector<uint8_t>> ())
|
||||
{
|
||||
{
|
||||
nano::vectorstream stream (*buffer);
|
||||
nano::serialize_block (stream, *val_a);
|
||||
}
|
||||
value = { buffer->size (), const_cast<uint8_t *> (buffer->data ()) };
|
||||
}
|
||||
|
||||
db_val (uint64_t val_a) :
|
||||
buffer (std::make_shared<std::vector<uint8_t>> ())
|
||||
{
|
||||
{
|
||||
boost::endian::native_to_big_inplace (val_a);
|
||||
nano::vectorstream stream (*buffer);
|
||||
nano::write (stream, val_a);
|
||||
}
|
||||
value = { buffer->size (), const_cast<uint8_t *> (buffer->data ()) };
|
||||
}
|
||||
|
||||
explicit operator nano::account_info () const
|
||||
{
|
||||
nano::account_info result;
|
||||
result.epoch = epoch;
|
||||
assert (size () == result.db_size ());
|
||||
std::copy (reinterpret_cast<uint8_t const *> (data ()), reinterpret_cast<uint8_t const *> (data ()) + result.db_size (), reinterpret_cast<uint8_t *> (&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit operator nano::account_info_v13 () const
|
||||
{
|
||||
nano::account_info_v13 result;
|
||||
result.epoch = epoch;
|
||||
assert (size () == result.db_size ());
|
||||
std::copy (reinterpret_cast<uint8_t const *> (data ()), reinterpret_cast<uint8_t const *> (data ()) + result.db_size (), reinterpret_cast<uint8_t *> (&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit operator nano::block_info () const
|
||||
{
|
||||
nano::block_info result;
|
||||
assert (size () == sizeof (result));
|
||||
static_assert (sizeof (nano::block_info::account) + sizeof (nano::block_info::balance) == sizeof (result), "Packed class");
|
||||
std::copy (reinterpret_cast<uint8_t const *> (data ()), reinterpret_cast<uint8_t const *> (data ()) + sizeof (result), reinterpret_cast<uint8_t *> (&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit operator nano::pending_info () const
|
||||
{
|
||||
nano::pending_info result;
|
||||
result.epoch = epoch;
|
||||
std::copy (reinterpret_cast<uint8_t const *> (data ()), reinterpret_cast<uint8_t const *> (data ()) + sizeof (nano::pending_info::source) + sizeof (nano::pending_info::amount), reinterpret_cast<uint8_t *> (&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit operator nano::pending_key () const
|
||||
{
|
||||
nano::pending_key result;
|
||||
assert (size () == sizeof (result));
|
||||
static_assert (sizeof (nano::pending_key::account) + sizeof (nano::pending_key::hash) == sizeof (result), "Packed class");
|
||||
std::copy (reinterpret_cast<uint8_t const *> (data ()), reinterpret_cast<uint8_t const *> (data ()) + sizeof (result), reinterpret_cast<uint8_t *> (&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit operator nano::unchecked_info () const
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (data ()), size ());
|
||||
nano::unchecked_info result;
|
||||
bool error (result.deserialize (stream));
|
||||
assert (!error);
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit operator nano::uint128_union () const
|
||||
{
|
||||
nano::uint128_union result;
|
||||
assert (size () == sizeof (result));
|
||||
std::copy (reinterpret_cast<uint8_t const *> (data ()), reinterpret_cast<uint8_t const *> (data ()) + sizeof (result), result.bytes.data ());
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit operator nano::uint256_union () const
|
||||
{
|
||||
nano::uint256_union result;
|
||||
assert (size () == sizeof (result));
|
||||
std::copy (reinterpret_cast<uint8_t const *> (data ()), reinterpret_cast<uint8_t const *> (data ()) + sizeof (result), result.bytes.data ());
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit operator std::array<char, 64> () const
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (data ()), size ());
|
||||
std::array<char, 64> result;
|
||||
auto error = nano::try_read (stream, result);
|
||||
assert (!error);
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit operator nano::endpoint_key () const
|
||||
{
|
||||
nano::endpoint_key result;
|
||||
std::copy (reinterpret_cast<uint8_t const *> (data ()), reinterpret_cast<uint8_t const *> (data ()) + sizeof (result), reinterpret_cast<uint8_t *> (&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit operator nano::no_value () const
|
||||
{
|
||||
return no_value::dummy;
|
||||
}
|
||||
|
||||
explicit operator std::shared_ptr<nano::block> () const
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (data ()), size ());
|
||||
std::shared_ptr<nano::block> result (nano::deserialize_block (stream));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Block>
|
||||
std::shared_ptr<Block> convert_to_block () const
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (data ()), size ());
|
||||
auto error (false);
|
||||
auto result (std::make_shared<Block> (error, stream));
|
||||
assert (!error);
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit operator std::shared_ptr<nano::send_block> () const
|
||||
{
|
||||
return convert_to_block<nano::send_block> ();
|
||||
}
|
||||
|
||||
explicit operator std::shared_ptr<nano::receive_block> () const
|
||||
{
|
||||
return convert_to_block<nano::receive_block> ();
|
||||
}
|
||||
|
||||
explicit operator std::shared_ptr<nano::open_block> () const
|
||||
{
|
||||
return convert_to_block<nano::open_block> ();
|
||||
}
|
||||
|
||||
explicit operator std::shared_ptr<nano::change_block> () const
|
||||
{
|
||||
return convert_to_block<nano::change_block> ();
|
||||
}
|
||||
|
||||
explicit operator std::shared_ptr<nano::state_block> () const
|
||||
{
|
||||
return convert_to_block<nano::state_block> ();
|
||||
}
|
||||
|
||||
explicit operator std::shared_ptr<nano::vote> () const
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (data ()), size ());
|
||||
auto error (false);
|
||||
auto result (nano::make_shared<nano::vote> (error, stream));
|
||||
assert (!error);
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit operator uint64_t () const
|
||||
{
|
||||
uint64_t result;
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (data ()), size ());
|
||||
auto error (nano::try_read (stream, result));
|
||||
assert (!error);
|
||||
boost::endian::big_to_native_inplace (result);
|
||||
return result;
|
||||
}
|
||||
|
||||
operator Val * () const
|
||||
{
|
||||
// Allow passing a temporary to a non-c++ function which doesn't have constness
|
||||
return const_cast<Val *> (&value);
|
||||
}
|
||||
|
||||
operator Val const & () const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/** Must be specialized in the sub-class */
|
||||
void * data () const;
|
||||
size_t size () const;
|
||||
|
||||
Val value;
|
||||
std::shared_ptr<std::vector<uint8_t>> buffer;
|
||||
nano::epoch epoch{ nano::epoch::unspecified };
|
||||
};
|
||||
|
||||
class block_sideband final
|
||||
{
|
||||
public:
|
||||
|
@ -186,8 +478,6 @@ private:
|
|||
std::unique_ptr<nano::store_iterator_impl<T, U>> impl;
|
||||
};
|
||||
|
||||
class block_predecessor_set;
|
||||
|
||||
class transaction_impl
|
||||
{
|
||||
public:
|
||||
|
@ -308,7 +598,7 @@ public:
|
|||
|
||||
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;
|
||||
nano::uint128_t block_balance_calculated (std::shared_ptr<nano::block>, nano::block_sideband const &) const;
|
||||
virtual nano::uint128_t block_balance_calculated (std::shared_ptr<nano::block>, nano::block_sideband const &) const = 0;
|
||||
virtual nano::epoch block_version (nano::transaction const &, nano::block_hash const &) = 0;
|
||||
|
||||
virtual nano::uint128_t representation_get (nano::transaction const &, nano::account const &) = 0;
|
||||
|
@ -367,4 +657,472 @@ public:
|
|||
/** Start read-only transaction */
|
||||
virtual nano::read_transaction tx_begin_read () = 0;
|
||||
};
|
||||
|
||||
template <typename Val>
|
||||
class block_predecessor_set;
|
||||
|
||||
/** This base class implements the block_store interface functions which have DB agnostic functionality */
|
||||
template <class Val>
|
||||
class block_store_partial : public block_store
|
||||
{
|
||||
public:
|
||||
using block_store::block_exists;
|
||||
using block_store::unchecked_put;
|
||||
|
||||
friend class nano::block_predecessor_set<Val>;
|
||||
|
||||
std::mutex cache_mutex;
|
||||
|
||||
/**
|
||||
* 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 initialize (nano::transaction const & transaction_a, nano::genesis const & genesis_a) override
|
||||
{
|
||||
auto hash_l (genesis_a.hash ());
|
||||
assert (latest_v0_begin (transaction_a) == latest_v0_end ());
|
||||
assert (latest_v1_begin (transaction_a) == latest_v1_end ());
|
||||
nano::block_sideband sideband (nano::block_type::open, network_params.ledger.genesis_account, 0, network_params.ledger.genesis_amount, 1, nano::seconds_since_epoch ());
|
||||
block_put (transaction_a, hash_l, *genesis_a.open, sideband);
|
||||
account_put (transaction_a, network_params.ledger.genesis_account, { hash_l, genesis_a.open->hash (), genesis_a.open->hash (), std::numeric_limits<nano::uint128_t>::max (), nano::seconds_since_epoch (), 1, 1, nano::epoch::epoch_0 });
|
||||
representation_put (transaction_a, network_params.ledger.genesis_account, std::numeric_limits<nano::uint128_t>::max ());
|
||||
frontier_put (transaction_a, hash_l, network_params.ledger.genesis_account);
|
||||
}
|
||||
|
||||
nano::uint128_t block_balance (nano::transaction const & transaction_a, nano::block_hash const & hash_a) override
|
||||
{
|
||||
nano::block_sideband sideband;
|
||||
auto block (block_get (transaction_a, hash_a, &sideband));
|
||||
nano::uint128_t result (block_balance_calculated (block, sideband));
|
||||
return result;
|
||||
}
|
||||
|
||||
void representation_add (nano::transaction const & transaction_a, nano::block_hash const & source_a, nano::uint128_t const & amount_a) override
|
||||
{
|
||||
auto source_block (block_get (transaction_a, source_a));
|
||||
assert (source_block != nullptr);
|
||||
auto source_rep (source_block->representative ());
|
||||
auto source_previous (representation_get (transaction_a, source_rep));
|
||||
representation_put (transaction_a, source_rep, source_previous + amount_a);
|
||||
}
|
||||
|
||||
bool account_exists (nano::transaction const & transaction_a, nano::account const & account_a) override
|
||||
{
|
||||
auto iterator (latest_begin (transaction_a, account_a));
|
||||
return iterator != latest_end () && nano::account (iterator->first) == account_a;
|
||||
}
|
||||
|
||||
void confirmation_height_clear (nano::transaction const & transaction_a, nano::account const & account, nano::account_info const & account_info) override
|
||||
{
|
||||
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 confirmation_height_clear (nano::transaction const & transaction_a) override
|
||||
{
|
||||
for (auto i (latest_begin (transaction_a)), n (latest_end ()); i != n; ++i)
|
||||
{
|
||||
confirmation_height_clear (transaction_a, i->first, i->second);
|
||||
}
|
||||
}
|
||||
|
||||
bool pending_exists (nano::transaction const & transaction_a, nano::pending_key const & key_a) override
|
||||
{
|
||||
auto iterator (pending_begin (transaction_a, key_a));
|
||||
return iterator != pending_end () && nano::pending_key (iterator->first) == key_a;
|
||||
}
|
||||
|
||||
std::vector<nano::unchecked_info> unchecked_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a) override
|
||||
{
|
||||
std::vector<nano::unchecked_info> result;
|
||||
for (auto i (unchecked_begin (transaction_a, nano::unchecked_key (hash_a, 0))), n (unchecked_end ()); i != n && nano::block_hash (i->first.key ()) == hash_a; ++i)
|
||||
{
|
||||
nano::unchecked_info const & unchecked_info (i->second);
|
||||
result.push_back (unchecked_info);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void block_put (nano::transaction const & transaction_a, nano::block_hash const & hash_a, nano::block const & block_a, nano::block_sideband const & sideband_a, nano::epoch epoch_a = nano::epoch::epoch_0) override
|
||||
{
|
||||
assert (block_a.type () == sideband_a.type);
|
||||
assert (sideband_a.successor.is_zero () || block_exists (transaction_a, sideband_a.successor));
|
||||
std::vector<uint8_t> vector;
|
||||
{
|
||||
nano::vectorstream stream (vector);
|
||||
block_a.serialize (stream);
|
||||
sideband_a.serialize (stream);
|
||||
}
|
||||
block_raw_put (transaction_a, vector, block_a.type (), epoch_a, hash_a);
|
||||
nano::block_predecessor_set<Val> predecessor (transaction_a, *this);
|
||||
block_a.visit (predecessor);
|
||||
assert (block_a.previous ().is_zero () || block_successor (transaction_a, block_a.previous ()) == hash_a);
|
||||
}
|
||||
|
||||
// Converts a block hash to a block height
|
||||
uint64_t block_account_height (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const override
|
||||
{
|
||||
nano::block_sideband sideband;
|
||||
auto block = block_get (transaction_a, hash_a, &sideband);
|
||||
assert (block != nullptr);
|
||||
return sideband.height;
|
||||
}
|
||||
|
||||
std::shared_ptr<nano::block> block_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a, nano::block_sideband * sideband_a = nullptr) const override
|
||||
{
|
||||
nano::block_type type;
|
||||
auto value (block_raw_get (transaction_a, hash_a, type));
|
||||
std::shared_ptr<nano::block> result;
|
||||
if (value.size () != 0)
|
||||
{
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.data ()), value.size ());
|
||||
result = nano::deserialize_block (stream, type);
|
||||
assert (result != nullptr);
|
||||
if (sideband_a)
|
||||
{
|
||||
sideband_a->type = type;
|
||||
if (full_sideband (transaction_a) || entry_has_sideband (value.size (), type))
|
||||
{
|
||||
auto error (sideband_a->deserialize (stream));
|
||||
assert (!error);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reconstruct sideband data for block.
|
||||
sideband_a->account = block_account_computed (transaction_a, hash_a);
|
||||
sideband_a->balance = block_balance_computed (transaction_a, hash_a);
|
||||
sideband_a->successor = block_successor (transaction_a, hash_a);
|
||||
sideband_a->height = 0;
|
||||
sideband_a->timestamp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool block_exists (nano::transaction const & tx_a, nano::block_hash const & hash_a) override
|
||||
{
|
||||
// Table lookups are ordered by match probability
|
||||
// clang-format off
|
||||
return
|
||||
block_exists (tx_a, nano::block_type::state, hash_a) ||
|
||||
block_exists (tx_a, nano::block_type::send, hash_a) ||
|
||||
block_exists (tx_a, nano::block_type::receive, hash_a) ||
|
||||
block_exists (tx_a, nano::block_type::open, hash_a) ||
|
||||
block_exists (tx_a, nano::block_type::change, hash_a);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
bool root_exists (nano::transaction const & transaction_a, nano::uint256_union const & root_a) override
|
||||
{
|
||||
return block_exists (transaction_a, root_a) || account_exists (transaction_a, root_a);
|
||||
}
|
||||
|
||||
bool source_exists (nano::transaction const & transaction_a, nano::block_hash const & source_a) override
|
||||
{
|
||||
return block_exists (transaction_a, nano::block_type::state, source_a) || block_exists (transaction_a, nano::block_type::send, source_a);
|
||||
}
|
||||
|
||||
nano::account block_account (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const override
|
||||
{
|
||||
nano::block_sideband sideband;
|
||||
auto block (block_get (transaction_a, hash_a, &sideband));
|
||||
nano::account result (block->account ());
|
||||
if (result.is_zero ())
|
||||
{
|
||||
result = sideband.account;
|
||||
}
|
||||
assert (!result.is_zero ());
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::uint128_t block_balance_calculated (std::shared_ptr<nano::block> block_a, nano::block_sideband const & sideband_a) const override
|
||||
{
|
||||
nano::uint128_t result;
|
||||
switch (block_a->type ())
|
||||
{
|
||||
case nano::block_type::open:
|
||||
case nano::block_type::receive:
|
||||
case nano::block_type::change:
|
||||
result = sideband_a.balance.number ();
|
||||
break;
|
||||
case nano::block_type::send:
|
||||
result = boost::polymorphic_downcast<nano::send_block *> (block_a.get ())->hashables.balance.number ();
|
||||
break;
|
||||
case nano::block_type::state:
|
||||
result = boost::polymorphic_downcast<nano::state_block *> (block_a.get ())->hashables.balance.number ();
|
||||
break;
|
||||
case nano::block_type::invalid:
|
||||
case nano::block_type::not_a_block:
|
||||
release_assert (false);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::block_hash block_successor (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const override
|
||||
{
|
||||
nano::block_type type;
|
||||
auto value (block_raw_get (transaction_a, hash_a, type));
|
||||
nano::block_hash result;
|
||||
if (value.size () != 0)
|
||||
{
|
||||
assert (value.size () >= result.bytes.size ());
|
||||
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.data ()) + block_successor_offset (transaction_a, value.size (), type), result.bytes.size ());
|
||||
auto error (nano::try_read (stream, result.bytes));
|
||||
assert (!error);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.clear ();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool full_sideband (nano::transaction const & transaction_a) const
|
||||
{
|
||||
return version_get (transaction_a) > 12;
|
||||
}
|
||||
|
||||
void block_successor_clear (nano::transaction const & transaction_a, nano::block_hash const & hash_a) override
|
||||
{
|
||||
nano::block_type type;
|
||||
auto value (block_raw_get (transaction_a, hash_a, type));
|
||||
auto version (block_version (transaction_a, hash_a));
|
||||
assert (value.size () != 0);
|
||||
std::vector<uint8_t> data (static_cast<uint8_t *> (value.data ()), static_cast<uint8_t *> (value.data ()) + value.size ());
|
||||
std::fill_n (data.begin () + block_successor_offset (transaction_a, value.size (), type), sizeof (nano::uint256_union), 0);
|
||||
block_raw_put (transaction_a, data, type, version, hash_a);
|
||||
}
|
||||
|
||||
uint64_t cemented_count (nano::transaction const & transaction_a) override
|
||||
{
|
||||
uint64_t sum = 0;
|
||||
for (auto i (latest_begin (transaction_a)), n (latest_end ()); i != n; ++i)
|
||||
{
|
||||
nano::account_info const & info (i->second);
|
||||
sum += info.confirmation_height;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void unchecked_put (nano::transaction const & transaction_a, nano::block_hash const & hash_a, std::shared_ptr<nano::block> const & block_a) override
|
||||
{
|
||||
nano::unchecked_key key (hash_a, block_a->hash ());
|
||||
nano::unchecked_info info (block_a, block_a->account (), nano::seconds_since_epoch (), nano::signature_verification::unknown);
|
||||
unchecked_put (transaction_a, key, info);
|
||||
}
|
||||
|
||||
std::shared_ptr<nano::vote> vote_current (nano::transaction const & transaction_a, nano::account const & account_a) override
|
||||
{
|
||||
assert (!cache_mutex.try_lock ());
|
||||
std::shared_ptr<nano::vote> result;
|
||||
auto existing (vote_cache_l1.find (account_a));
|
||||
auto have_existing (true);
|
||||
if (existing == vote_cache_l1.end ())
|
||||
{
|
||||
existing = vote_cache_l2.find (account_a);
|
||||
if (existing == vote_cache_l2.end ())
|
||||
{
|
||||
have_existing = false;
|
||||
}
|
||||
}
|
||||
if (have_existing)
|
||||
{
|
||||
result = existing->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = vote_get (transaction_a, account_a);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<nano::vote> vote_generate (nano::transaction const & transaction_a, nano::account const & account_a, nano::raw_key const & key_a, std::shared_ptr<nano::block> block_a) override
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (cache_mutex);
|
||||
auto result (vote_current (transaction_a, account_a));
|
||||
uint64_t sequence ((result ? result->sequence : 0) + 1);
|
||||
result = std::make_shared<nano::vote> (account_a, key_a, sequence, block_a);
|
||||
vote_cache_l1[account_a] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<nano::vote> vote_generate (nano::transaction const & transaction_a, nano::account const & account_a, nano::raw_key const & key_a, std::vector<nano::block_hash> blocks_a) override
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (cache_mutex);
|
||||
auto result (vote_current (transaction_a, account_a));
|
||||
uint64_t sequence ((result ? result->sequence : 0) + 1);
|
||||
result = std::make_shared<nano::vote> (account_a, key_a, sequence, blocks_a);
|
||||
vote_cache_l1[account_a] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<nano::vote> vote_max (nano::transaction const & transaction_a, std::shared_ptr<nano::vote> vote_a) override
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (cache_mutex);
|
||||
auto current (vote_current (transaction_a, vote_a->account));
|
||||
auto result (vote_a);
|
||||
if (current != nullptr && current->sequence > result->sequence)
|
||||
{
|
||||
result = current;
|
||||
}
|
||||
vote_cache_l1[vote_a->account] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void block_raw_put (nano::transaction const & transaction_a, std::vector<uint8_t> const & data, nano::block_type block_type_a, nano::epoch epoch_a, nano::block_hash const & hash_a) = 0;
|
||||
|
||||
protected:
|
||||
nano::network_params network_params;
|
||||
std::unordered_map<nano::account, std::shared_ptr<nano::vote>> vote_cache_l1;
|
||||
std::unordered_map<nano::account, std::shared_ptr<nano::vote>> vote_cache_l2;
|
||||
|
||||
bool entry_has_sideband (size_t entry_size_a, nano::block_type type_a) const
|
||||
{
|
||||
return entry_size_a == nano::block::size (type_a) + nano::block_sideband::size (type_a);
|
||||
}
|
||||
|
||||
nano::db_val<Val> block_raw_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a, nano::block_type & type_a) const
|
||||
{
|
||||
nano::db_val<Val> result;
|
||||
// Table lookups are ordered by match probability
|
||||
nano::block_type block_types[]{ nano::block_type::state, nano::block_type::send, nano::block_type::receive, nano::block_type::open, nano::block_type::change };
|
||||
for (auto current_type : block_types)
|
||||
{
|
||||
auto db_val (block_raw_get_by_type (transaction_a, hash_a, current_type));
|
||||
if (db_val.is_initialized ())
|
||||
{
|
||||
type_a = current_type;
|
||||
result = db_val.get ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Return account containing hash
|
||||
nano::account block_account_computed (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const
|
||||
{
|
||||
assert (!full_sideband (transaction_a));
|
||||
nano::account result (0);
|
||||
auto hash (hash_a);
|
||||
while (result.is_zero ())
|
||||
{
|
||||
auto block (block_get (transaction_a, hash));
|
||||
assert (block);
|
||||
result = block->account ();
|
||||
if (result.is_zero ())
|
||||
{
|
||||
auto type (nano::block_type::invalid);
|
||||
auto value (block_raw_get (transaction_a, block->previous (), type));
|
||||
if (entry_has_sideband (value.size (), type))
|
||||
{
|
||||
result = block_account (transaction_a, block->previous ());
|
||||
}
|
||||
else
|
||||
{
|
||||
nano::block_info block_info;
|
||||
if (!block_info_get (transaction_a, hash, block_info))
|
||||
{
|
||||
result = block_info.account;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = frontier_get (transaction_a, hash);
|
||||
if (result.is_zero ())
|
||||
{
|
||||
auto successor (block_successor (transaction_a, hash));
|
||||
assert (!successor.is_zero ());
|
||||
hash = successor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert (!result.is_zero ());
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::uint128_t 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);
|
||||
return visitor.compute_balance (hash_a);
|
||||
}
|
||||
|
||||
size_t block_successor_offset (nano::transaction const & transaction_a, size_t entry_size_a, nano::block_type type_a) const
|
||||
{
|
||||
size_t result;
|
||||
if (full_sideband (transaction_a) || entry_has_sideband (entry_size_a, type_a))
|
||||
{
|
||||
result = entry_size_a - nano::block_sideband::size (type_a);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read old successor-only sideband
|
||||
assert (entry_size_a == nano::block::size (type_a) + sizeof (nano::uint256_union));
|
||||
result = entry_size_a - sizeof (nano::uint256_union);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual boost::optional<DB_val> block_raw_get_by_type (nano::transaction const &, nano::block_hash const &, nano::block_type &) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fill in our predecessors
|
||||
*/
|
||||
template <class Val>
|
||||
class block_predecessor_set : public nano::block_visitor
|
||||
{
|
||||
public:
|
||||
block_predecessor_set (nano::transaction const & transaction_a, nano::block_store_partial<Val> & store_a) :
|
||||
transaction (transaction_a),
|
||||
store (store_a)
|
||||
{
|
||||
}
|
||||
virtual ~block_predecessor_set () = default;
|
||||
void fill_value (nano::block const & block_a)
|
||||
{
|
||||
auto hash (block_a.hash ());
|
||||
nano::block_type type;
|
||||
auto value (store.block_raw_get (transaction, block_a.previous (), type));
|
||||
auto version (store.block_version (transaction, block_a.previous ()));
|
||||
assert (value.size () != 0);
|
||||
std::vector<uint8_t> data (static_cast<uint8_t *> (value.data ()), static_cast<uint8_t *> (value.data ()) + value.size ());
|
||||
std::copy (hash.bytes.begin (), hash.bytes.end (), data.begin () + store.block_successor_offset (transaction, value.size (), type));
|
||||
store.block_raw_put (transaction, data, type, version, block_a.previous ());
|
||||
}
|
||||
void send_block (nano::send_block const & block_a) override
|
||||
{
|
||||
fill_value (block_a);
|
||||
}
|
||||
void receive_block (nano::receive_block const & block_a) override
|
||||
{
|
||||
fill_value (block_a);
|
||||
}
|
||||
void open_block (nano::open_block const & block_a) override
|
||||
{
|
||||
// Open blocks don't have a predecessor
|
||||
}
|
||||
void change_block (nano::change_block const & block_a) override
|
||||
{
|
||||
fill_value (block_a);
|
||||
}
|
||||
void state_block (nano::state_block const & block_a) override
|
||||
{
|
||||
if (!block_a.previous ().is_zero ())
|
||||
{
|
||||
fill_value (block_a);
|
||||
}
|
||||
}
|
||||
nano::transaction const & transaction;
|
||||
nano::block_store_partial<Val> & store;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue