From af39839d203591c59fd406be03f21f896858a184 Mon Sep 17 00:00:00 2001 From: SergiySW Date: Wed, 9 Jan 2019 14:25:49 +0300 Subject: [PATCH 1/8] Check state blocks existance in ledger before verification Alternative to https://github.com/nanocurrency/nano-node/pull/1566 --- nano/node/node.cpp | 33 ++++++++++++++++++--------------- nano/node/node.hpp | 2 +- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 572104553a..3922b668fe 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -1299,24 +1299,23 @@ 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 ()) - { - items.swap (state_blocks); - } - else + std::deque, std::chrono::steady_clock::time_point>> items_l1; + items_l1.swap (state_blocks); + lock_a.unlock (); + for (auto i (0); i < max_count; i++) { - 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 (items_l1.front ()); + items_l1.pop_front (); + if (!ledger.store.block_exists (transaction, item.first->type (), item.first->hash ())) + { + items.push_back (item); + } } - lock_a.unlock (); auto size (items.size ()); std::vector hashes; hashes.reserve (size); @@ -1365,9 +1364,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 ()); @@ -1437,7 +1440,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 13bf27b5db..133184ba54 100644 --- a/nano/node/node.hpp +++ b/nano/node/node.hpp @@ -429,7 +429,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; From e79b395f7ca2ea477b25a63aa75e5b96f9d7a521 Mon Sep 17 00:00:00 2001 From: SergiySW Date: Wed, 9 Jan 2019 14:28:00 +0300 Subject: [PATCH 2/8] Avoid batch verification for empty items --- nano/node/node.cpp | 77 ++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 3922b668fe..f4ec294d6f 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -1316,45 +1316,48 @@ void nano::block_processor::verify_state_blocks (nano::transaction const & trans items.push_back (item); } } - 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 ()) - { - BOOST_LOG (node.log) << boost::str (boost::format ("Batch verified %1% state blocks in %2% %3%") % size % timer_l.stop ().count () % timer_l.unit ()); } } From 9cf8c71b8d8a4dc34dbb7fb3024dd343ed68227e Mon Sep 17 00:00:00 2001 From: SergiySW Date: Wed, 9 Jan 2019 15:28:49 +0300 Subject: [PATCH 3/8] Empty check --- nano/node/node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nano/node/node.cpp b/nano/node/node.cpp index f4ec294d6f..69dbe30d2b 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -1307,7 +1307,7 @@ void nano::block_processor::verify_state_blocks (nano::transaction const & trans std::deque, std::chrono::steady_clock::time_point>> items_l1; items_l1.swap (state_blocks); lock_a.unlock (); - for (auto i (0); i < max_count; i++) + for (auto i (0); i < max_count && !items_l1.empty (); i++) { auto item (items_l1.front ()); items_l1.pop_front (); From 57077fe40391a607cfb76772164d7fd9ed54f587 Mon Sep 17 00:00:00 2001 From: SergiySW Date: Wed, 9 Jan 2019 17:34:19 +0300 Subject: [PATCH 4/8] Fix --- nano/node/node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 69dbe30d2b..79902ce7af 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -1311,7 +1311,7 @@ void nano::block_processor::verify_state_blocks (nano::transaction const & trans { auto item (items_l1.front ()); items_l1.pop_front (); - if (!ledger.store.block_exists (transaction, item.first->type (), item.first->hash ())) + if (!node.ledger.store.block_exists (transaction, item.first->type (), item.first->hash ())) { items.push_back (item); } From 89624d9a31bdd3d67bca76e385b3d0b656f5b9fa Mon Sep 17 00:00:00 2001 From: SergiySW Date: Thu, 10 Jan 2019 20:40:08 +0300 Subject: [PATCH 5/8] Fix --- nano/node/node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nano/node/node.cpp b/nano/node/node.cpp index cc79d94f84..35f3d8cc91 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -1312,7 +1312,7 @@ void nano::block_processor::verify_state_blocks (nano::transaction const & trans { auto item (items_l1.front ()); items_l1.pop_front (); - if (!node.ledger.store.block_exists (transaction, item.first->type (), item.first->hash ())) + if (!node.ledger.store.block_exists (transaction_a, item.first->type (), item.first->hash ())) { items.push_back (item); } From 61fcd7bb4eb206feb101b9a6abbc5785596521d1 Mon Sep 17 00:00:00 2001 From: SergiySW Date: Fri, 11 Jan 2019 02:37:31 +0300 Subject: [PATCH 6/8] Fix lock --- nano/node/node.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 35f3d8cc91..3ac41aa1f9 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -1360,6 +1360,10 @@ void nano::block_processor::verify_state_blocks (nano::transaction const & trans BOOST_LOG (node.log) << boost::str (boost::format ("Batch verified %1% state blocks in %2% %3%") % size % timer_l.stop ().count () % timer_l.unit ()); } } + else + { + lock_a.lock (); + } } void nano::block_processor::process_batch (std::unique_lock & lock_a) From 6be189370ca380f60d51a9c88b1e88c8fb69d841 Mon Sep 17 00:00:00 2001 From: SergiySW Date: Sat, 12 Jan 2019 13:05:02 +0300 Subject: [PATCH 7/8] Fix deleted state blocks --- nano/node/node.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 3ac41aa1f9..83f7abe7ef 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -1305,18 +1305,16 @@ void nano::block_processor::verify_state_blocks (nano::transaction const & trans assert (!mutex.try_lock ()); nano::timer timer_l (nano::timer_state::started); std::deque, std::chrono::steady_clock::time_point>> items; - std::deque, std::chrono::steady_clock::time_point>> items_l1; - items_l1.swap (state_blocks); - lock_a.unlock (); for (auto i (0); i < max_count && !items_l1.empty (); i++) { - auto item (items_l1.front ()); - items_l1.pop_front (); + 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 (); if (!items.empty ()) { auto size (items.size ()); From ed7ed51808d8210849265a6d3df46c135b3363f7 Mon Sep 17 00:00:00 2001 From: SergiySW Date: Sat, 12 Jan 2019 13:05:44 +0300 Subject: [PATCH 8/8] Fix --- nano/node/node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 83f7abe7ef..2aaed357df 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -1305,7 +1305,7 @@ void nano::block_processor::verify_state_blocks (nano::transaction const & trans assert (!mutex.try_lock ()); nano::timer timer_l (nano::timer_state::started); std::deque, std::chrono::steady_clock::time_point>> items; - for (auto i (0); i < max_count && !items_l1.empty (); i++) + for (auto i (0); i < max_count && !state_blocks.empty (); i++) { auto item (state_blocks.front ()); state_blocks.pop_front ();