diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 2bcbd41f00..7673965e09 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -1307,63 +1307,67 @@ bool nano::block_processor::have_blocks () return !blocks.empty () || !forced.empty () || !state_blocks.empty (); } -void nano::block_processor::verify_state_blocks (std::unique_lock & lock_a, size_t max_count) +void nano::block_processor::verify_state_blocks (nano::transaction const & transaction_a, std::unique_lock & lock_a, size_t max_count) { assert (!mutex.try_lock ()); nano::timer timer_l (nano::timer_state::started); std::deque, std::chrono::steady_clock::time_point>> items; - if (max_count == std::numeric_limits::max () || max_count >= state_blocks.size ()) + for (auto i (0); i < max_count && !state_blocks.empty (); i++) { - items.swap (state_blocks); - } - else - { - auto keep_size (state_blocks.size () - max_count); - items.resize (keep_size); - std::swap_ranges (state_blocks.end () - keep_size, state_blocks.end (), items.begin ()); - state_blocks.resize (max_count); - items.swap (state_blocks); + auto item (state_blocks.front ()); + state_blocks.pop_front (); + if (!node.ledger.store.block_exists (transaction_a, item.first->type (), item.first->hash ())) + { + items.push_back (item); + } } lock_a.unlock (); - auto size (items.size ()); - std::vector hashes; - hashes.reserve (size); - std::vector messages; - messages.reserve (size); - std::vector lengths; - lengths.reserve (size); - std::vector pub_keys; - pub_keys.reserve (size); - std::vector signatures; - signatures.reserve (size); - std::vector verifications; - verifications.resize (size, 0); - for (auto i (0); i < size; ++i) - { - auto & block (static_cast (*items[i].first)); - hashes.push_back (block.hash ()); - messages.push_back (hashes.back ().bytes.data ()); - lengths.push_back (sizeof (decltype (hashes)::value_type)); - pub_keys.push_back (block.hashables.account.bytes.data ()); - signatures.push_back (block.signature.bytes.data ()); - } - std::promise promise; - nano::signature_check_set check = { size, messages.data (), lengths.data (), pub_keys.data (), signatures.data (), verifications.data (), &promise }; - node.checker.add (check); - promise.get_future ().wait (); - lock_a.lock (); - for (auto i (0); i < size; ++i) - { - assert (verifications[i] == 1 || verifications[i] == 0); - if (verifications[i] == 1) + if (!items.empty ()) + { + auto size (items.size ()); + std::vector hashes; + hashes.reserve (size); + std::vector messages; + messages.reserve (size); + std::vector lengths; + lengths.reserve (size); + std::vector pub_keys; + pub_keys.reserve (size); + std::vector signatures; + signatures.reserve (size); + std::vector verifications; + verifications.resize (size, 0); + for (auto i (0); i < size; ++i) + { + auto & block (static_cast (*items[i].first)); + hashes.push_back (block.hash ()); + messages.push_back (hashes.back ().bytes.data ()); + lengths.push_back (sizeof (decltype (hashes)::value_type)); + pub_keys.push_back (block.hashables.account.bytes.data ()); + signatures.push_back (block.signature.bytes.data ()); + } + std::promise promise; + nano::signature_check_set check = { size, messages.data (), lengths.data (), pub_keys.data (), signatures.data (), verifications.data (), &promise }; + node.checker.add (check); + promise.get_future ().wait (); + lock_a.lock (); + for (auto i (0); i < size; ++i) + { + assert (verifications[i] == 1 || verifications[i] == 0); + if (verifications[i] == 1) + { + blocks.push_back (items.front ()); + } + items.pop_front (); + } + if (node.config.logging.timing_logging ()) { - blocks.push_back (items.front ()); + BOOST_LOG (node.log) << boost::str (boost::format ("Batch verified %1% state blocks in %2% %3%") % size % timer_l.stop ().count () % timer_l.unit ()); } - items.pop_front (); } - if (node.config.logging.timing_logging ()) + else { - BOOST_LOG (node.log) << boost::str (boost::format ("Batch verified %1% state blocks in %2% %3%") % size % timer_l.stop ().count () % timer_l.unit ()); + lock_a.lock (); } } @@ -1373,9 +1377,13 @@ void nano::block_processor::process_batch (std::unique_lock & lock_a lock_a.lock (); timer_l.start (); // Limit state blocks verification time - while (!state_blocks.empty () && timer_l.before_deadline (std::chrono::seconds (2))) + if (!state_blocks.empty ()) { - verify_state_blocks (lock_a, 2048); + auto transaction (node.store.tx_begin_read ()); + while (!state_blocks.empty () && timer_l.before_deadline (std::chrono::seconds (2))) + { + verify_state_blocks (transaction, lock_a, 2048); + } } lock_a.unlock (); auto transaction (node.store.tx_begin_write ()); @@ -1459,7 +1467,7 @@ void nano::block_processor::process_batch (std::unique_lock & lock_a Because verification is long process, avoid large deque verification inside of write transaction */ if (blocks.empty () && !state_blocks.empty ()) { - verify_state_blocks (lock_a, 256); + verify_state_blocks (transaction, lock_a, 256); } } lock_a.unlock (); diff --git a/nano/node/node.hpp b/nano/node/node.hpp index 07562e3724..83248aa3db 100644 --- a/nano/node/node.hpp +++ b/nano/node/node.hpp @@ -434,7 +434,7 @@ class block_processor private: void queue_unchecked (nano::transaction const &, nano::block_hash const &, std::chrono::steady_clock::time_point = std::chrono::steady_clock::time_point ()); - void verify_state_blocks (std::unique_lock &, size_t = std::numeric_limits::max ()); + void verify_state_blocks (nano::transaction const & transaction_a, std::unique_lock &, size_t = std::numeric_limits::max ()); void process_batch (std::unique_lock &); bool stopped; bool active;