diff --git a/nano/core_test/block_store.cpp b/nano/core_test/block_store.cpp index 487484e5..a420b534 100644 --- a/nano/core_test/block_store.cpp +++ b/nano/core_test/block_store.cpp @@ -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); } } diff --git a/nano/core_test/ledger.cpp b/nano/core_test/ledger.cpp index 2dbdff25..95f48e43 100644 --- a/nano/core_test/ledger.cpp +++ b/nano/core_test/ledger.cpp @@ -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); diff --git a/nano/node/cli.cpp b/nano/node/cli.cpp index c58c04e7..b92528b0 100644 --- a/nano/node/cli.cpp +++ b/nano/node/cli.cpp @@ -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 diff --git a/nano/node/lmdb/lmdb.cpp b/nano/node/lmdb/lmdb.cpp index fd1d621e..aec2d79f 100644 --- a/nano/node/lmdb/lmdb.cpp +++ b/nano/node/lmdb/lmdb.cpp @@ -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; diff --git a/nano/node/lmdb/lmdb.hpp b/nano/node/lmdb/lmdb.hpp index fbdf015e..0d778ed4 100644 --- a/nano/node/lmdb/lmdb.hpp +++ b/nano/node/lmdb/lmdb.hpp @@ -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 unchecked_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a) override; diff --git a/nano/node/request_aggregator.cpp b/nano/node/request_aggregator.cpp index faefc50c..04e608c1 100644 --- a/nano/node/request_aggregator.cpp +++ b/nano/node/request_aggregator.cpp @@ -188,7 +188,7 @@ std::pair>, std::vector 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; diff --git a/nano/node/voting.cpp b/nano/node/voting.cpp index 520e02d0..1df8d347 100644 --- a/nano/node/voting.cpp +++ b/nano/node/voting.cpp @@ -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 diff --git a/nano/secure/CMakeLists.txt b/nano/secure/CMakeLists.txt index a4e0899c..fc661cb7 100644 --- a/nano/secure/CMakeLists.txt +++ b/nano/secure/CMakeLists.txt @@ -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 diff --git a/nano/secure/blockstore.cpp b/nano/secure/blockstore.cpp index 89a7a3ed..e8fa4206 100644 --- a/nano/secure/blockstore.cpp +++ b/nano/secure/blockstore.cpp @@ -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) + { } diff --git a/nano/secure/blockstore.hpp b/nano/secure/blockstore.hpp index dd8c2616..a7c3287b 100644 --- a/nano/secure/blockstore.hpp +++ b/nano/secure/blockstore.hpp @@ -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 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 begin (nano::transaction const & transaction_a, nano::qualified_root const & root_a) const = 0; + virtual nano::store_iterator begin (nano::transaction const & transaction_a) const = 0; + virtual nano::store_iterator end () const = 0; + virtual void for_each_par (std::function, nano::store_iterator)> 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, nano::store_iterator)> const & action_a) const = 0; virtual void pruned_for_each_par (std::function, nano::store_iterator)> const & action_a) const = 0; virtual void blocks_for_each_par (std::function, nano::store_iterator)> const & action_a) const = 0; - virtual void final_vote_for_each_par (std::function, nano::store_iterator)> 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 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 final_vote_begin (nano::transaction const & transaction_a, nano::qualified_root const & root_a) const = 0; - virtual nano::store_iterator final_vote_begin (nano::transaction const & transaction_a) const = 0; - virtual nano::store_iterator final_vote_end () const = 0; + final_vote_store & final_vote; virtual unsigned max_block_write_batch_num () const = 0; diff --git a/nano/secure/blockstore_partial.hpp b/nano/secure/blockstore_partial.hpp index cd085dd0..d402dc4d 100644 --- a/nano/secure/blockstore_partial.hpp +++ b/nano/secure/blockstore_partial.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ class block_store_partial : public block_store nano::account_store_partial account_store_partial; nano::pending_store_partial pending_store_partial; nano::online_weight_store_partial online_weight_store_partial; + nano::final_vote_store_partial final_vote_store_partial; friend void release_assert_success (block_store_partial const & block_store, const int status); @@ -55,13 +57,15 @@ public: friend class nano::account_store_partial; friend class nano::pending_store_partial; friend class nano::online_weight_store_partial; + friend class nano::final_vote_store_partial; 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 (nullptr); } - nano::store_iterator final_vote_end () const override - { - return nano::store_iterator (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 (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 value; - auto status = get (transaction_a, tables::final_votes, nano::db_val (root_a), value); - release_assert (success (status) || not_found (status)); - bool result (true); - if (success (status)) - { - result = static_cast (value) == hash_a; - } - else - { - status = put (transaction_a, tables::final_votes, root_a, hash_a); - release_assert_success (*this, status); - } - return result; - } - - std::vector final_vote_get (nano::transaction const & transaction_a, nano::root const & root_a) override - { - std::vector 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 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 (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 (transaction_a, tables::pruned); } - nano::store_iterator final_vote_begin (nano::transaction const & transaction_a, nano::qualified_root const & root_a) const override - { - return make_iterator (transaction_a, tables::final_votes, nano::db_val (root_a)); - } - - nano::store_iterator final_vote_begin (nano::transaction const & transaction_a) const override - { - return make_iterator (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, nano::store_iterator)> const & action_a) const override - { - parallel_traversal ( - [&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: diff --git a/nano/secure/ledger.cpp b/nano/secure/ledger.cpp index ce9dcdb6..82e780a5 100644 --- a/nano/secure/ledger.cpp +++ b/nano/secure/ledger.cpp @@ -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); diff --git a/nano/secure/store/final_vote_store_partial.hpp b/nano/secure/store/final_vote_store_partial.hpp new file mode 100644 index 00000000..e02c17b0 --- /dev/null +++ b/nano/secure/store/final_vote_store_partial.hpp @@ -0,0 +1,115 @@ +#pragma once + +#include + +namespace +{ +template +void parallel_traversal (std::function const & action); +} + +namespace nano +{ +template +class block_store_partial; + +template +void release_assert_success (block_store_partial const & block_store, const int status); + +template +class final_vote_store_partial : public final_vote_store +{ +private: + nano::block_store_partial & block_store; + + friend void release_assert_success (block_store_partial const & block_store, const int status); + +public: + explicit final_vote_store_partial (nano::block_store_partial & 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 value; + auto status = block_store.get (transaction_a, tables::final_votes, nano::db_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 (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 get (nano::transaction const & transaction_a, nano::root const & root_a) override + { + std::vector 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 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 (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 begin (nano::transaction const & transaction_a, nano::qualified_root const & root_a) const override + { + return block_store.template make_iterator (transaction_a, tables::final_votes, nano::db_val (root_a)); + } + + nano::store_iterator begin (nano::transaction const & transaction_a) const override + { + return block_store.template make_iterator (transaction_a, tables::final_votes); + } + + nano::store_iterator end () const override + { + return nano::store_iterator (nullptr); + } + + void for_each_par (std::function, nano::store_iterator)> const & action_a) const override + { + parallel_traversal ( + [&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 ()); + }); + } +}; + +}