diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 8e4f2c17..38d937a6 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -334,6 +334,22 @@ void nano::network::confirm_hashes (nano::transaction const & transaction_a, nan } } +bool nano::network::send_votes_cache (nano::block_hash const & hash_a, nano::endpoint const & peer_a) +{ + // Search in cache + auto votes (node.votes_cache.find (hash_a)); + // Send from cache + for (auto & vote : votes) + { + nano::confirm_ack confirm (vote); + auto vote_bytes = confirm.to_bytes (); + confirm_send (confirm, vote_bytes, peer_a); + } + // Returns true if votes were sent + bool result (!votes.empty ()); + return result; +} + void nano::network::republish_block (std::shared_ptr block) { auto hash (block->hash ()); @@ -650,41 +666,31 @@ public: node.stats.inc (nano::stat::type::message, nano::stat::detail::confirm_req, nano::stat::dir::in); node.peers.contacted (sender, message_a.header.version_using); // Don't load nodes with disabled voting - if (node.config.enable_voting) + if (node.config.enable_voting && node.wallets.reps_count) { - auto transaction (node.store.tx_begin_read ()); if (message_a.block != nullptr) { - auto successor (node.ledger.successor (transaction, nano::uint512_union (message_a.block->previous (), message_a.block->root ()))); - if (successor != nullptr) + auto hash (message_a.block->hash ()); + if (!node.network.send_votes_cache (hash, sender)) { - auto same_block (successor->hash () == message_a.block->hash ()); - confirm_block (transaction, node, sender, std::move (successor), !same_block); + auto transaction (node.store.tx_begin_read ()); + auto successor (node.ledger.successor (transaction, nano::uint512_union (message_a.block->previous (), message_a.block->root ()))); + if (successor != nullptr) + { + auto same_block (successor->hash () == hash); + confirm_block (transaction, node, sender, std::move (successor), !same_block); + } } } else if (!message_a.roots_hashes.empty ()) { + auto transaction (node.store.tx_begin_read ()); std::vector blocks_bundle; for (auto & root_hash : message_a.roots_hashes) { - if (node.store.block_exists (transaction, root_hash.first)) + if (!node.network.send_votes_cache (root_hash.first, sender) && node.store.block_exists (transaction, root_hash.first)) { - // Search in cache - auto votes (node.votes_cache.find (root_hash.first)); - if (votes.empty ()) - { - blocks_bundle.push_back (root_hash.first); - } - else - { - // Send from cache - for (auto & vote : votes) - { - nano::confirm_ack confirm (vote); - auto vote_bytes = confirm.to_bytes (); - node.network.confirm_send (confirm, vote_bytes, sender); - } - } + blocks_bundle.push_back (root_hash.first); } else { @@ -701,22 +707,10 @@ public: } if (!successor.is_zero ()) { - // Search in cache - auto votes (node.votes_cache.find (successor)); - if (votes.empty ()) + if (!node.network.send_votes_cache (successor, sender)) { blocks_bundle.push_back (successor); } - else - { - // Send from cache - for (auto & vote : votes) - { - nano::confirm_ack confirm (vote); - auto vote_bytes = confirm.to_bytes (); - node.network.confirm_send (confirm, vote_bytes, sender); - } - } auto successor_block (node.store.block_get (transaction, successor)); assert (successor_block != nullptr); node.network.republish_block (std::move (successor_block), sender); @@ -1811,7 +1805,9 @@ void nano::block_processor::process_batch (std::unique_lock & lock_a { // Replace our block with the winner and roll back any dependent blocks BOOST_LOG (node.log) << boost::str (boost::format ("Rolling back %1% and replacing with %2%") % successor->hash ().to_string () % hash.to_string ()); - node.ledger.rollback (transaction, successor->hash ()); + std::vector rollback_list; + node.ledger.rollback (transaction, successor->hash (), rollback_list); + BOOST_LOG (node.log) << boost::str (boost::format ("%1% blocks rolled back") % rollback_list.size ()); lock_a.lock (); // Prevent rolled back blocks second insertion auto inserted (rolled_back.insert (nano::rolled_hash{ std::chrono::steady_clock::now (), successor->hash () })); @@ -1826,6 +1822,11 @@ void nano::block_processor::process_batch (std::unique_lock & lock_a } } lock_a.unlock (); + // Deleting from votes cache + for (auto & i : rollback_list) + { + node.votes_cache.remove (i); + } } } number_of_blocks_processed++; diff --git a/nano/node/node.hpp b/nano/node/node.hpp index 69c71183..4015493b 100644 --- a/nano/node/node.hpp +++ b/nano/node/node.hpp @@ -334,6 +334,7 @@ public: void send_confirm_req (nano::endpoint const &, std::shared_ptr); void send_confirm_req_hashes (nano::endpoint const &, std::vector> const &); void confirm_hashes (nano::transaction const &, nano::endpoint const &, std::vector); + bool send_votes_cache (nano::block_hash const &, nano::endpoint const &); void send_buffer (uint8_t const *, size_t, nano::endpoint const &, std::function); nano::endpoint endpoint (); nano::udp_buffer buffer_container; diff --git a/nano/node/voting.cpp b/nano/node/voting.cpp index e199fb2b..f1534189 100644 --- a/nano/node/voting.cpp +++ b/nano/node/voting.cpp @@ -141,6 +141,12 @@ std::vector> nano::votes_cache::find (nano::block_ha return result; } +void nano::votes_cache::remove (nano::block_hash const & hash_a) +{ + std::lock_guard lock (cache_mutex); + cache.get<1> ().erase (hash_a); +} + namespace nano { std::unique_ptr collect_seq_con_info (vote_generator & vote_generator, const std::string & name) diff --git a/nano/node/voting.hpp b/nano/node/voting.hpp index 167ecbc9..41310802 100644 --- a/nano/node/voting.hpp +++ b/nano/node/voting.hpp @@ -53,6 +53,7 @@ class votes_cache public: void add (std::shared_ptr const &); std::vector> find (nano::block_hash const &); + void remove (nano::block_hash const &); private: std::mutex cache_mutex; diff --git a/nano/node/wallet.cpp b/nano/node/wallet.cpp index f673d2c3..a93c1eba 100644 --- a/nano/node/wallet.cpp +++ b/nano/node/wallet.cpp @@ -805,6 +805,7 @@ nano::public_key nano::wallet::deterministic_insert (nano::transaction const & t { std::lock_guard lock (representatives_mutex); representatives.insert (key); + ++wallets.reps_count; } } return key; @@ -847,6 +848,7 @@ nano::public_key nano::wallet::insert_adhoc (nano::transaction const & transacti { std::lock_guard lock (representatives_mutex); representatives.insert (key); + ++wallets.reps_count; } } return key; @@ -1605,6 +1607,7 @@ void nano::wallets::clear_send_ids (nano::transaction const & transaction_a) void nano::wallets::compute_reps () { std::lock_guard lock (mutex); + reps_count = 0; auto ledger_transaction (node.store.tx_begin_read ()); auto transaction (tx_begin_read ()); for (auto i (items.begin ()), n (items.end ()); i != n; ++i) @@ -1617,6 +1620,7 @@ void nano::wallets::compute_reps () if (node.ledger.weight (ledger_transaction, account) >= node.config.vote_minimum.number ()) { representatives_l.insert (account); + ++reps_count; } } std::lock_guard representatives_lock (wallet.representatives_mutex); diff --git a/nano/node/wallet.hpp b/nano/node/wallet.hpp index 738b6cf5..0755add1 100644 --- a/nano/node/wallet.hpp +++ b/nano/node/wallet.hpp @@ -200,6 +200,7 @@ public: boost::thread thread; static nano::uint128_t const generate_priority; static nano::uint128_t const high_priority; + std::atomic reps_count{ 0 }; /** Start read-write transaction */ nano::transaction tx_begin_write (); diff --git a/nano/secure/ledger.cpp b/nano/secure/ledger.cpp index 72c30b81..cb793e7f 100644 --- a/nano/secure/ledger.cpp +++ b/nano/secure/ledger.cpp @@ -11,9 +11,10 @@ namespace class rollback_visitor : public nano::block_visitor { public: - rollback_visitor (nano::transaction const & transaction_a, nano::ledger & ledger_a) : + rollback_visitor (nano::transaction const & transaction_a, nano::ledger & ledger_a, std::vector & list_a) : transaction (transaction_a), - ledger (ledger_a) + ledger (ledger_a), + list (list_a) { } virtual ~rollback_visitor () = default; @@ -24,7 +25,7 @@ public: nano::pending_key key (block_a.hashables.destination, hash); while (ledger.store.pending_get (transaction, key, pending)) { - ledger.rollback (transaction, ledger.latest (transaction, block_a.hashables.destination)); + ledger.rollback (transaction, ledger.latest (transaction, block_a.hashables.destination), list); } nano::account_info info; auto error (ledger.store.account_get (transaction, pending.source, info)); @@ -114,7 +115,7 @@ public: nano::pending_key key (block_a.hashables.link, hash); while (!ledger.store.pending_exists (transaction, key)) { - ledger.rollback (transaction, ledger.latest (transaction, block_a.hashables.link)); + ledger.rollback (transaction, ledger.latest (transaction, block_a.hashables.link), list); } ledger.store.pending_del (transaction, key); ledger.stats.inc (nano::stat::type::rollback, nano::stat::detail::send); @@ -148,6 +149,7 @@ public: } nano::transaction const & transaction; nano::ledger & ledger; + std::vector & list; }; class ledger_processor : public nano::block_visitor @@ -824,21 +826,28 @@ nano::uint128_t nano::ledger::weight (nano::transaction const & transaction_a, n } // Rollback blocks until `block_a' doesn't exist -void nano::ledger::rollback (nano::transaction const & transaction_a, nano::block_hash const & block_a) +void nano::ledger::rollback (nano::transaction const & transaction_a, nano::block_hash const & block_a, std::vector & list_a) { assert (store.block_exists (transaction_a, block_a)); auto account_l (account (transaction_a, block_a)); - rollback_visitor rollback (transaction_a, *this); + rollback_visitor rollback (transaction_a, *this, list_a); nano::account_info info; while (store.block_exists (transaction_a, block_a)) { auto latest_error (store.account_get (transaction_a, account_l, info)); assert (!latest_error); auto block (store.block_get (transaction_a, info.head)); + list_a.push_back (info.head); block->visit (rollback); } } +void nano::ledger::rollback (nano::transaction const & transaction_a, nano::block_hash const & block_a) +{ + std::vector rollback_list; + rollback (transaction_a, block_a, rollback_list); +} + // Return account containing hash nano::account nano::ledger::account (nano::transaction const & transaction_a, nano::block_hash const & hash_a) { diff --git a/nano/secure/ledger.hpp b/nano/secure/ledger.hpp index e47da239..1fca677d 100644 --- a/nano/secure/ledger.hpp +++ b/nano/secure/ledger.hpp @@ -38,6 +38,7 @@ public: nano::block_hash block_destination (nano::transaction const &, nano::block const &); nano::block_hash block_source (nano::transaction const &, nano::block const &); nano::process_return process (nano::transaction const &, nano::block const &, nano::signature_verification = nano::signature_verification::unknown); + void rollback (nano::transaction const &, nano::block_hash const &, std::vector &); void rollback (nano::transaction const &, nano::block_hash const &); void change_latest (nano::transaction const &, nano::account const &, nano::block_hash const &, nano::account const &, nano::uint128_union const &, uint64_t, bool = false, nano::epoch = nano::epoch::epoch_0); void dump_account_chain (nano::account const &);