diff --git a/nano/core_test/node.cpp b/nano/core_test/node.cpp index 0d71f615a..dabda43e9 100644 --- a/nano/core_test/node.cpp +++ b/nano/core_test/node.cpp @@ -2499,6 +2499,33 @@ TEST (node, local_votes_cache_generate_new_vote) ASSERT_FALSE (node.votes_cache.find (send2->hash ()).empty ()); } +// Tests that the max cache size is inversely proportional to the number of voting accounts +TEST (node, local_votes_cache_size) +{ + nano::system system; + nano::node_config node_config (nano::get_available_port (), system.logging); + node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled; + node_config.vote_minimum = 0; // wallet will pick up the second account as voting even if unopened + auto & node (*system.add_node (node_config)); + ASSERT_EQ (node.network_params.voting.max_cache, 2); // effective cache size is 1 with 2 voting accounts + nano::genesis genesis; + nano::keypair key; + auto & wallet (*system.wallet (0)); + wallet.insert_adhoc (nano::test_genesis_key.prv); + wallet.insert_adhoc (nano::keypair ().prv); + ASSERT_EQ (2, node.wallets.rep_counts ().voting); + auto transaction (node.store.tx_begin_read ()); + auto vote1 (node.store.vote_generate (transaction, nano::test_genesis_key.pub, nano::test_genesis_key.prv, { genesis.open->hash () })); + nano::block_hash hash (1); + auto vote2 (node.store.vote_generate (transaction, nano::test_genesis_key.pub, nano::test_genesis_key.prv, { hash })); + node.votes_cache.add (vote1); + node.votes_cache.add (vote2); + auto existing2 (node.votes_cache.find (hash)); + ASSERT_EQ (1, existing2.size ()); + ASSERT_EQ (vote2, existing2.front ()); + ASSERT_EQ (0, node.votes_cache.find (genesis.open->hash ()).size ()); +} + TEST (node, vote_republish) { nano::system system (2); diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 2d2888636..8c37ef838 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -132,6 +132,7 @@ port_mapping (*this), vote_processor (checker, active, store, observers, stats, config, logger, online_reps, ledger, network_params), rep_crawler (*this), warmed_up (0), +votes_cache (wallets), block_processor (*this, write_database_queue), block_processor_thread ([this]() { nano::thread_role::set (nano::thread_role::name::block_processing); diff --git a/nano/node/voting.cpp b/nano/node/voting.cpp index 8f4088e44..e9666415c 100644 --- a/nano/node/voting.cpp +++ b/nano/node/voting.cpp @@ -100,9 +100,17 @@ void nano::vote_generator::run () } } +nano::votes_cache::votes_cache (nano::wallets & wallets_a) : +wallets (wallets_a) +{ +} + void nano::votes_cache::add (std::shared_ptr const & vote_a) { nano::lock_guard lock (cache_mutex); + auto voting (wallets.rep_counts ().voting); + assert (voting > 0); + auto const max_cache_size (network_params.voting.max_cache / std::max (voting, static_cast (1))); for (auto & block : vote_a->blocks) { auto hash (boost::get (block)); @@ -110,7 +118,7 @@ void nano::votes_cache::add (std::shared_ptr const & vote_a) if (existing == cache.get ().end ()) { // Clean old votes - if (cache.size () >= network_params.voting.max_cache) + if (cache.size () >= max_cache_size) { cache.get ().pop_front (); } diff --git a/nano/node/voting.hpp b/nano/node/voting.hpp index b53afdbbb..79c83a21f 100644 --- a/nano/node/voting.hpp +++ b/nano/node/voting.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,7 @@ public: class votes_cache final { public: + votes_cache (nano::wallets & wallets_a); void add (std::shared_ptr const &); std::vector> find (nano::block_hash const &); void remove (nano::block_hash const &); @@ -79,6 +81,7 @@ private: cache; // clang-format on nano::network_params network_params; + nano::wallets & wallets; friend std::unique_ptr collect_container_info (votes_cache & votes_cache, const std::string & name); }; diff --git a/nano/node/wallet.cpp b/nano/node/wallet.cpp index 42e27db4b..ec4e527d7 100644 --- a/nano/node/wallet.cpp +++ b/nano/node/wallet.cpp @@ -1758,10 +1758,13 @@ void nano::wallets::foreach_representative (std::functionsecond); nano::lock_guard store_lock (wallet.store.mutex); - nano::lock_guard representatives_lock (wallet.representatives_mutex); - for (auto ii (wallet.representatives.begin ()), nn (wallet.representatives.end ()); ii != nn; ++ii) + decltype (wallet.representatives) representatives_l; + { + nano::lock_guard representatives_lock (wallet.representatives_mutex); + representatives_l = wallet.representatives; + } + for (auto const & account : representatives_l) { - nano::account account (*ii); if (wallet.store.exists (transaction_l, account)) { if (!node.ledger.weight (account).is_zero ()) diff --git a/nano/secure/common.cpp b/nano/secure/common.cpp index 17d437f46..22bf2a95c 100644 --- a/nano/secure/common.cpp +++ b/nano/secure/common.cpp @@ -132,7 +132,7 @@ nano::node_constants::node_constants (nano::network_constants & network_constant nano::voting_constants::voting_constants (nano::network_constants & network_constants) { - max_cache = network_constants.is_test_network () ? 2 : 4 * 1024; + max_cache = network_constants.is_test_network () ? 2 : 64 * 1024; } nano::portmapping_constants::portmapping_constants (nano::network_constants & network_constants)