From a4c70b773d7d5f4bd83a87e5b4c494519823f9ad Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Wed, 4 Sep 2019 13:40:43 +0300 Subject: [PATCH] Fix active transactions difficulty update for state blocks (#2279) * Fix active transactions difficulty update for state blocks due to verify_state_blocks () old blocks filter * Remove unused read transaction * Formatting --- nano/core_test/active_transactions.cpp | 51 ++++++++++++++++++++++++++ nano/node/blockprocessor.cpp | 17 ++------- nano/node/blockprocessor.hpp | 2 +- 3 files changed, 56 insertions(+), 14 deletions(-) diff --git a/nano/core_test/active_transactions.cpp b/nano/core_test/active_transactions.cpp index b23eb7d1..88dbb318 100644 --- a/nano/core_test/active_transactions.cpp +++ b/nano/core_test/active_transactions.cpp @@ -512,3 +512,54 @@ TEST (active_transactions, inactive_votes_cache_multiple_votes) } ASSERT_EQ (2, system.nodes[0]->stats.count (nano::stat::type::election, nano::stat::detail::vote_cached)); } + +TEST (active_transactions, update_difficulty) +{ + nano::system system (24000, 2); + auto & node1 = *system.nodes[0]; + auto & node2 = *system.nodes[1]; + nano::genesis genesis; + nano::keypair key1; + // Generate blocks & start elections + auto send1 (std::make_shared (genesis.hash (), key1.pub, nano::genesis_amount - 100, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (genesis.hash ()))); + uint64_t difficulty1 (0); + nano::work_validate (*send1, &difficulty1); + auto send2 (std::make_shared (nano::test_genesis_key.pub, send1->hash (), nano::test_genesis_key.pub, nano::genesis_amount - 200, key1.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send1->hash ()))); + uint64_t difficulty2 (0); + nano::work_validate (*send2, &difficulty2); + node1.process_active (send1); + node1.process_active (send2); + node1.block_processor.flush (); + system.deadline_set (10s); + while (node1.active.size () != 2 || node2.active.size () != 2) + { + ASSERT_NO_ERROR (system.poll ()); + } + // Update work with higher difficulty + node1.work_generate_blocking (*send1, difficulty1 + 1); + node1.work_generate_blocking (*send2, difficulty2 + 1); + node1.process_active (send1); + node1.process_active (send2); + node1.block_processor.flush (); + system.deadline_set (10s); + bool done (false); + while (!done) + { + { + // node1 + nano::lock_guard guard1 (node1.active.mutex); + auto const existing1 (node1.active.roots.find (send1->qualified_root ())); + ASSERT_NE (existing1, node1.active.roots.end ()); + auto const existing2 (node1.active.roots.find (send2->qualified_root ())); + ASSERT_NE (existing2, node1.active.roots.end ()); + // node2 + nano::lock_guard guard2 (node2.active.mutex); + auto const existing3 (node2.active.roots.find (send1->qualified_root ())); + ASSERT_NE (existing3, node2.active.roots.end ()); + auto const existing4 (node2.active.roots.find (send2->qualified_root ())); + ASSERT_NE (existing4, node2.active.roots.end ()); + done = (existing1->difficulty > difficulty1) && (existing2->difficulty > difficulty2) && (existing3->difficulty > difficulty1) && (existing4->difficulty > difficulty2); + } + ASSERT_NO_ERROR (system.poll ()); + } +} diff --git a/nano/node/blockprocessor.cpp b/nano/node/blockprocessor.cpp index 9c0a3a77..15efe46e 100644 --- a/nano/node/blockprocessor.cpp +++ b/nano/node/blockprocessor.cpp @@ -147,20 +147,12 @@ bool nano::block_processor::have_blocks () return !blocks.empty () || !forced.empty () || !state_blocks.empty (); } -void nano::block_processor::verify_state_blocks (nano::transaction const & transaction_a, nano::unique_lock & lock_a, size_t max_count) +void nano::block_processor::verify_state_blocks (nano::unique_lock & lock_a, size_t max_count) { assert (!mutex.try_lock ()); nano::timer timer_l (nano::timer_state::started); std::deque items; - for (auto i (0); i < max_count && !state_blocks.empty (); i++) - { - auto & item (state_blocks.front ()); - if (!node.ledger.store.block_exists (transaction_a, item.block->type (), item.block->hash ())) - { - items.push_back (std::move (item)); - } - state_blocks.pop_front (); - } + items.swap (state_blocks); lock_a.unlock (); if (!items.empty ()) { @@ -253,10 +245,9 @@ void nano::block_processor::process_batch (nano::unique_lock & lock_ if (!state_blocks.empty ()) { size_t max_verification_batch (node.flags.block_processor_verification_size != 0 ? node.flags.block_processor_verification_size : 2048 * (node.config.signature_checker_threads + 1)); - 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, max_verification_batch); + verify_state_blocks (lock_a, max_verification_batch); } } } @@ -354,7 +345,7 @@ void nano::block_processor::process_batch (nano::unique_lock & lock_ Because verification is long process, avoid large deque verification inside of write transaction */ if (blocks.empty () && !state_blocks.empty ()) { - verify_state_blocks (transaction, lock_a, 256 * (node.config.signature_checker_threads + 1)); + verify_state_blocks (lock_a, 256 * (node.config.signature_checker_threads + 1)); } } awaiting_write = false; diff --git a/nano/node/blockprocessor.hpp b/nano/node/blockprocessor.hpp index ecb073d6..2ed0b5fd 100644 --- a/nano/node/blockprocessor.hpp +++ b/nano/node/blockprocessor.hpp @@ -56,7 +56,7 @@ public: private: void queue_unchecked (nano::write_transaction const &, nano::block_hash const &); - void verify_state_blocks (nano::transaction const & transaction_a, nano::unique_lock &, size_t = std::numeric_limits::max ()); + void verify_state_blocks (nano::unique_lock &, size_t = std::numeric_limits::max ()); void process_batch (nano::unique_lock &); void process_live (nano::block_hash const &, std::shared_ptr, const bool = false); bool stopped;