diff --git a/nano/core_test/active_transactions.cpp b/nano/core_test/active_transactions.cpp index 177bde557f..d15e215659 100644 --- a/nano/core_test/active_transactions.cpp +++ b/nano/core_test/active_transactions.cpp @@ -768,6 +768,10 @@ TEST (active_transactions, insertion_prioritization) // Sort by difficulty, descending std::vector> blocks{ send1, send2, send3, send4, send5, send6, send7 }; + for (auto const & block : blocks) + { + ASSERT_EQ (nano::process_result::progress, node.process (*block).code); + } std::sort (blocks.begin (), blocks.end (), [](auto const & blockl, auto const & blockr) { return blockl->difficulty () > blockr->difficulty (); }); auto update_active_multiplier = [&node] { @@ -904,3 +908,94 @@ TEST (active_transactions, vote_generator_session) } } } + +TEST (active_transactions, election_difficulty_update_old) +{ + nano::system system; + nano::node_flags node_flags; + node_flags.disable_request_loop = true; + auto & node = *system.add_node (node_flags); + nano::genesis genesis; + nano::keypair key; + auto send1 (std::make_shared (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - 10 * nano::xrb_ratio, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (genesis.hash ()))); + auto send1_copy (std::make_shared (*send1)); + node.process_active (send1); + node.block_processor.flush (); + auto root (send1->qualified_root ()); + ASSERT_EQ (1, node.active.size ()); + auto multiplier = node.active.roots.begin ()->multiplier; + { + nano::lock_guard guard (node.active.mutex); + ASSERT_EQ (node.active.normalized_multiplier (*send1), multiplier); + } + // Should not update with a lower difficulty + send1_copy->block_work_set (0); + ASSERT_EQ (nano::process_result::old, node.process (*send1_copy).code); + ASSERT_FALSE (send1_copy->has_sideband ()); + node.process_active (send1); + node.block_processor.flush (); + ASSERT_EQ (1, node.active.size ()); + ASSERT_EQ (node.active.roots.begin ()->multiplier, multiplier); + // Update work, even without a sideband it should find the block in the election and update the election multiplier + ASSERT_TRUE (node.work_generate_blocking (*send1_copy, send1->difficulty () + 1).is_initialized ()); + node.process_active (send1_copy); + node.block_processor.flush (); + ASSERT_EQ (1, node.active.size ()); + ASSERT_GT (node.active.roots.begin ()->multiplier, multiplier); +} + +TEST (active_transactions, election_difficulty_update_fork) +{ + nano::system system; + nano::node_flags node_flags; + node_flags.disable_request_loop = true; + auto & node = *system.add_node (node_flags); + + ASSERT_NE (nullptr, system.upgrade_genesis_epoch (node, nano::epoch::epoch_1)); + auto epoch2 = system.upgrade_genesis_epoch (node, nano::epoch::epoch_2); + ASSERT_NE (nullptr, epoch2); + nano::keypair key; + auto send1 (std::make_shared (nano::test_genesis_key.pub, epoch2->hash (), nano::test_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (epoch2->hash ()))); + auto open1 (std::make_shared (key.pub, 0, key.pub, nano::Gxrb_ratio, send1->hash (), key.prv, key.pub, *system.work.generate (key.pub))); + auto send2 (std::make_shared (nano::test_genesis_key.pub, send1->hash (), nano::test_genesis_key.pub, nano::genesis_amount - 2 * nano::Gxrb_ratio, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send1->hash ()))); + ASSERT_EQ (nano::process_result::progress, node.process (*send1).code); + ASSERT_EQ (nano::process_result::progress, node.process (*open1).code); + ASSERT_EQ (nano::process_result::progress, node.process (*send2).code); + + // Verify an election with multiple blocks is correctly updated on arrival of another block + // Each subsequent block has difficulty at least higher than the previous one + auto fork_change (std::make_shared (key.pub, open1->hash (), nano::test_genesis_key.pub, nano::Gxrb_ratio, 0, key.prv, key.pub, *system.work.generate (open1->hash ()))); + auto fork_send (std::make_shared (key.pub, open1->hash (), key.pub, 0, key.pub, key.prv, key.pub, *system.work.generate (open1->hash (), fork_change->difficulty ()))); + auto fork_receive (std::make_shared (key.pub, open1->hash (), key.pub, 2 * nano::Gxrb_ratio, send2->hash (), key.prv, key.pub, *system.work.generate (open1->hash (), fork_send->difficulty ()))); + ASSERT_GT (fork_send->difficulty (), fork_change->difficulty ()); + ASSERT_GT (fork_receive->difficulty (), fork_send->difficulty ()); + + node.process_active (fork_change); + node.block_processor.flush (); + ASSERT_EQ (1, node.active.size ()); + auto multiplier_change = node.active.roots.begin ()->multiplier; + node.process_active (fork_send); + node.block_processor.flush (); + ASSERT_EQ (1, node.active.size ()); + auto multiplier_send = node.active.roots.begin ()->multiplier; + node.process_active (fork_receive); + node.block_processor.flush (); + ASSERT_EQ (1, node.active.size ()); + auto multiplier_receive = node.active.roots.begin ()->multiplier; + + ASSERT_GT (multiplier_send, multiplier_change); + ASSERT_GT (multiplier_receive, multiplier_send); + + EXPECT_FALSE (fork_receive->has_sideband ()); + auto threshold = nano::work_threshold (fork_receive->work_version (), nano::block_details (nano::epoch::epoch_2, false, true, false)); + auto denormalized = nano::denormalized_multiplier (multiplier_receive, threshold); + ASSERT_NEAR (nano::difficulty::to_multiplier (fork_receive->difficulty (), threshold), denormalized, 1e-10); + + // Ensure a fork with updated difficulty will also update the election difficulty + fork_receive->block_work_set (*system.work.generate (fork_receive->root (), fork_receive->difficulty () + 1)); + node.process_active (fork_receive); + node.block_processor.flush (); + ASSERT_EQ (1, node.active.size ()); + auto multiplier_receive_updated = node.active.roots.begin ()->multiplier; + ASSERT_GT (multiplier_receive_updated, multiplier_receive); +} diff --git a/nano/core_test/conflicts.cpp b/nano/core_test/conflicts.cpp index a55b010974..79fdfc4292 100644 --- a/nano/core_test/conflicts.cpp +++ b/nano/core_test/conflicts.cpp @@ -39,6 +39,7 @@ TEST (conflicts, add_existing) node1.active.insert (send1); nano::keypair key2; auto send2 (std::make_shared (genesis.hash (), key2.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0)); + send2->sideband_set ({}); auto election1 = node1.active.insert (send2); ASSERT_EQ (1, node1.active.size ()); auto vote1 (std::make_shared (key2.pub, key2.prv, 0, send2)); diff --git a/nano/core_test/ledger.cpp b/nano/core_test/ledger.cpp index 5aadcfaca3..e57aa97a7d 100644 --- a/nano/core_test/ledger.cpp +++ b/nano/core_test/ledger.cpp @@ -928,32 +928,33 @@ TEST (votes, add_old_different_account) node1.work_generate_blocking (*send1); auto send2 (std::make_shared (send1->hash (), key1.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0)); node1.work_generate_blocking (*send2); - auto transaction (node1.store.tx_begin_write ()); - ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code); - ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send2).code); - auto election1 = node1.active.insert (send1); - auto election2 = node1.active.insert (send2); - ASSERT_EQ (1, election1.election->last_votes_size ()); - ASSERT_EQ (1, election2.election->last_votes_size ()); + ASSERT_EQ (nano::process_result::progress, node1.process_local (send1).code); + ASSERT_EQ (nano::process_result::progress, node1.process_local (send2).code); + auto election1 = node1.active.election (send1->qualified_root ()); + ASSERT_NE (nullptr, election1); + auto election2 = node1.active.election (send2->qualified_root ()); + ASSERT_NE (nullptr, election2); + ASSERT_EQ (1, election1->last_votes_size ()); + ASSERT_EQ (1, election2->last_votes_size ()); auto vote1 (std::make_shared (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 2, send1)); auto channel (std::make_shared (node1.network.udp_channels, node1.network.endpoint (), node1.network_params.protocol.protocol_version)); auto vote_result1 (node1.vote_processor.vote_blocking (vote1, channel)); ASSERT_EQ (nano::vote_code::vote, vote_result1); - ASSERT_EQ (2, election1.election->last_votes_size ()); - ASSERT_EQ (1, election2.election->last_votes_size ()); + ASSERT_EQ (2, election1->last_votes_size ()); + ASSERT_EQ (1, election2->last_votes_size ()); auto vote2 (std::make_shared (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 1, send2)); auto vote_result2 (node1.vote_processor.vote_blocking (vote2, channel)); ASSERT_EQ (nano::vote_code::vote, vote_result2); - ASSERT_EQ (2, election1.election->last_votes_size ()); - ASSERT_EQ (2, election2.election->last_votes_size ()); + ASSERT_EQ (2, election1->last_votes_size ()); + ASSERT_EQ (2, election2->last_votes_size ()); nano::unique_lock lock (node1.active.mutex); - ASSERT_NE (election1.election->last_votes.end (), election1.election->last_votes.find (nano::test_genesis_key.pub)); - ASSERT_NE (election2.election->last_votes.end (), election2.election->last_votes.find (nano::test_genesis_key.pub)); - ASSERT_EQ (send1->hash (), election1.election->last_votes[nano::test_genesis_key.pub].hash); - ASSERT_EQ (send2->hash (), election2.election->last_votes[nano::test_genesis_key.pub].hash); - auto winner1 (*election1.election->tally ().begin ()); + ASSERT_NE (election1->last_votes.end (), election1->last_votes.find (nano::test_genesis_key.pub)); + ASSERT_NE (election2->last_votes.end (), election2->last_votes.find (nano::test_genesis_key.pub)); + ASSERT_EQ (send1->hash (), election1->last_votes[nano::test_genesis_key.pub].hash); + ASSERT_EQ (send2->hash (), election2->last_votes[nano::test_genesis_key.pub].hash); + auto winner1 (*election1->tally ().begin ()); ASSERT_EQ (*send1, *winner1.second); - auto winner2 (*election2.election->tally ().begin ()); + auto winner2 (*election2->tally ().begin ()); ASSERT_EQ (*send2, *winner2.second); } @@ -2659,20 +2660,23 @@ TEST (ledger, block_hash_account_conflict) node1.work_generate_blocking (*receive1); node1.work_generate_blocking (*send2); node1.work_generate_blocking (*open_epoch1); - auto transaction (node1.store.tx_begin_write ()); - ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code); - ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *receive1).code); - ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send2).code); - ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *open_epoch1).code); - auto election1 = node1.active.insert (send1); - auto election2 = node1.active.insert (receive1); - auto election3 = node1.active.insert (send2); - auto election4 = node1.active.insert (open_epoch1); + ASSERT_EQ (nano::process_result::progress, node1.process_local (send1).code); + ASSERT_EQ (nano::process_result::progress, node1.process_local (receive1).code); + ASSERT_EQ (nano::process_result::progress, node1.process_local (send2).code); + ASSERT_EQ (nano::process_result::progress, node1.process_local (open_epoch1).code); + auto election1 = node1.active.election (send1->qualified_root ()); + ASSERT_NE (nullptr, election1); + auto election2 = node1.active.election (receive1->qualified_root ()); + ASSERT_NE (nullptr, election2); + auto election3 = node1.active.election (send2->qualified_root ()); + ASSERT_NE (nullptr, election3); + auto election4 = node1.active.election (open_epoch1->qualified_root ()); + ASSERT_NE (nullptr, election4); nano::lock_guard lock (node1.active.mutex); - auto winner1 (*election1.election->tally ().begin ()); - auto winner2 (*election2.election->tally ().begin ()); - auto winner3 (*election3.election->tally ().begin ()); - auto winner4 (*election4.election->tally ().begin ()); + auto winner1 (*election1->tally ().begin ()); + auto winner2 (*election2->tally ().begin ()); + auto winner3 (*election3->tally ().begin ()); + auto winner4 (*election4->tally ().begin ()); ASSERT_EQ (*send1, *winner1.second); ASSERT_EQ (*receive1, *winner2.second); ASSERT_EQ (*send2, *winner3.second); diff --git a/nano/node/active_transactions.cpp b/nano/node/active_transactions.cpp index 41d727c157..a1d8f27186 100644 --- a/nano/node/active_transactions.cpp +++ b/nano/node/active_transactions.cpp @@ -493,8 +493,9 @@ void nano::active_transactions::stop () roots.clear (); } -nano::election_insertion_result nano::active_transactions::insert_impl (std::shared_ptr block_a, std::function)> const & confirmation_action_a) +nano::election_insertion_result nano::active_transactions::insert_impl (std::shared_ptr const & block_a, boost::optional const & previous_balance_a, std::function)> const & confirmation_action_a) { + debug_assert (block_a->has_sideband ()); nano::election_insertion_result result; if (!stopped) { @@ -507,10 +508,14 @@ nano::election_insertion_result nano::active_transactions::insert_impl (std::sha result.inserted = true; auto hash (block_a->hash ()); auto difficulty (block_a->difficulty ()); + auto epoch (block_a->sideband ().details.epoch); + auto previous_balance = block_a->previous ().is_zero () ? 0 : previous_balance_a.value_or_eval ([& node = node, &block_a] { + return node.ledger.balance (node.store.tx_begin_read (), block_a->previous ()); + }); double multiplier (normalized_multiplier (*block_a)); bool prioritized = roots.size () < prioritized_cutoff || multiplier > last_prioritized_multiplier.value_or (0); result.election = nano::make_shared (node, block_a, confirmation_action_a, prioritized); - roots.get ().emplace (nano::conflict_info{ root, multiplier, multiplier, result.election }); + roots.get ().emplace (nano::active_transactions::conflict_info{ root, multiplier, multiplier, result.election, epoch, previous_balance }); blocks.emplace (hash, result.election); add_adjust_difficulty (hash); result.election->insert_inactive_votes_cache (hash); @@ -524,10 +529,10 @@ nano::election_insertion_result nano::active_transactions::insert_impl (std::sha return result; } -nano::election_insertion_result nano::active_transactions::insert (std::shared_ptr block_a, std::function)> const & confirmation_action_a) +nano::election_insertion_result nano::active_transactions::insert (std::shared_ptr const & block_a, boost::optional const & previous_balance_a, std::function)> const & confirmation_action_a) { nano::lock_guard lock (mutex); - return insert_impl (block_a, confirmation_action_a); + return insert_impl (block_a, previous_balance_a, confirmation_action_a); } // Validate a vote and apply it to the current election if one exists @@ -628,30 +633,35 @@ std::shared_ptr nano::active_transactions::election (nano::quali return result; } -void nano::active_transactions::update_difficulty (std::shared_ptr block_a) +void nano::active_transactions::update_difficulty (nano::block const & block_a) { nano::unique_lock lock (mutex); - auto existing_election (roots.get ().find (block_a->qualified_root ())); + auto existing_election (roots.get ().find (block_a.qualified_root ())); if (existing_election != roots.get ().end ()) { - double multiplier (normalized_multiplier (*block_a, existing_election->election->blocks)); - if (multiplier > existing_election->multiplier) + update_difficulty_impl (existing_election, block_a); + } +} + +void nano::active_transactions::update_difficulty_impl (nano::active_transactions::roots_iterator const & root_it_a, nano::block const & block_a) +{ + double multiplier (normalized_multiplier (block_a, root_it_a)); + if (multiplier > root_it_a->multiplier) + { + if (node.config.logging.active_update_logging ()) { - if (node.config.logging.active_update_logging ()) - { - node.logger.try_log (boost::str (boost::format ("Block %1% was updated from multiplier %2% to %3%") % block_a->hash ().to_string () % existing_election->multiplier % multiplier)); - } - roots.get ().modify (existing_election, [multiplier](nano::conflict_info & info_a) { - info_a.multiplier = multiplier; - }); - existing_election->election->publish (block_a); - add_adjust_difficulty (block_a->hash ()); + node.logger.try_log (boost::str (boost::format ("Block %1% was updated from multiplier %2% to %3%") % block_a.hash ().to_string () % root_it_a->multiplier % multiplier)); } + roots.get ().modify (root_it_a, [multiplier](nano::active_transactions::conflict_info & info_a) { + info_a.multiplier = multiplier; + }); + add_adjust_difficulty (block_a.hash ()); } } -double nano::active_transactions::normalized_multiplier (nano::block const & block_a, std::unordered_map> const & blocks_a) +double nano::active_transactions::normalized_multiplier (nano::block const & block_a, boost::optional const & root_it_a) const { + debug_assert (!mutex.try_lock ()); auto difficulty (block_a.difficulty ()); uint64_t threshold (0); bool sideband_not_found (false); @@ -659,16 +669,23 @@ double nano::active_transactions::normalized_multiplier (nano::block const & blo { threshold = nano::work_threshold (block_a.work_version (), block_a.sideband ().details); } - else + else if (root_it_a.is_initialized ()) { - auto find_block (blocks_a.find (block_a.hash ())); - if (find_block != blocks_a.end () && find_block->second->has_sideband ()) + auto election (*root_it_a); + debug_assert (election != roots.end ()); + auto find_block (election->election->blocks.find (block_a.hash ())); + if (find_block != election->election->blocks.end () && find_block->second->has_sideband ()) { threshold = nano::work_threshold (block_a.work_version (), find_block->second->sideband ().details); } else { - threshold = nano::work_threshold_base (block_a.work_version ()); + // This can have incorrect results during an epoch upgrade, but it only affects prioritization + bool is_send = election->previous_balance > block_a.balance ().number (); + bool is_receive = election->previous_balance < block_a.balance ().number (); + nano::block_details details (election->epoch, is_send, is_receive, false); + + threshold = nano::work_threshold (block_a.work_version (), details); sideband_not_found = true; } } @@ -678,6 +695,11 @@ double nano::active_transactions::normalized_multiplier (nano::block const & blo { multiplier = nano::normalized_multiplier (multiplier, threshold); } + else + { + // Inferred threshold was incorrect + multiplier = 1; + } return multiplier; } @@ -763,7 +785,7 @@ void nano::active_transactions::update_adjusted_multiplier () double multiplier_a = avg_multiplier + (double)item.second * min_unit; if (existing_root->adjusted_multiplier != multiplier_a) { - roots.get ().modify (existing_root, [multiplier_a](nano::conflict_info & info_a) { + roots.get ().modify (existing_root, [multiplier_a](nano::active_transactions::conflict_info & info_a) { info_a.adjusted_multiplier = multiplier_a; }); } @@ -909,6 +931,7 @@ bool nano::active_transactions::publish (std::shared_ptr block_a) auto result (true); if (existing != roots.get ().end ()) { + update_difficulty_impl (existing, *block_a); auto election (existing->election); result = election->publish (block_a); if (!result) diff --git a/nano/node/active_transactions.hpp b/nano/node/active_transactions.hpp index 9809d730ad..0c36302e15 100644 --- a/nano/node/active_transactions.hpp +++ b/nano/node/active_transactions.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -31,15 +32,6 @@ class vote; class transaction; class confirmation_height_processor; -class conflict_info final -{ -public: - nano::qualified_root root; - double multiplier; - double adjusted_multiplier; - std::shared_ptr election; -}; - class cementable_account final { public: @@ -76,6 +68,17 @@ class election_insertion_result final // Holds all active blocks i.e. recently added blocks that need confirmation class active_transactions final { + class conflict_info final + { + public: + nano::qualified_root root; + double multiplier; + double adjusted_multiplier; + std::shared_ptr election; + nano::epoch epoch; + nano::uint128_t previous_balance; + }; + friend class nano::election; // clang-format off @@ -89,12 +92,24 @@ class active_transactions final // clang-format on public: + // clang-format off + using ordered_roots = boost::multi_index_container, + mi::member>, + mi::ordered_non_unique, + mi::member, + std::greater>>>; + // clang-format on + ordered_roots roots; + using roots_iterator = active_transactions::ordered_roots::index_iterator::type; + explicit active_transactions (nano::node &, nano::confirmation_height_processor &); ~active_transactions (); // Start an election for a block // Call action with confirmed block, may be different than what we started with // clang-format off - nano::election_insertion_result insert (std::shared_ptr, std::function)> const & = [](std::shared_ptr) {}); + nano::election_insertion_result insert (std::shared_ptr const &, boost::optional const & = boost::none, std::function)> const & = [](std::shared_ptr) {}); // clang-format on // Distinguishes replay votes, cannot be determined if the block is not in any election nano::vote_code vote (std::shared_ptr); @@ -102,8 +117,8 @@ class active_transactions final bool active (nano::block const &); bool active (nano::qualified_root const &); std::shared_ptr election (nano::qualified_root const &) const; - void update_difficulty (std::shared_ptr); - double normalized_multiplier (nano::block const &, std::unordered_map> const & = {}); + void update_difficulty (nano::block const &); + double normalized_multiplier (nano::block const &, boost::optional const & = boost::none) const; void add_adjust_difficulty (nano::block_hash const &); void update_adjusted_multiplier (); void update_active_multiplier (nano::unique_lock &); @@ -120,16 +135,6 @@ class active_transactions final boost::optional confirm_block (nano::transaction const &, std::shared_ptr); void block_cemented_callback (std::shared_ptr const & block_a); void block_already_cemented_callback (nano::block_hash const &); - // clang-format off - boost::multi_index_container, - mi::member>, - mi::ordered_non_unique, - mi::member, - std::greater>>> - roots; - // clang-format on boost::optional last_prioritized_multiplier{ boost::none }; std::unordered_map> blocks; std::deque list_recently_cemented (); @@ -159,8 +164,9 @@ class active_transactions final // Call action with confirmed block, may be different than what we started with // clang-format off - nano::election_insertion_result insert_impl (std::shared_ptr, std::function)> const & = [](std::shared_ptr) {}); + nano::election_insertion_result insert_impl (std::shared_ptr const &, boost::optional const & = boost::none, std::function)> const & = [](std::shared_ptr) {}); // clang-format on + void update_difficulty_impl (roots_iterator const &, nano::block const &); void request_loop (); void confirm_prioritized_frontiers (nano::transaction const & transaction_a); void request_confirm (nano::unique_lock &); diff --git a/nano/node/blockprocessor.cpp b/nano/node/blockprocessor.cpp index bf24af73cc..29915b88c5 100644 --- a/nano/node/blockprocessor.cpp +++ b/nano/node/blockprocessor.cpp @@ -264,7 +264,7 @@ void nano::block_processor::process_batch (nano::unique_lock & lock_ } } -void nano::block_processor::process_live (nano::block_hash const & hash_a, std::shared_ptr block_a, const bool watch_work_a, const bool initial_publish_a) +void nano::block_processor::process_live (nano::block_hash const & hash_a, std::shared_ptr block_a, nano::process_return const & process_return_a, const bool watch_work_a, const bool initial_publish_a) { // Add to work watcher to prevent dropping the election if (watch_work_a) @@ -273,7 +273,7 @@ void nano::block_processor::process_live (nano::block_hash const & hash_a, std:: } // Start collecting quorum on block - auto election = node.active.insert (block_a); + auto election = node.active.insert (block_a, process_return_a.previous_balance.number ()); if (election.inserted) { election.election->transition_passive (); @@ -308,7 +308,7 @@ nano::process_return nano::block_processor::process_one (nano::write_transaction } if (info_a.modified > nano::seconds_since_epoch () - 300 && node.block_arrival.recent (hash)) { - process_live (hash, info_a.block, watch_work_a, first_publish_a); + process_live (hash, info_a.block, result, watch_work_a, first_publish_a); } queue_unchecked (transaction_a, hash); break; @@ -368,7 +368,7 @@ nano::process_return nano::block_processor::process_one (nano::write_transaction node.logger.try_log (boost::str (boost::format ("Old for: %1%") % hash.to_string ())); } queue_unchecked (transaction_a, hash); - node.active.update_difficulty (info_a.block); + node.active.update_difficulty (*info_a.block); node.stats.inc (nano::stat::type::ledger, nano::stat::detail::old); break; } diff --git a/nano/node/blockprocessor.hpp b/nano/node/blockprocessor.hpp index ca6299ccf5..84c8dc8113 100644 --- a/nano/node/blockprocessor.hpp +++ b/nano/node/blockprocessor.hpp @@ -51,7 +51,7 @@ class block_processor final private: void queue_unchecked (nano::write_transaction const &, nano::block_hash const &); void process_batch (nano::unique_lock &); - void process_live (nano::block_hash const &, std::shared_ptr, const bool = false, const bool = false); + void process_live (nano::block_hash const &, std::shared_ptr, nano::process_return const &, const bool = false, const bool = false); void requeue_invalid (nano::block_hash const &, nano::unchecked_info const &); void process_verified_state_blocks (std::deque &, std::vector const &, std::vector const &, std::vector const &); bool stopped{ false }; diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 91db5c05c7..36f30824af 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -545,7 +545,7 @@ void nano::node::process_fork (nano::transaction const & transaction_a, std::sha if (ledger_block && !block_confirmed_or_being_confirmed (transaction_a, ledger_block->hash ())) { std::weak_ptr this_w (shared_from_this ()); - auto election = active.insert (ledger_block, [this_w, root](std::shared_ptr) { + auto election = active.insert (ledger_block, boost::none, [this_w, root](std::shared_ptr) { if (auto this_l = this_w.lock ()) { auto attempt (this_l->bootstrap_initiator.current_attempt ()); diff --git a/nano/node/wallet.cpp b/nano/node/wallet.cpp index 95fb8ce9d3..3413210e66 100644 --- a/nano/node/wallet.cpp +++ b/nano/node/wallet.cpp @@ -1482,7 +1482,7 @@ void nano::work_watcher::watching (nano::qualified_root const & root_a, std::sha if (!ec) { watcher_l->node.network.flood_block_initial (block); - watcher_l->node.active.update_difficulty (block); + watcher_l->node.active.update_difficulty (*block); watcher_l->update (root_a, block); } } diff --git a/nano/secure/common.hpp b/nano/secure/common.hpp index 3f5df09150..2b273d4616 100644 --- a/nano/secure/common.hpp +++ b/nano/secure/common.hpp @@ -330,6 +330,7 @@ class process_return final nano::account pending_account; boost::optional state_is_send; nano::signature_verification verified; + nano::amount previous_balance; }; enum class tally_result { diff --git a/nano/secure/ledger.cpp b/nano/secure/ledger.cpp index 377215b1b7..01ad49e06c 100644 --- a/nano/secure/ledger.cpp +++ b/nano/secure/ledger.cpp @@ -280,8 +280,9 @@ void ledger_processor::state_block_impl (nano::state_block & block_a) auto account_error (ledger.store.account_get (transaction, block_a.hashables.account, info)); if (!account_error) { - epoch = info.epoch (); // Account already exists + epoch = info.epoch (); + result.previous_balance = info.balance; result.code = block_a.hashables.previous.is_zero () ? nano::process_result::fork : nano::process_result::progress; // Has this account already been opened? (Ambigious) if (result.code == nano::process_result::progress) { @@ -298,6 +299,7 @@ void ledger_processor::state_block_impl (nano::state_block & block_a) else { // Account does not yet exists + result.previous_balance = 0; result.code = block_a.previous ().is_zero () ? nano::process_result::progress : nano::process_result::gap_previous; // Does the first block in an account yield 0 for previous() ? (Unambigious) if (result.code == nano::process_result::progress) { @@ -399,6 +401,7 @@ void ledger_processor::epoch_block_impl (nano::state_block & block_a) if (!account_error) { // Account already exists + result.previous_balance = info.balance; result.code = block_a.hashables.previous.is_zero () ? nano::process_result::fork : nano::process_result::progress; // Has this account already been opened? (Ambigious) if (result.code == nano::process_result::progress) { @@ -411,6 +414,7 @@ void ledger_processor::epoch_block_impl (nano::state_block & block_a) } else { + result.previous_balance = 0; result.code = block_a.hashables.representative.is_zero () ? nano::process_result::progress : nano::process_result::representative_mismatch; // Non-exisitng account should have pending entries if (result.code == nano::process_result::progress) @@ -512,6 +516,7 @@ void ledger_processor::change_block (nano::change_block & block_a) ledger.store.frontier_put (transaction, hash, account); result.account = account; result.amount = 0; + result.previous_balance = info.balance; ledger.stats.inc (nano::stat::type::ledger, nano::stat::detail::change); } } @@ -572,6 +577,7 @@ void ledger_processor::send_block (nano::send_block & block_a) result.account = account; result.amount = amount; result.pending_account = block_a.hashables.destination; + result.previous_balance = info.balance; ledger.stats.inc (nano::stat::type::ledger, nano::stat::detail::send); } } @@ -644,6 +650,7 @@ void ledger_processor::receive_block (nano::receive_block & block_a) ledger.store.frontier_put (transaction, hash, account); result.account = account; result.amount = pending.amount; + result.previous_balance = info.balance; ledger.stats.inc (nano::stat::type::ledger, nano::stat::detail::receive); } } @@ -712,6 +719,7 @@ void ledger_processor::open_block (nano::open_block & block_a) ledger.store.frontier_put (transaction, hash, block_a.hashables.account); result.account = block_a.hashables.account; result.amount = pending.amount; + result.previous_balance = 0; ledger.stats.inc (nano::stat::type::ledger, nano::stat::detail::open); } }