Moves out final vote methods from block store class (#3320)

* Moves out final vote methods from block store class
This commit is contained in:
Thiago Silva 2021-06-02 15:33:56 -03:00 committed by GitHub
commit 1f41f570b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 176 additions and 128 deletions

View file

@ -1829,13 +1829,13 @@ TEST (mdb_block_store, upgrade_v20_v21)
auto transaction (store.tx_begin_write ());
store.initialize (transaction, genesis, ledger.cache);
// Delete pruned table
ASSERT_FALSE (mdb_drop (store.env.tx (transaction), store.final_votes, 1));
ASSERT_FALSE (mdb_drop (store.env.tx (transaction), store.final_vote_handle, 1));
store.version_put (transaction, 20);
}
// Upgrading should create the table
nano::mdb_store store (logger, path);
ASSERT_FALSE (store.init_error ());
ASSERT_NE (store.final_votes, 0);
ASSERT_NE (store.final_vote_handle, 0);
// Version should be correct
auto transaction (store.tx_begin_read ());
@ -1944,18 +1944,18 @@ TEST (block_store, final_vote)
{
auto qualified_root = nano::genesis ().open->qualified_root ();
auto transaction (store->tx_begin_write ());
store->final_vote_put (transaction, qualified_root, nano::block_hash (2));
ASSERT_EQ (store->final_vote_count (transaction), 1);
store->final_vote_clear (transaction);
ASSERT_EQ (store->final_vote_count (transaction), 0);
store->final_vote_put (transaction, qualified_root, nano::block_hash (2));
ASSERT_EQ (store->final_vote_count (transaction), 1);
store->final_vote.put (transaction, qualified_root, nano::block_hash (2));
ASSERT_EQ (store->final_vote.count (transaction), 1);
store->final_vote.clear (transaction);
ASSERT_EQ (store->final_vote.count (transaction), 0);
store->final_vote.put (transaction, qualified_root, nano::block_hash (2));
ASSERT_EQ (store->final_vote.count (transaction), 1);
// Clearing with incorrect root shouldn't remove
store->final_vote_clear (transaction, qualified_root.previous ());
ASSERT_EQ (store->final_vote_count (transaction), 1);
store->final_vote.clear (transaction, qualified_root.previous ());
ASSERT_EQ (store->final_vote.count (transaction), 1);
// Clearing with correct root should remove
store->final_vote_clear (transaction, qualified_root.root ());
ASSERT_EQ (store->final_vote_count (transaction), 0);
store->final_vote.clear (transaction, qualified_root.root ());
ASSERT_EQ (store->final_vote.count (transaction), 0);
}
}

View file

@ -3872,7 +3872,7 @@ TEST (ledger, migrate_lmdb_to_rocksdb)
store.version_put (transaction, version);
send->sideband_set ({});
store.block_put (transaction, send->hash (), *send);
store.final_vote_put (transaction, send->qualified_root (), nano::block_hash (2));
store.final_vote.put (transaction, send->qualified_root (), nano::block_hash (2));
}
auto error = ledger.migrate_lmdb_to_rocksdb (path);
@ -3902,8 +3902,8 @@ TEST (ledger, migrate_lmdb_to_rocksdb)
ASSERT_FALSE (rocksdb_store.confirmation_height_get (rocksdb_transaction, nano::genesis_account, confirmation_height_info));
ASSERT_EQ (confirmation_height_info.height, 2);
ASSERT_EQ (confirmation_height_info.frontier, send->hash ());
ASSERT_TRUE (rocksdb_store.final_vote_get (rocksdb_transaction, nano::root (send->previous ())).size () == 1);
ASSERT_EQ (rocksdb_store.final_vote_get (rocksdb_transaction, nano::root (send->previous ()))[0], nano::block_hash (2));
ASSERT_TRUE (rocksdb_store.final_vote.get (rocksdb_transaction, nano::root (send->previous ())).size () == 1);
ASSERT_EQ (rocksdb_store.final_vote.get (rocksdb_transaction, nano::root (send->previous ()))[0], nano::block_hash (2));
auto unchecked_infos = rocksdb_store.unchecked_get (rocksdb_transaction, nano::genesis_hash);
ASSERT_EQ (unchecked_infos.size (), 1);

View file

