diff --git a/nano/core_test/CMakeLists.txt b/nano/core_test/CMakeLists.txt index dda4bcca..8f16a81f 100644 --- a/nano/core_test/CMakeLists.txt +++ b/nano/core_test/CMakeLists.txt @@ -22,7 +22,6 @@ add_executable( enums.cpp epochs.cpp frontiers_confirmation.cpp - gap_cache.cpp ipc.cpp ledger.cpp locks.cpp diff --git a/nano/core_test/gap_cache.cpp b/nano/core_test/gap_cache.cpp deleted file mode 100644 index 561088db..00000000 --- a/nano/core_test/gap_cache.cpp +++ /dev/null @@ -1,168 +0,0 @@ -#include -#include -#include - -#include - -using namespace std::chrono_literals; - -TEST (gap_cache, add_new) -{ - nano::test::system system (1); - nano::gap_cache cache (*system.nodes[0]); - nano::block_builder builder; - auto block1 = builder - .send () - .previous (0) - .destination (1) - .balance (2) - .sign (nano::keypair ().prv, 4) - .work (5) - .build_shared (); - cache.add (block1->hash ()); -} - -TEST (gap_cache, add_existing) -{ - nano::test::system system (1); - nano::gap_cache cache (*system.nodes[0]); - nano::block_builder builder; - auto block1 = builder - .send () - .previous (0) - .destination (1) - .balance (2) - .sign (nano::keypair ().prv, 4) - .work (5) - .build_shared (); - cache.add (block1->hash ()); - nano::unique_lock lock{ cache.mutex }; - auto existing1 (cache.blocks.get<1> ().find (block1->hash ())); - ASSERT_NE (cache.blocks.get<1> ().end (), existing1); - auto arrival (existing1->arrival); - lock.unlock (); - ASSERT_TIMELY (20s, arrival != std::chrono::steady_clock::now ()); - cache.add (block1->hash ()); - ASSERT_EQ (1, cache.size ()); - lock.lock (); - auto existing2 (cache.blocks.get<1> ().find (block1->hash ())); - ASSERT_NE (cache.blocks.get<1> ().end (), existing2); - ASSERT_GT (existing2->arrival, arrival); -} - -TEST (gap_cache, comparison) -{ - nano::test::system system (1); - nano::gap_cache cache (*system.nodes[0]); - nano::block_builder builder; - auto block1 = builder - .send () - .previous (1) - .destination (0) - .balance (2) - .sign (nano::keypair ().prv, 4) - .work (5) - .build_shared (); - cache.add (block1->hash ()); - nano::unique_lock lock{ cache.mutex }; - auto existing1 (cache.blocks.get<1> ().find (block1->hash ())); - ASSERT_NE (cache.blocks.get<1> ().end (), existing1); - auto arrival (existing1->arrival); - lock.unlock (); - ASSERT_TIMELY (20s, std::chrono::steady_clock::now () != arrival); - auto block3 = builder - .send () - .previous (0) - .destination (42) - .balance (1) - .sign (nano::keypair ().prv, 3) - .work (4) - .build_shared (); - cache.add (block3->hash ()); - ASSERT_EQ (2, cache.size ()); - lock.lock (); - auto existing2 (cache.blocks.get<1> ().find (block3->hash ())); - ASSERT_NE (cache.blocks.get<1> ().end (), existing2); - ASSERT_GT (existing2->arrival, arrival); - ASSERT_EQ (arrival, cache.blocks.get<1> ().begin ()->arrival); -} - -// Upon receiving enough votes for a gapped block, a lazy bootstrap should be initiated -TEST (gap_cache, gap_bootstrap) -{ - nano::node_flags node_flags; - node_flags.disable_legacy_bootstrap = true; - node_flags.disable_request_loop = true; // to avoid fallback behavior of broadcasting blocks - nano::test::system system (2, nano::transport::transport_type::tcp, node_flags); - - auto & node1 (*system.nodes[0]); - auto & node2 (*system.nodes[1]); - nano::block_hash latest (node1.latest (nano::dev::genesis_key.pub)); - nano::keypair key; - nano::block_builder builder; - auto send = builder - .send () - .previous (latest) - .destination (key.pub) - .balance (nano::dev::constants.genesis_amount - 100) - .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) - .work (*system.work.generate (latest)) - .build_shared (); - ASSERT_EQ (nano::process_result::progress, node1.process (*send).code); - ASSERT_EQ (nano::dev::constants.genesis_amount - 100, node1.balance (nano::dev::genesis->account ())); - ASSERT_EQ (nano::dev::constants.genesis_amount, node2.balance (nano::dev::genesis->account ())); - // Confirm send block, allowing voting on the upcoming block - auto election = nano::test::start_election (system, node1, send->hash ()); - ASSERT_NE (nullptr, election); - election->force_confirm (); - ASSERT_TIMELY (5s, node1.block_confirmed (send->hash ())); - node1.active.erase (*send); - system.wallet (0)->insert_adhoc (nano::dev::genesis_key.prv); - auto latest_block (system.wallet (0)->send_action (nano::dev::genesis_key.pub, key.pub, 100)); - ASSERT_NE (nullptr, latest_block); - ASSERT_TIMELY_EQ (5s, nano::dev::constants.genesis_amount - 200, node1.balance (nano::dev::genesis->account ())); - ASSERT_TIMELY_EQ (5s, nano::dev::constants.genesis_amount, node2.balance (nano::dev::genesis->account ())); - ASSERT_TIMELY_EQ (5s, node2.balance (nano::dev::genesis->account ()), nano::dev::constants.genesis_amount - 200); -} - -TEST (gap_cache, two_dependencies) -{ - nano::test::system system (1); - auto & node1 (*system.nodes[0]); - nano::keypair key; - nano::block_builder builder; - auto send1 = builder - .send () - .previous (nano::dev::genesis->hash ()) - .destination (key.pub) - .balance (1) - .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) - .work (*system.work.generate (nano::dev::genesis->hash ())) - .build_shared (); - auto send2 = builder - .send () - .previous (send1->hash ()) - .destination (key.pub) - .balance (0) - .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) - .work (*system.work.generate (send1->hash ())) - .build_shared (); - auto open = builder - .open () - .source (send1->hash ()) - .representative (key.pub) - .account (key.pub) - .sign (key.prv, key.pub) - .work (*system.work.generate (key.pub)) - .build_shared (); - ASSERT_EQ (0, node1.gap_cache.size ()); - node1.block_processor.add (send2); - ASSERT_TIMELY_EQ (5s, 1, node1.gap_cache.size ()); - node1.block_processor.add (open); - ASSERT_TIMELY_EQ (5s, 2, node1.gap_cache.size ()); - node1.block_processor.add (send1); - ASSERT_TIMELY_EQ (5s, node1.gap_cache.size (), 0); - ASSERT_TIMELY (5s, node1.store.block.exists (node1.store.tx_begin_read (), send1->hash ())); - ASSERT_TIMELY (5s, node1.store.block.exists (node1.store.tx_begin_read (), send2->hash ())); - ASSERT_TIMELY (5s, node1.store.block.exists (node1.store.tx_begin_read (), open->hash ())); -} diff --git a/nano/core_test/node.cpp b/nano/core_test/node.cpp index 99696105..fddf1683 100644 --- a/nano/core_test/node.cpp +++ b/nano/core_test/node.cpp @@ -338,26 +338,6 @@ TEST (node, auto_bootstrap_age) node1->stop (); } -// Test ensures the block processor adds the published block to the gap cache. -TEST (node, receive_gap) -{ - nano::test::system system (1); - auto & node1 (*system.nodes[0]); - ASSERT_EQ (0, node1.gap_cache.size ()); - auto block = nano::send_block_builder () - .previous (5) - .destination (1) - .balance (2) - .sign (nano::keypair ().prv, 4) - .work (0) - .build_shared (); - node1.work_generate_blocking (*block); - nano::publish message{ nano::dev::network_params.network, block }; - auto channel1 = std::make_shared (node1); - node1.network.inbound (message, channel1); - ASSERT_TIMELY_EQ (5s, 1, node1.gap_cache.size ()); -} - TEST (node, merge_peers) { nano::test::system system (1); diff --git a/nano/node/CMakeLists.txt b/nano/node/CMakeLists.txt index 79183880..e340508c 100644 --- a/nano/node/CMakeLists.txt +++ b/nano/node/CMakeLists.txt @@ -26,8 +26,6 @@ add_library( block_broadcast.hpp block_publisher.cpp block_publisher.hpp - gap_tracker.cpp - gap_tracker.hpp blocking_observer.cpp blocking_observer.hpp blockprocessor.hpp @@ -88,8 +86,6 @@ add_library( election_insertion_result.hpp epoch_upgrader.hpp epoch_upgrader.cpp - gap_cache.hpp - gap_cache.cpp inactive_cache_information.hpp inactive_cache_information.cpp inactive_cache_status.hpp diff --git a/nano/node/blockprocessor.cpp b/nano/node/blockprocessor.cpp index 27090889..c0477b4e 100644 --- a/nano/node/blockprocessor.cpp +++ b/nano/node/blockprocessor.cpp @@ -343,7 +343,6 @@ nano::process_return nano::block_processor::process_one (store::write_transactio void nano::block_processor::queue_unchecked (store::write_transaction const & transaction_a, nano::hash_or_account const & hash_or_account_a) { node.unchecked.trigger (hash_or_account_a); - node.gap_cache.erase (hash_or_account_a.hash); } std::unique_ptr nano::collect_container_info (block_processor & block_processor, std::string const & name) diff --git a/nano/node/gap_cache.cpp b/nano/node/gap_cache.cpp deleted file mode 100644 index 1ef81dd5..00000000 --- a/nano/node/gap_cache.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include -#include - -#include - -nano::gap_cache::gap_cache (nano::node & node_a) : - node (node_a) -{ -} - -void nano::gap_cache::add (nano::block_hash const & hash_a, std::chrono::steady_clock::time_point time_point_a) -{ - nano::lock_guard lock{ mutex }; - auto existing (blocks.get ().find (hash_a)); - if (existing != blocks.get ().end ()) - { - blocks.get ().modify (existing, [time_point_a] (nano::gap_information & info) { - info.arrival = time_point_a; - }); - } - else - { - blocks.get ().emplace (nano::gap_information{ time_point_a, hash_a, std::vector () }); - if (blocks.get ().size () > max) - { - blocks.get ().erase (blocks.get ().begin ()); - } - } -} - -void nano::gap_cache::erase (nano::block_hash const & hash_a) -{ - nano::lock_guard lock{ mutex }; - blocks.get ().erase (hash_a); -} - -void nano::gap_cache::vote (std::shared_ptr const & vote_a) -{ - nano::lock_guard lock{ mutex }; - for (auto const & hash : vote_a->hashes) - { - auto & gap_blocks_by_hash (blocks.get ()); - auto existing (gap_blocks_by_hash.find (hash)); - if (existing != gap_blocks_by_hash.end () && !existing->bootstrap_started) - { - auto is_new (false); - gap_blocks_by_hash.modify (existing, [&is_new, &vote_a] (nano::gap_information & info) { - auto it = std::find (info.voters.begin (), info.voters.end (), vote_a->account); - is_new = (it == info.voters.end ()); - if (is_new) - { - info.voters.push_back (vote_a->account); - } - }); - - if (is_new) - { - if (bootstrap_check (existing->voters, hash)) - { - gap_blocks_by_hash.modify (existing, [] (nano::gap_information & info) { - info.bootstrap_started = true; - }); - } - } - } - } -} - -bool nano::gap_cache::bootstrap_check (std::vector const & voters_a, nano::block_hash const & hash_a) -{ - nano::uint128_t tally; - for (auto const & voter : voters_a) - { - tally += node.ledger.weight (voter); - } - bool start_bootstrap (false); - if (!node.flags.disable_lazy_bootstrap) - { - if (tally >= node.online_reps.delta ()) - { - start_bootstrap = true; - } - } - else if (!node.flags.disable_legacy_bootstrap && tally > bootstrap_threshold ()) - { - start_bootstrap = true; - } - if (start_bootstrap && !node.ledger.block_or_pruned_exists (hash_a)) - { - bootstrap_start (hash_a); - } - return start_bootstrap; -} - -void nano::gap_cache::bootstrap_start (nano::block_hash const & hash_a) -{ - auto node_l (node.shared ()); - node.workers.add_timed_task (std::chrono::steady_clock::now () + node.network_params.bootstrap.gap_cache_bootstrap_start_interval, [node_l, hash_a] () { - if (!node_l->ledger.block_or_pruned_exists (hash_a)) - { - if (!node_l->bootstrap_initiator.in_progress ()) - { - node_l->logger.debug (nano::log::type::gap_cache, "Block {} has enough votes to warrant lazy bootstrapping it", hash_a.to_string ()); - } - if (!node_l->flags.disable_lazy_bootstrap) - { - node_l->bootstrap_initiator.bootstrap_lazy (hash_a); - } - else if (!node_l->flags.disable_legacy_bootstrap) - { - node_l->bootstrap_initiator.bootstrap (); - } - } - }); -} - -nano::uint128_t nano::gap_cache::bootstrap_threshold () -{ - auto result ((node.online_reps.trended () / 256) * node.config.bootstrap_fraction_numerator); - return result; -} - -std::size_t nano::gap_cache::size () -{ - nano::lock_guard lock{ mutex }; - return blocks.size (); -} - -std::unique_ptr nano::collect_container_info (gap_cache & gap_cache, std::string const & name) -{ - auto count = gap_cache.size (); - auto sizeof_element = sizeof (decltype (gap_cache.blocks)::value_type); - auto composite = std::make_unique (name); - composite->add_component (std::make_unique (container_info{ "blocks", count, sizeof_element })); - return composite; -} diff --git a/nano/node/gap_cache.hpp b/nano/node/gap_cache.hpp deleted file mode 100644 index 118625fd..00000000 --- a/nano/node/gap_cache.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -namespace nano -{ -class node; - -/** For each gap in account chains, track arrival time and voters */ -class gap_information final -{ -public: - std::chrono::steady_clock::time_point arrival; - nano::block_hash hash; - std::vector voters; - bool bootstrap_started{ false }; -}; - -/** Maintains voting and arrival information for gaps (missing source or previous blocks in account chains) */ -class gap_cache final -{ -public: - explicit gap_cache (nano::node &); - void add (nano::block_hash const &, std::chrono::steady_clock::time_point = std::chrono::steady_clock::now ()); - void erase (nano::block_hash const & hash_a); - void vote (std::shared_ptr const &); - bool bootstrap_check (std::vector const &, nano::block_hash const &); - void bootstrap_start (nano::block_hash const & hash_a); - nano::uint128_t bootstrap_threshold (); - std::size_t size (); - // clang-format off - class tag_arrival {}; - class tag_hash {}; - using ordered_gaps = boost::multi_index_container, - boost::multi_index::member>, - boost::multi_index::hashed_unique, - boost::multi_index::member>>>; - ordered_gaps blocks; - // clang-format on - std::size_t const max = 256; - nano::mutex mutex{ mutex_identifier (mutexes::gap_cache) }; - nano::node & node; -}; - -std::unique_ptr collect_container_info (gap_cache & gap_cache, std::string const & name); -} diff --git a/nano/node/gap_tracker.cpp b/nano/node/gap_tracker.cpp deleted file mode 100644 index 35c6e534..00000000 --- a/nano/node/gap_tracker.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include -#include - -nano::gap_tracker::gap_tracker (nano::gap_cache & gap_cache) : - gap_cache{ gap_cache } -{ -} - -void nano::gap_tracker::connect (nano::block_processor & block_processor) -{ - block_processor.processed.add ([this] (auto const & result, auto const & block) { - switch (result.code) - { - case nano::process_result::gap_previous: - case nano::process_result::gap_source: - observe (block); - break; - default: - break; - } - }); -} - -void nano::gap_tracker::observe (std::shared_ptr block) -{ - gap_cache.add (block->hash ()); -} diff --git a/nano/node/gap_tracker.hpp b/nano/node/gap_tracker.hpp deleted file mode 100644 index 6b8e54f2..00000000 --- a/nano/node/gap_tracker.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include - -namespace nano -{ -class gap_cache; -class block_processor; -class block; - -// Observes the processed blocks and tracks them (gap_cache) if they are gap blocks. -class gap_tracker -{ -public: - gap_tracker (nano::gap_cache & gap_cache); - void connect (nano::block_processor & block_processor); - -private: - // Block_processor observer - void observe (std::shared_ptr block); - - nano::gap_cache & gap_cache; -}; -} diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 24a2e311..cda73b2f 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -156,7 +156,6 @@ nano::node::node (boost::asio::io_context & io_ctx_a, std::filesystem::path cons unchecked{ config.max_unchecked_blocks, stats, flags.disable_block_processor_unchecked_deletion }, wallets_store_impl (std::make_unique (application_path_a / "wallets.ldb", config_a.lmdb_config)), wallets_store (*wallets_store_impl), - gap_cache (*this), ledger (store, stats, network_params.ledger, flags_a.generate_cache), outbound_limiter{ outbound_bandwidth_limiter_config (config) }, // empty `config.peering_port` means the user made no port choice at all; @@ -200,14 +199,12 @@ nano::node::node (boost::asio::io_context & io_ctx_a, std::filesystem::path cons node_seq (seq), block_broadcast{ network, block_arrival, !flags.disable_block_processor_republishing }, block_publisher{ active }, - gap_tracker{ gap_cache }, process_live_dispatcher{ ledger, scheduler.priority, vote_cache, websocket } { logger.debug (nano::log::type::node, "Constructing node..."); block_broadcast.connect (block_processor); block_publisher.connect (block_processor); - gap_tracker.connect (block_processor); process_live_dispatcher.connect (block_processor); unchecked.satisfied.add ([this] (nano::unchecked_info const & info) { this->block_processor.add (info.block); @@ -331,7 +328,6 @@ nano::node::node (boost::asio::io_context & io_ctx_a, std::filesystem::path cons // Representative is defined as online if replying to live votes or rep_crawler queries this->online_reps.observe (vote_a->account); } - this->gap_cache.vote (vote_a); }); // Cancelling local work generation @@ -531,7 +527,6 @@ std::unique_ptr nano::collect_container_info (no { auto composite = std::make_unique (name); composite->add_component (collect_container_info (node.work, "work")); - composite->add_component (collect_container_info (node.gap_cache, "gap_cache")); composite->add_component (collect_container_info (node.ledger, "ledger")); composite->add_component (collect_container_info (node.active, "active")); composite->add_component (collect_container_info (node.bootstrap_initiator, "bootstrap_initiator")); @@ -1371,7 +1366,7 @@ void nano::node::bootstrap_block (const nano::block_hash & hash) if (!ledger.pruning || !store.pruned.exists (store.tx_begin_read (), hash)) { // We don't have the block, try to bootstrap it - gap_cache.bootstrap_start (hash); + // TODO: Use ascending bootstraper to bootstrap block hash } } diff --git a/nano/node/node.hpp b/nano/node/node.hpp index dcdffdcf..dbf5d651 100644 --- a/nano/node/node.hpp +++ b/nano/node/node.hpp @@ -20,8 +20,6 @@ #include #include #include -#include -#include #include #include #include @@ -156,7 +154,6 @@ public: nano::unchecked_map unchecked; std::unique_ptr wallets_store_impl; nano::wallets_store & wallets_store; - nano::gap_cache gap_cache; nano::ledger ledger; nano::outbound_bandwidth_limiter outbound_limiter; nano::network network; @@ -195,7 +192,6 @@ public: nano::epoch_upgrader epoch_upgrader; nano::block_broadcast block_broadcast; nano::block_publisher block_publisher; - nano::gap_tracker gap_tracker; nano::process_live_dispatcher process_live_dispatcher; std::chrono::steady_clock::time_point const startup_time;