@ -240,7 +240,7 @@ bool copy_database (boost::filesystem::path const & data_path, boost::program_op
}
if (vm.count ("final_vote_clear"))
{
node.node->store.final_vote_clear (store.tx_begin_write ());
node.node->store.final_vote.clear (store.tx_begin_write ());
}
if (vm.count ("rebuild_database"))
{
@ -626,7 +626,7 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map
nano::root root;
if (!root.decode_hex (root_str))
{
node.node->store.final_vote_clear (transaction, root);
node.node->store.final_vote.clear (transaction, root);
std::cout << "Successfully cleared final votes" << std::endl;
}
else
@ -637,7 +637,7 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map
}
else if (vm.count ("all"))
{
node.node->store.final_vote_clear (node.node->store.tx_begin_write ());
node.node->store.final_vote.clear (node.node->store.tx_begin_write ());
std::cout << "All final votes are cleared" << std::endl;
}
else

View file

@ -199,7 +199,7 @@ void nano::mdb_store::open_databases (bool & error_a, nano::transaction const &
accounts = accounts_v0;
error_a |= mdb_dbi_open (env.tx (transaction_a), "pending", flags, &pending_v0) != 0;
lmdb_pending = pending_v0;
error_a |= mdb_dbi_open (env.tx (transaction_a), "final_votes", flags, &final_votes) != 0;
error_a |= mdb_dbi_open (env.tx (transaction_a), "final_votes", flags, &final_vote_handle) != 0;
auto version_l = version_get (transaction_a);
if (version_l < 19)
@ -752,7 +752,7 @@ void nano::mdb_store::upgrade_v19_to_v20 (nano::write_transaction const & transa
void nano::mdb_store::upgrade_v20_to_v21 (nano::write_transaction const & transaction_a)
{
logger.always_log ("Preparing v20 to v21 database upgrade...");
mdb_dbi_open (env.tx (transaction_a), "final_votes", MDB_CREATE, &final_votes);
mdb_dbi_open (env.tx (transaction_a), "final_votes", MDB_CREATE, &final_vote_handle);
version_put (transaction_a, 21);
logger.always_log ("Finished creating new final_vote table");
}
@ -878,7 +878,7 @@ MDB_dbi nano::mdb_store::table_to_dbi (tables table_a) const
case tables::confirmation_height:
return confirmation_height;
case tables::final_votes:
return final_votes;
return final_vote_handle;
default:
release_assert (false);
return peers;

View file

@ -196,7 +196,7 @@ public:
* Maps root to block hash for generated final votes.
* nano::qualified_root -> nano::block_hash
*/
MDB_dbi final_votes{ 0 };
MDB_dbi final_vote_handle{ 0 };
bool exists (nano::transaction const & transaction_a, tables table_a, nano::mdb_val const & key_a) const;
std::vector<nano::unchecked_info> unchecked_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a) override;

View file

@ -188,7 +188,7 @@ std::pair<std::vector<std::shared_ptr<nano::block>>, std::vector<std::shared_ptr
std::shared_ptr<nano::block> block;
//2. Final votes
auto final_vote_hashes (ledger.store.final_vote_get (transaction, root));
auto final_vote_hashes (ledger.store.final_vote.get (transaction, root));
if (!final_vote_hashes.empty ())
{
generate_final_vote = true;

View file

@ -194,7 +194,7 @@ void nano::vote_generator::add (nano::root const & root_a, nano::block_hash cons
{
auto transaction (ledger.store.tx_begin_write ({ tables::final_votes }));
auto block (ledger.store.block_get (transaction, hash_a));
should_vote = block != nullptr && ledger.dependents_confirmed (transaction, *block) && ledger.store.final_vote_put (transaction, block->qualified_root (), hash_a);
should_vote = block != nullptr && ledger.dependents_confirmed (transaction, *block) && ledger.store.final_vote.put (transaction, block->qualified_root (), hash_a);
debug_assert (block == nullptr || root_a == block->root ());
}
else

View file

@ -57,7 +57,8 @@ add_library(
store/frontier_store_partial.hpp
store/account_store_partial.hpp
store/pending_store_partial.hpp
store/online_weight_partial.hpp)
store/online_weight_partial.hpp
store/final_vote_store_partial.hpp)
target_link_libraries(
secure

View file

@ -105,10 +105,12 @@ bool nano::write_transaction::contains (nano::tables table_a) const
return impl->contains (table_a);
}
nano::block_store::block_store (nano::frontier_store & frontier_store_a, nano::account_store & account_store_a, nano::pending_store & pending_store_a, nano::online_weight_store & online_weight_store_a) :
nano::block_store::block_store (nano::frontier_store & frontier_store_a, nano::account_store & account_store_a, nano::pending_store & pending_store_a, nano::online_weight_store & online_weight_store_a, nano::final_vote_store & final_vote_store_a) :
frontier (frontier_store_a),
account (account_store_a),
pending (pending_store_a),
online_weight (online_weight_store_a)
online_weight (online_weight_store_a),
final_vote (final_vote_store_a)
{
}

View file

@ -685,13 +685,31 @@ public:
virtual void clear (nano::write_transaction const &) = 0;
};
/**
* Manages final vote storage and iteration
*/
class final_vote_store
{
public:
virtual bool put (nano::write_transaction const & transaction_a, nano::qualified_root const & root_a, nano::block_hash const & hash_a) = 0;
virtual std::vector<nano::block_hash> get (nano::transaction const & transaction_a, nano::root const & root_a) = 0;
virtual void del (nano::write_transaction const & transaction_a, nano::root const & root_a) = 0;
virtual size_t count (nano::transaction const & transaction_a) const = 0;
virtual void clear (nano::write_transaction const &, nano::root const &) = 0;
virtual void clear (nano::write_transaction const &) = 0;
virtual nano::store_iterator<nano::qualified_root, nano::block_hash> begin (nano::transaction const & transaction_a, nano::qualified_root const & root_a) const = 0;
virtual nano::store_iterator<nano::qualified_root, nano::block_hash> begin (nano::transaction const & transaction_a) const = 0;
virtual nano::store_iterator<nano::qualified_root, nano::block_hash> end () const = 0;
virtual void for_each_par (std::function<void (nano::read_transaction const &, nano::store_iterator<nano::qualified_root, nano::block_hash>, nano::store_iterator<nano::qualified_root, nano::block_hash>)> const & action_a) const = 0;
};
/**
* Manages block storage and iteration
*/
class block_store
{
public:
explicit block_store (nano::frontier_store &, nano::account_store &, nano::pending_store &, nano::online_weight_store &);
explicit block_store (nano::frontier_store &, nano::account_store &, nano::pending_store &, nano::online_weight_store &, nano::final_vote_store &);
virtual ~block_store () = default;
virtual void initialize (nano::write_transaction const &, nano::genesis const &, nano::ledger_cache &) = 0;
virtual void block_put (nano::write_transaction const &, nano::block_hash const &, nano::block const &) = 0;
@ -768,19 +786,10 @@ public:
virtual void unchecked_for_each_par (std::function<void (nano::read_transaction const &, nano::store_iterator<nano::unchecked_key, nano::unchecked_info>, nano::store_iterator<nano::unchecked_key, nano::unchecked_info>)> const & action_a) const = 0;
virtual void pruned_for_each_par (std::function<void (nano::read_transaction const &, nano::store_iterator<nano::block_hash, std::nullptr_t>, nano::store_iterator<nano::block_hash, std::nullptr_t>)> const & action_a) const = 0;
virtual void blocks_for_each_par (std::function<void (nano::read_transaction const &, nano::store_iterator<nano::block_hash, block_w_sideband>, nano::store_iterator<nano::block_hash, block_w_sideband>)> const & action_a) const = 0;
virtual void final_vote_for_each_par (std::function<void (nano::read_transaction const &, nano::store_iterator<nano::qualified_root, nano::block_hash>, nano::store_iterator<nano::qualified_root, nano::block_hash>)> const & action_a) const = 0;
virtual uint64_t block_account_height (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const = 0;
virtual bool final_vote_put (nano::write_transaction const & transaction_a, nano::qualified_root const & root_a, nano::block_hash const & hash_a) = 0;
virtual std::vector<nano::block_hash> final_vote_get (nano::transaction const & transaction_a, nano::root const & root_a) = 0;
virtual void final_vote_del (nano::write_transaction const & transaction_a, nano::root const & root_a) = 0;
virtual size_t final_vote_count (nano::transaction const & transaction_a) const = 0;
virtual void final_vote_clear (nano::write_transaction const &, nano::root const &) = 0;
virtual void final_vote_clear (nano::write_transaction const &) = 0;
virtual nano::store_iterator<nano::qualified_root, nano::block_hash> final_vote_begin (nano::transaction const & transaction_a, nano::qualified_root const & root_a) const = 0;
virtual nano::store_iterator<nano::qualified_root, nano::block_hash> final_vote_begin (nano::transaction const & transaction_a) const = 0;
virtual nano::store_iterator<nano::qualified_root, nano::block_hash> final_vote_end () const = 0;
final_vote_store & final_vote;
virtual unsigned max_block_write_batch_num () const = 0;

View file

@ -7,6 +7,7 @@
#include <nano/secure/blockstore.hpp>
#include <nano/secure/buffer.hpp>
#include <nano/secure/store/account_store_partial.hpp>
#include <nano/secure/store/final_vote_store_partial.hpp>
#include <nano/secure/store/frontier_store_partial.hpp>
#include <nano/secure/store/online_weight_partial.hpp>
#include <nano/secure/store/pending_store_partial.hpp>
@ -43,6 +44,7 @@ class block_store_partial : public block_store
nano::account_store_partial<Val, Derived_Store> account_store_partial;
nano::pending_store_partial<Val, Derived_Store> pending_store_partial;
nano::online_weight_store_partial<Val, Derived_Store> online_weight_store_partial;
nano::final_vote_store_partial<Val, Derived_Store> final_vote_store_partial;
friend void release_assert_success<Val, Derived_Store> (block_store_partial<Val, Derived_Store> const & block_store, const int status);
@ -55,13 +57,15 @@ public:
friend class nano::account_store_partial<Val, Derived_Store>;
friend class nano::pending_store_partial<Val, Derived_Store>;
friend class nano::online_weight_store_partial<Val, Derived_Store>;
friend class nano::final_vote_store_partial<Val, Derived_Store>;
block_store_partial () :
block_store{ frontier_store_partial, account_store_partial, pending_store_partial, online_weight_store_partial },
block_store{ frontier_store_partial, account_store_partial, pending_store_partial, online_weight_store_partial, final_vote_store_partial },
frontier_store_partial{ *this },
account_store_partial{ *this },
pending_store_partial{ *this },
online_weight_store_partial{ *this }
online_weight_store_partial{ *this },
final_vote_store_partial{ *this }
{
}
@ -257,11 +261,6 @@ public:
return nano::store_iterator<nano::block_hash, std::nullptr_t> (nullptr);
}
nano::store_iterator<nano::qualified_root, nano::block_hash> final_vote_end () const override
{
return nano::store_iterator<nano::qualified_root, nano::block_hash> (nullptr);
}
int version_get (nano::transaction const & transaction_a) const override
{
nano::uint256_union version_key (1);
@ -471,65 +470,6 @@ public:
return exists (transaction_a, tables::confirmation_height, nano::db_val<Val> (account_a));
}
bool final_vote_put (nano::write_transaction const & transaction_a, nano::qualified_root const & root_a, nano::block_hash const & hash_a) override
{
nano::db_val<Val> value;
auto status = get (transaction_a, tables::final_votes, nano::db_val<Val> (root_a), value);
release_assert (success (status) || not_found (status));
bool result (true);
if (success (status))
{
result = static_cast<nano::block_hash> (value) == hash_a;
}
else
{
status = put (transaction_a, tables::final_votes, root_a, hash_a);
release_assert_success (*this, status);
}
return result;
}
std::vector<nano::block_hash> final_vote_get (nano::transaction const & transaction_a, nano::root const & root_a) override
{
std::vector<nano::block_hash> result;
nano::qualified_root key_start (root_a.raw, 0);
for (auto i (final_vote_begin (transaction_a, key_start)), n (final_vote_end ()); i != n && nano::qualified_root (i->first).root () == root_a; ++i)
{
result.push_back (i->second);
}
return result;
}
size_t final_vote_count (nano::transaction const & transaction_a) const override
{
return count (transaction_a, tables::final_votes);
}
void final_vote_del (nano::write_transaction const & transaction_a, nano::root const & root_a) override
{
std::vector<nano::qualified_root> final_vote_qualified_roots;
for (auto i (final_vote_begin (transaction_a, nano::qualified_root (root_a.raw, 0))), n (final_vote_end ()); i != n && nano::qualified_root (i->first).root () == root_a; ++i)
{
final_vote_qualified_roots.push_back (i->first);
}
for (auto & final_vote_qualified_root : final_vote_qualified_roots)
{
auto status (del (transaction_a, tables::final_votes, nano::db_val<Val> (final_vote_qualified_root)));
release_assert_success (*this, status);
}
}
void final_vote_clear (nano::write_transaction const & transaction_a, nano::root const & root_a) override
{
final_vote_del (transaction_a, root_a);
}
void final_vote_clear (nano::write_transaction const & transaction_a) override
{
drop (transaction_a, nano::tables::final_votes);
}
void confirmation_height_clear (nano::write_transaction const & transaction_a, nano::account const & account_a) override
{
confirmation_height_del (transaction_a, account_a);
@ -585,16 +525,6 @@ public:
return make_iterator<nano::block_hash, std::nullptr_t> (transaction_a, tables::pruned);
}
nano::store_iterator<nano::qualified_root, nano::block_hash> final_vote_begin (nano::transaction const & transaction_a, nano::qualified_root const & root_a) const override
{
return make_iterator<nano::qualified_root, nano::block_hash> (transaction_a, tables::final_votes, nano::db_val<Val> (root_a));
}
nano::store_iterator<nano::qualified_root, nano::block_hash> final_vote_begin (nano::transaction const & transaction_a) const override
{
return make_iterator<nano::qualified_root, nano::block_hash> (transaction_a, tables::final_votes);
}
size_t unchecked_count (nano::transaction const & transaction_a) override
{
return count (transaction_a, tables::unchecked);
@ -638,15 +568,6 @@ public:
});
}
void final_vote_for_each_par (std::function<void (nano::read_transaction const &, nano::store_iterator<nano::qualified_root, nano::block_hash>, nano::store_iterator<nano::qualified_root, nano::block_hash>)> const & action_a) const override
{
parallel_traversal<nano::uint512_t> (
[&action_a, this] (nano::uint512_t const & start, nano::uint512_t const & end, bool const is_last) {
auto transaction (this->tx_begin_read ());
action_a (transaction, this->final_vote_begin (transaction, start), !is_last ? this->final_vote_begin (transaction, end) : this->final_vote_end ());
});
}
int const minimum_version{ 14 };
protected:

View file

@ -632,7 +632,7 @@ void ledger_processor::receive_block (nano::receive_block & block_a)
if (ledger.store.block_exists (transaction, block_a.hashables.source))
{
nano::account_info source_info;
[[maybe_unused]] auto error (ledger.store.account.account_get (transaction, pending.source, source_info));
[[maybe_unused]] auto error (ledger.store.account.get (transaction, pending.source, source_info));
debug_assert (!error);
}
#endif
@ -704,7 +704,7 @@ void ledger_processor::open_block (nano::open_block & block_a)
if (ledger.store.block_exists (transaction, block_a.hashables.source))
{
nano::account_info source_info;
[[maybe_unused]] auto error (ledger.store.account.account_get (transaction, pending.source, source_info));
[[maybe_unused]] auto error (ledger.store.account.get (transaction, pending.source, source_info));
debug_assert (!error);
}
#endif
@ -1490,12 +1490,12 @@ bool nano::ledger::migrate_lmdb_to_rocksdb (boost::filesystem::path const & data
}
});
store.final_vote_for_each_par (
store.final_vote.for_each_par (
[&rocksdb_store] (nano::read_transaction const & /*unused*/, auto i, auto n) {
for (; i != n; ++i)
{
auto rocksdb_transaction (rocksdb_store->tx_begin_write ({}, { nano::tables::final_votes }));
rocksdb_store->final_vote_put (rocksdb_transaction, i->first, i->second);
rocksdb_store->final_vote.put (rocksdb_transaction, i->first, i->second);
}
});
@ -1518,7 +1518,7 @@ bool nano::ledger::migrate_lmdb_to_rocksdb (boost::filesystem::path const & data
error |= store.unchecked_count (lmdb_transaction) != rocksdb_store->unchecked_count (rocksdb_transaction);
error |= store.peer_count (lmdb_transaction) != rocksdb_store->peer_count (rocksdb_transaction);
error |= store.pruned_count (lmdb_transaction) != rocksdb_store->pruned_count (rocksdb_transaction);
error |= store.final_vote_count (lmdb_transaction) != rocksdb_store->final_vote_count (rocksdb_transaction);
error |= store.final_vote.count (lmdb_transaction) != rocksdb_store->final_vote.count (rocksdb_transaction);
error |= store.online_weight.count (lmdb_transaction) != rocksdb_store->online_weight.count (rocksdb_transaction);
error |= store.version_get (lmdb_transaction) != rocksdb_store->version_get (rocksdb_transaction);

View file

@ -0,0 +1,115 @@
#pragma once
#include <nano/secure/blockstore_partial.hpp>
namespace
{
template <typename T>
void parallel_traversal (std::function<void (T const &, T const &, bool const)> const & action);
}
namespace nano
{
template <typename Val, typename Derived_Store>
class block_store_partial;
template <typename Val, typename Derived_Store>
void release_assert_success (block_store_partial<Val, Derived_Store> const & block_store, const int status);
template <typename Val, typename Derived_Store>
class final_vote_store_partial : public final_vote_store
{
private:
nano::block_store_partial<Val, Derived_Store> & block_store;
friend void release_assert_success<Val, Derived_Store> (block_store_partial<Val, Derived_Store> const & block_store, const int status);
public:
explicit final_vote_store_partial (nano::block_store_partial<Val, Derived_Store> & block_store_a) :
block_store (block_store_a){};
bool put (nano::write_transaction const & transaction_a, nano::qualified_root const & root_a, nano::block_hash const & hash_a) override
{
nano::db_val<Val> value;
auto status = block_store.get (transaction_a, tables::final_votes, nano::db_val<Val> (root_a), value);
release_assert (block_store.success (status) || block_store.not_found (status));
bool result (true);
if (block_store.success (status))
{
result = static_cast<nano::block_hash> (value) == hash_a;
}
else
{
status = block_store.put (transaction_a, tables::final_votes, root_a, hash_a);
release_assert_success (block_store, status);
}
return result;
}
std::vector<nano::block_hash> get (nano::transaction const & transaction_a, nano::root const & root_a) override
{
std::vector<nano::block_hash> result;
nano::qualified_root key_start (root_a.raw, 0);
for (auto i (begin (transaction_a, key_start)), n (end ()); i != n && nano::qualified_root (i->first).root () == root_a; ++i)
{
result.push_back (i->second);
}
return result;
}
void del (nano::write_transaction const & transaction_a, nano::root const & root_a) override
{
std::vector<nano::qualified_root> final_vote_qualified_roots;
for (auto i (begin (transaction_a, nano::qualified_root (root_a.raw, 0))), n (end ()); i != n && nano::qualified_root (i->first).root () == root_a; ++i)
{
final_vote_qualified_roots.push_back (i->first);
}
for (auto & final_vote_qualified_root : final_vote_qualified_roots)
{
auto status (block_store.del (transaction_a, tables::final_votes, nano::db_val<Val> (final_vote_qualified_root)));
release_assert_success (block_store, status);
}
}
size_t count (nano::transaction const & transaction_a) const override
{
return block_store.count (transaction_a, tables::final_votes);
}
void clear (nano::write_transaction const & transaction_a, nano::root const & root_a) override
{
del (transaction_a, root_a);
}
void clear (nano::write_transaction const & transaction_a) override
{
block_store.drop (transaction_a, nano::tables::final_votes);
}
nano::store_iterator<nano::qualified_root, nano::block_hash> begin (nano::transaction const & transaction_a, nano::qualified_root const & root_a) const override
{
return block_store.template make_iterator<nano::qualified_root, nano::block_hash> (transaction_a, tables::final_votes, nano::db_val<Val> (root_a));
}
nano::store_iterator<nano::qualified_root, nano::block_hash> begin (nano::transaction const & transaction_a) const override
{
return block_store.template make_iterator<nano::qualified_root, nano::block_hash> (transaction_a, tables::final_votes);
}
nano::store_iterator<nano::qualified_root, nano::block_hash> end () const override
{
return nano::store_iterator<nano::qualified_root, nano::block_hash> (nullptr);
}
void for_each_par (std::function<void (nano::read_transaction const &, nano::store_iterator<nano::qualified_root, nano::block_hash>, nano::store_iterator<nano::qualified_root, nano::block_hash>)> const & action_a) const override
{
parallel_traversal<nano::uint512_t> (
[&action_a, this] (nano::uint512_t const & start, nano::uint512_t const & end, bool const is_last) {
auto transaction (this->block_store.tx_begin_read ());
action_a (transaction, this->begin (transaction, start), !is_last ? this->begin (transaction, end) : this->end ());
});
}
};
}