diff --git a/ci/actions/deploy.sh b/ci/actions/deploy.sh index e203ed034b..7d0fc51bba 100755 --- a/ci/actions/deploy.sh +++ b/ci/actions/deploy.sh @@ -12,7 +12,11 @@ else fi if [[ "$OS" == 'Linux' ]]; then + sha256sum $GITHUB_WORKSPACE/build/nano-node-*-Linux.tar.bz2 | cut -f1 -d' ' > $GITHUB_WORKSPACE/build/nano-node-$TAG-Linux.tar.bz2.sha256 aws s3 cp $GITHUB_WORKSPACE/build/nano-node-*-Linux.tar.bz2 s3://repo.nano.org/$BUILD/binaries/nano-node-$TAG-Linux.tar.bz2 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers + aws s3 cp $GITHUB_WORKSPACE/build/nano-node-$TAG-Linux.tar.bz2.sha256 s3://repo.nano.org/$BUILD/binaries/nano-node-$TAG-Linux.tar.bz2.sha256 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers else + sha256sum $GITHUB_WORKSPACE/build/nano-node-*-Darwin.dmg | cut -f1 -d' ' > $GITHUB_WORKSPACE/build/nano-node-$TAG-Darwin.dmg.sha256 aws s3 cp $GITHUB_WORKSPACE/build/nano-node-*-Darwin.dmg s3://repo.nano.org/$BUILD/binaries/nano-node-$TAG-Darwin.dmg --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers + aws s3 cp $GITHUB_WORKSPACE/build/nano-node-$TAG-Darwin.dmg.sha256 s3://repo.nano.org/$BUILD/binaries/nano-node-$TAG-Darwin.dmg.sha256 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers fi diff --git a/ci/actions/windows/build.ps1 b/ci/actions/windows/build.ps1 index 9fe4dc7d47..5868c9b4c6 100644 --- a/ci/actions/windows/build.ps1 +++ b/ci/actions/windows/build.ps1 @@ -4,7 +4,8 @@ if (${env:artifact} -eq 1) { if ( ${env:BETA} -eq 1 ) { $env:NETWORK_CFG = "beta" $env:BUILD_TYPE = "RelWithDebInfo" - } else { + } + else { $env:NETWORK_CFG = "live" $env:BUILD_TYPE = "Release" } @@ -14,11 +15,13 @@ if (${env:artifact} -eq 1) { $env:CI = "-DCI_BUILD=ON" $env:RUN = "artifact" -} else { +} +else { if ( ${env:RELEASE} -eq 1 ) { $env:BUILD_TYPE = "RelWithDebInfo" $env:ROCKS_LIB = '-DROCKSDB_LIBRARIES="c:\vcpkg\installed\x64-windows-static\lib\rocksdb.lib"' - } else { + } + else { $env:BUILD_TYPE = "Debug" $env:ROCKS_LIB = '-DROCKSDB_LIBRARIES="c:\vcpkg\installed\x64-windows-static\debug\lib\rocksdbd.lib"' } diff --git a/ci/actions/windows/deploy.ps1 b/ci/actions/windows/deploy.ps1 index 2e766bf23d..0dbfa460a4 100644 --- a/ci/actions/windows/deploy.ps1 +++ b/ci/actions/windows/deploy.ps1 @@ -1,12 +1,19 @@ $ErrorActionPreference = "Continue" if ( ${env:BETA} -eq 1 ) { - $network_cfg="beta" -} else { - $network_cfg="live" + $network_cfg = "beta" } +else { + $network_cfg = "live" +} + +$exe = Resolve-Path -Path $env:GITHUB_WORKSPACE\build\nano-node-*-win64.exe +$zip = Resolve-Path -Path $env:GITHUB_WORKSPACE\build\nano-node-*-win64.zip + +(Get-FileHash $exe).hash | Out-file -FilePath "$exe.sh256" +(Get-FileHash $zip).hash | Out-file -FilePath "$zip.sh256" -$exe=Resolve-Path -Path $env:GITHUB_WORKSPACE\build\nano-node-*-win64.exe -$zip=Resolve-Path -Path $env:GITHUB_WORKSPACE\build\nano-node-*-win64.zip aws s3 cp $exe s3://repo.nano.org/$network_cfg/binaries/nano-node-$env:TAG-win64.exe --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers -aws s3 cp "$zip" s3://repo.nano.org/$network_cfg/binaries/nano-node-$env:TAG-win64.zip --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers \ No newline at end of file +aws s3 cp "$exe.sha256" s3://repo.nano.org/$network_cfg/binaries/nano-node-$env:TAG-win64.exe.sha256 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers +aws s3 cp "$zip" s3://repo.nano.org/$network_cfg/binaries/nano-node-$env:TAG-win64.zip --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers +aws s3 cp "$zip.sha256" s3://repo.nano.org/$network_cfg/binaries/nano-node-$env:TAG-win64.zip.sha256 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers \ No newline at end of file diff --git a/nano/core_test/network.cpp b/nano/core_test/network.cpp index c773b7cfb9..92535152b0 100644 --- a/nano/core_test/network.cpp +++ b/nano/core_test/network.cpp @@ -927,6 +927,25 @@ TEST (network, replace_port) node1->stop (); } +TEST (network, peer_max_tcp_attempts) +{ + nano::system system (1); + auto node (system.nodes[0]); + // Add nodes that can accept TCP connection, but not node ID handshake + nano::node_flags node_flags; + node_flags.disable_tcp_realtime = true; + for (auto i (0); i < node->network_params.node.max_peers_per_ip; ++i) + { + auto node2 (std::make_shared (system.io_ctx, nano::get_available_port (), nano::unique_path (), system.alarm, system.logging, system.work, node_flags)); + node2->start (); + system.nodes.push_back (node2); + // Start TCP attempt + node->network.merge_peer (node2->network.endpoint ()); + } + ASSERT_EQ (0, node->network.size ()); + ASSERT_TRUE (node->network.tcp_channels.reachout (nano::endpoint (node->network.endpoint ().address (), nano::get_available_port ()))); +} + TEST (network, duplicate_detection) { nano::system system; diff --git a/nano/core_test/node.cpp b/nano/core_test/node.cpp index ee9d35b177..ca2511b499 100644 --- a/nano/core_test/node.cpp +++ b/nano/core_test/node.cpp @@ -3588,7 +3588,7 @@ TEST (node, bandwidth_limiter) nano::publish message (genesis.open); auto message_size = message.to_bytes ()->size (); auto message_limit = 4; // must be multiple of the number of channels - nano::node_config node_config (24000, system.logging); + nano::node_config node_config (nano::get_available_port (), system.logging); node_config.bandwidth_limit = message_limit * message_size; auto & node = *system.add_node (node_config); auto channel1 (node.network.udp_channels.create (node.network.endpoint ())); diff --git a/nano/core_test/request_aggregator.cpp b/nano/core_test/request_aggregator.cpp index 819dd04354..8043c6d272 100644 --- a/nano/core_test/request_aggregator.cpp +++ b/nano/core_test/request_aggregator.cpp @@ -52,7 +52,7 @@ TEST (request_aggregator, one) ASSERT_EQ (1, node.stats.count (nano::stat::type::requests, nano::stat::detail::requests_unknown)); ASSERT_EQ (1, node.stats.count (nano::stat::type::requests, nano::stat::detail::requests_generated_votes)); ASSERT_EQ (1, node.stats.count (nano::stat::type::requests, nano::stat::detail::requests_cached_votes)); - ASSERT_EQ (2, node.stats.count (nano::stat::type::message, nano::stat::detail::confirm_ack, nano::stat::dir::out)); + ASSERT_TIMELY (3s, node.stats.count (nano::stat::type::message, nano::stat::detail::confirm_ack, nano::stat::dir::out) == 2); } TEST (request_aggregator, one_update) @@ -91,7 +91,7 @@ TEST (request_aggregator, one_update) ASSERT_EQ (1, node.stats.count (nano::stat::type::requests, nano::stat::detail::requests_generated_votes)); ASSERT_EQ (0, node.stats.count (nano::stat::type::requests, nano::stat::detail::requests_cached_hashes)); ASSERT_EQ (0, node.stats.count (nano::stat::type::requests, nano::stat::detail::requests_cached_votes)); - ASSERT_EQ (1, node.stats.count (nano::stat::type::message, nano::stat::detail::confirm_ack, nano::stat::dir::out)); + ASSERT_TIMELY (3s, node.stats.count (nano::stat::type::message, nano::stat::detail::confirm_ack, nano::stat::dir::out) == 1); } TEST (request_aggregator, two) @@ -136,7 +136,7 @@ TEST (request_aggregator, two) ASSERT_EQ (1, node.stats.count (nano::stat::type::requests, nano::stat::detail::requests_generated_votes)); ASSERT_EQ (2, node.stats.count (nano::stat::type::requests, nano::stat::detail::requests_cached_hashes)); ASSERT_EQ (1, node.stats.count (nano::stat::type::requests, nano::stat::detail::requests_cached_votes)); - ASSERT_EQ (2, node.stats.count (nano::stat::type::message, nano::stat::detail::confirm_ack, nano::stat::dir::out)); + ASSERT_TIMELY (3s, node.stats.count (nano::stat::type::message, nano::stat::detail::confirm_ack, nano::stat::dir::out) == 2); // Make sure the cached vote is for both hashes auto vote1 (node.votes_cache.find (send1->hash ())); auto vote2 (node.votes_cache.find (send2->hash ())); @@ -231,7 +231,7 @@ TEST (request_aggregator, split) ASSERT_EQ (2, node.stats.count (nano::stat::type::requests, nano::stat::detail::requests_generated_votes)); ASSERT_EQ (0, node.stats.count (nano::stat::type::requests, nano::stat::detail::requests_unknown)); ASSERT_EQ (0, node.stats.count (nano::stat::type::requests, nano::stat::detail::requests_cached_hashes)); - ASSERT_EQ (2, node.stats.count (nano::stat::type::message, nano::stat::detail::confirm_ack, nano::stat::dir::out)); + ASSERT_TIMELY (3s, node.stats.count (nano::stat::type::message, nano::stat::detail::confirm_ack, nano::stat::dir::out) == 2); } TEST (request_aggregator, channel_lifetime) diff --git a/nano/core_test/socket.cpp b/nano/core_test/socket.cpp index 3ac1971cb4..cc54d11cee 100644 --- a/nano/core_test/socket.cpp +++ b/nano/core_test/socket.cpp @@ -11,7 +11,7 @@ TEST (socket, drop_policy) { auto node_flags = nano::inactive_node_flag_defaults (); node_flags.read_only = false; - nano::inactive_node inactivenode (nano::unique_path (), nano::get_available_port (), node_flags); + nano::inactive_node inactivenode (nano::unique_path (), node_flags); auto node = inactivenode.node; nano::thread_runner runner (node->io_ctx, 1); @@ -61,7 +61,7 @@ TEST (socket, concurrent_writes) { auto node_flags = nano::inactive_node_flag_defaults (); node_flags.read_only = false; - nano::inactive_node inactivenode (nano::unique_path (), nano::get_available_port (), node_flags); + nano::inactive_node inactivenode (nano::unique_path (), node_flags); auto node = inactivenode.node; // This gives more realistic execution than using system#poll, allowing writes to diff --git a/nano/core_test/wallets.cpp b/nano/core_test/wallets.cpp index ccb856e056..5d9ec86ca2 100644 --- a/nano/core_test/wallets.cpp +++ b/nano/core_test/wallets.cpp @@ -160,7 +160,7 @@ TEST (wallets, reload) ASSERT_EQ (1, node1.wallets.items.size ()); { nano::lock_guard lock_wallet (node1.wallets.mutex); - nano::inactive_node node (node1.application_path, nano::get_available_port ()); + nano::inactive_node node (node1.application_path); auto wallet (node.node->wallets.create (one)); ASSERT_NE (wallet, nullptr); } diff --git a/nano/lib/utility.cpp b/nano/lib/utility.cpp index d62865a1f2..fd71e43946 100644 --- a/nano/lib/utility.cpp +++ b/nano/lib/utility.cpp @@ -110,17 +110,11 @@ void nano::move_all_files_to_dir (boost::filesystem::path const & from, boost::f */ void assert_internal (const char * check_expr, const char * file, unsigned int line, bool is_release_assert) { - // Output stack trace + std::cerr << "Assertion (" << check_expr << ") failed " << file << ":" << line << "\n\n"; + + // Output stack trace to cerr auto backtrace_str = nano::generate_stacktrace (); - // Windows on Actions only outputs the first line of the stacktrace from standard error, use standard output -#if (defined(_WIN32) && CI) - std::cout << backtrace_str << std::endl; -#else std::cerr << backtrace_str << std::endl; -#endif - - std::cerr << "Assertion (" << check_expr << ") failed " << file << ":" << line << "\n" - << std::endl; // "abort" at the end of this function will go into any signal handlers (the daemon ones will generate a stack trace and load memory address files on non-Windows systems). // As there is no async-signal-safe way to generate stacktraces on Windows it must be done before aborting diff --git a/nano/nano_node/entry.cpp b/nano/nano_node/entry.cpp index e30c01cd00..ea0ef373b2 100644 --- a/nano/nano_node/entry.cpp +++ b/nano/nano_node/entry.cpp @@ -159,9 +159,10 @@ int main (int argc, char * const * argv) } else if (vm.count ("debug_block_count")) { - nano::inactive_node node (data_path); - auto transaction (node.node->store.tx_begin_read ()); - std::cout << boost::str (boost::format ("Block count: %1%\n") % node.node->store.block_count (transaction).sum ()); + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; + auto transaction (node->store.tx_begin_read ()); + std::cout << boost::str (boost::format ("Block count: %1%\n") % node->store.block_count (transaction).sum ()); } else if (vm.count ("debug_bootstrap_generate")) { @@ -221,11 +222,12 @@ int main (int argc, char * const * argv) } else if (vm.count ("debug_dump_online_weight")) { - nano::inactive_node node (data_path); - auto current (node.node->online_reps.online_stake ()); + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; + auto current (node->online_reps.online_stake ()); std::cout << boost::str (boost::format ("Online Weight %1%\n") % current); - auto transaction (node.node->store.tx_begin_read ()); - for (auto i (node.node->store.online_weight_begin (transaction)), n (node.node->store.online_weight_end ()); i != n; ++i) + auto transaction (node->store.tx_begin_read ()); + for (auto i (node->store.online_weight_begin (transaction)), n (node->store.online_weight_end ()); i != n; ++i) { using time_point = std::chrono::system_clock::time_point; time_point ts (std::chrono::duration_cast (std::chrono::nanoseconds (i->first))); @@ -238,11 +240,13 @@ int main (int argc, char * const * argv) else if (vm.count ("debug_dump_representatives")) { auto node_flags = nano::inactive_node_flag_defaults (); + nano::update_flags (node_flags, vm); node_flags.generate_cache.reps = true; - nano::inactive_node node (data_path, 24000, node_flags); - auto transaction (node.node->store.tx_begin_read ()); + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; + auto transaction (node->store.tx_begin_read ()); nano::uint128_t total; - auto rep_amounts = node.node->ledger.cache.rep_weights.get_rep_amounts (); + auto rep_amounts = node->ledger.cache.rep_weights.get_rep_amounts (); std::map ordered_reps (rep_amounts.begin (), rep_amounts.end ()); for (auto const & rep : ordered_reps) { @@ -252,19 +256,20 @@ int main (int argc, char * const * argv) } else if (vm.count ("debug_dump_frontier_unchecked_dependents")) { - nano::inactive_node node (data_path); + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; std::cout << "Outputting any frontier hashes which have associated key hashes in the unchecked table (may take some time)...\n"; // Cache the account heads to make searching quicker against unchecked keys. - auto transaction (node.node->store.tx_begin_read ()); + auto transaction (node->store.tx_begin_read ()); std::unordered_set frontier_hashes; - for (auto i (node.node->store.latest_begin (transaction)), n (node.node->store.latest_end ()); i != n; ++i) + for (auto i (node->store.latest_begin (transaction)), n (node->store.latest_end ()); i != n; ++i) { frontier_hashes.insert (i->second.head); } // Check all unchecked keys for matching frontier hashes. Indicates an issue with process_batch algorithm - for (auto i (node.node->store.unchecked_begin (transaction)), n (node.node->store.unchecked_end ()); i != n; ++i) + for (auto i (node->store.unchecked_begin (transaction)), n (node->store.unchecked_end ()); i != n; ++i) { auto it = frontier_hashes.find (i->first.key ()); if (it != frontier_hashes.cend ()) @@ -275,8 +280,8 @@ int main (int argc, char * const * argv) } else if (vm.count ("debug_account_count")) { - nano::inactive_node node (data_path); - std::cout << boost::str (boost::format ("Frontier count: %1%\n") % node.node->ledger.cache.account_count); + auto inactive_node = nano::default_inactive_node (data_path, vm); + std::cout << boost::str (boost::format ("Frontier count: %1%\n") % inactive_node->node->ledger.cache.account_count); } else if (vm.count ("debug_mass_activity")) { @@ -710,7 +715,7 @@ int main (int argc, char * const * argv) nano::logging logging; auto path (nano::unique_path ()); logging.init (path); - auto node_flags = nano::node_flags (); + nano::node_flags node_flags; nano::update_flags (node_flags, vm); auto node (std::make_shared (system.io_ctx, 24001, path, system.alarm, logging, work, node_flags)); nano::block_hash genesis_latest (node->latest (test_params.ledger.test_genesis_key.pub)); @@ -962,20 +967,21 @@ int main (int argc, char * const * argv) std::exit (0); }); - nano::inactive_node inactive_node_l (data_path); + auto inactive_node_l = nano::default_inactive_node (data_path, vm); nano::node_rpc_config config; - nano::ipc::ipc_server server (*inactive_node_l.node, config); - nano::json_handler handler_l (*inactive_node_l.node, config, command_l.str (), response_handler_l); + nano::ipc::ipc_server server (*inactive_node_l->node, config); + nano::json_handler handler_l (*inactive_node_l->node, config, command_l.str (), response_handler_l); handler_l.process_request (); } else if (vm.count ("debug_validate_blocks")) { - nano::inactive_node node (data_path); - auto transaction (node.node->store.tx_begin_read ()); + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; + auto transaction (node->store.tx_begin_read ()); std::cout << boost::str (boost::format ("Performing blocks hash, signature, work validation...\n")); size_t count (0); uint64_t block_count (0); - for (auto i (node.node->store.latest_begin (transaction)), n (node.node->store.latest_end ()); i != n; ++i) + for (auto i (node->store.latest_begin (transaction)), n (node->store.latest_end ()); i != n; ++i) { ++count; if ((count % 20000) == 0) @@ -985,7 +991,7 @@ int main (int argc, char * const * argv) nano::account_info const & info (i->second); nano::account const & account (i->first); nano::confirmation_height_info confirmation_height_info; - node.node->store.confirmation_height_get (transaction, account, confirmation_height_info); + node->store.confirmation_height_get (transaction, account, confirmation_height_info); if (confirmation_height_info.height > info.block_count) { @@ -994,7 +1000,7 @@ int main (int argc, char * const * argv) auto hash (info.open_block); nano::block_hash calculated_hash (0); - auto block (node.node->store.block_get (transaction, hash)); // Block data + auto block (node->store.block_get (transaction, hash)); // Block data uint64_t height (0); uint64_t previous_timestamp (0); nano::account calculated_representative (0); @@ -1046,11 +1052,11 @@ int main (int argc, char * const * argv) nano::amount prev_balance (0); if (!state_block.hashables.previous.is_zero ()) { - prev_balance = node.node->ledger.balance (transaction, state_block.hashables.previous); + prev_balance = node->ledger.balance (transaction, state_block.hashables.previous); } - if (node.node->ledger.is_epoch_link (state_block.hashables.link) && state_block.hashables.balance == prev_balance) + if (node->ledger.is_epoch_link (state_block.hashables.link) && state_block.hashables.balance == prev_balance) { - invalid = validate_message (node.node->ledger.epoch_signer (block->link ()), hash, block->block_signature ()); + invalid = validate_message (node->ledger.epoch_signer (block->link ()), hash, block->block_signature ()); } } if (invalid) @@ -1067,7 +1073,7 @@ int main (int argc, char * const * argv) } else { - auto prev_balance (node.node->ledger.balance (transaction, block->previous ())); + auto prev_balance (node->ledger.balance (transaction, block->previous ())); if (block->balance () < prev_balance) { // State send @@ -1080,7 +1086,7 @@ int main (int argc, char * const * argv) // State change block_details_error = sideband.details.is_send || sideband.details.is_receive || sideband.details.is_epoch; } - else if (block->balance () == prev_balance && node.node->ledger.is_epoch_link (block->link ())) + else if (block->balance () == prev_balance && node->ledger.is_epoch_link (block->link ())) { // State epoch block_details_error = !sideband.details.is_epoch || sideband.details.is_send || sideband.details.is_receive; @@ -1089,7 +1095,7 @@ int main (int argc, char * const * argv) { // State receive block_details_error = !sideband.details.is_receive || sideband.details.is_send || sideband.details.is_epoch; - block_details_error |= !node.node->store.source_exists (transaction, block->link ()); + block_details_error |= !node->store.source_exists (transaction, block->link ()); } } } @@ -1120,11 +1126,11 @@ int main (int argc, char * const * argv) calculated_representative = block->representative (); } // Retrieving successor block hash - hash = node.node->store.block_successor (transaction, hash); + hash = node->store.block_successor (transaction, hash); // Retrieving block data if (!hash.is_zero ()) { - block = node.node->store.block_get (transaction, hash); + block = node->store.block_get (transaction, hash); } } // Check if required block exists @@ -1150,14 +1156,14 @@ int main (int argc, char * const * argv) } std::cout << boost::str (boost::format ("%1% accounts validated\n") % count); // Validate total block count - auto ledger_block_count (node.node->store.block_count (transaction).sum ()); + auto ledger_block_count (node->store.block_count (transaction).sum ()); if (block_count != ledger_block_count) { std::cerr << boost::str (boost::format ("Incorrect total block count. Blocks validated %1%. Block count in database: %2%\n") % block_count % ledger_block_count); } // Validate pending blocks count = 0; - for (auto i (node.node->store.pending_begin (transaction)), n (node.node->store.pending_end ()); i != n; ++i) + for (auto i (node->store.pending_begin (transaction)), n (node->store.pending_end ()); i != n; ++i) { ++count; if ((count % 200000) == 0) @@ -1167,7 +1173,7 @@ int main (int argc, char * const * argv) nano::pending_key const & key (i->first); nano::pending_info const & info (i->second); // Check block existance - auto block (node.node->store.block_get_no_sideband (transaction, key.hash)); + auto block (node->store.block_get_no_sideband (transaction, key.hash)); if (block == nullptr) { std::cerr << boost::str (boost::format ("Pending block does not exist %1%\n") % key.hash.to_string ()); @@ -1178,7 +1184,7 @@ int main (int argc, char * const * argv) nano::account destination (0); if (auto state = dynamic_cast (block.get ())) { - if (node.node->ledger.is_send (transaction, *state)) + if (node->ledger.is_send (transaction, *state)) { destination = state->hashables.link; } @@ -1196,13 +1202,13 @@ int main (int argc, char * const * argv) std::cerr << boost::str (boost::format ("Incorrect destination for pending block %1%\n") % key.hash.to_string ()); } // Check if pending source is correct - auto account (node.node->ledger.account (transaction, key.hash)); + auto account (node->ledger.account (transaction, key.hash)); if (info.source != account) { std::cerr << boost::str (boost::format ("Incorrect source for pending block %1%\n") % key.hash.to_string ()); } // Check if pending amount is correct - auto amount (node.node->ledger.amount (transaction, key.hash)); + auto amount (node->ledger.amount (transaction, key.hash)); if (info.amount != amount) { std::cerr << boost::str (boost::format ("Incorrect amount for pending block %1%\n") % key.hash.to_string ()); @@ -1216,17 +1222,18 @@ int main (int argc, char * const * argv) auto node_flags = nano::inactive_node_flag_defaults (); node_flags.read_only = false; nano::update_flags (node_flags, vm); - nano::inactive_node node2 (nano::unique_path (), 24001, node_flags); + nano::inactive_node node2 (nano::unique_path (), node_flags); nano::genesis genesis; auto begin (std::chrono::high_resolution_clock::now ()); uint64_t block_count (0); size_t count (0); { - nano::inactive_node node (data_path, 24000); - auto transaction (node.node->store.tx_begin_read ()); - block_count = node.node->store.block_count (transaction).sum (); + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; + auto transaction (node->store.tx_begin_read ()); + block_count = node->store.block_count (transaction).sum (); std::cout << boost::str (boost::format ("Performing bootstrap emulation, %1% blocks in ledger...") % block_count) << std::endl; - for (auto i (node.node->store.latest_begin (transaction)), n (node.node->store.latest_end ()); i != n; ++i) + for (auto i (node->store.latest_begin (transaction)), n (node->store.latest_end ()); i != n; ++i) { nano::account const & account (i->first); nano::account_info const & info (i->second); @@ -1234,7 +1241,7 @@ int main (int argc, char * const * argv) while (!hash.is_zero ()) { // Retrieving block data - auto block (node.node->store.block_get_no_sideband (transaction, hash)); + auto block (node->store.block_get_no_sideband (transaction, hash)); if (block != nullptr) { ++count; @@ -1278,10 +1285,11 @@ int main (int argc, char * const * argv) } else if (vm.count ("debug_peers")) { - nano::inactive_node node (data_path); - auto transaction (node.node->store.tx_begin_read ()); + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; + auto transaction (node->store.tx_begin_read ()); - for (auto i (node.node->store.peers_begin (transaction)), n (node.node->store.peers_end ()); i != n; ++i) + for (auto i (node->store.peers_begin (transaction)), n (node->store.peers_end ()); i != n; ++i) { std::cout << boost::str (boost::format ("%1%\n") % nano::endpoint (boost::asio::ip::address_v6 (i->first.address_bytes ()), i->first.port ())); } @@ -1290,7 +1298,8 @@ int main (int argc, char * const * argv) { auto node_flags = nano::inactive_node_flag_defaults (); node_flags.generate_cache.cemented_count = true; - nano::inactive_node node (data_path, 24000, node_flags); + nano::update_flags (node_flags, vm); + nano::inactive_node node (data_path, node_flags); std::cout << "Total cemented block count: " << node.node->ledger.cache.cemented_count << std::endl; } else if (vm.count ("debug_stacktrace")) @@ -1306,18 +1315,19 @@ int main (int argc, char * const * argv) return 1; } #endif - nano::inactive_node node (data_path); - node.node->logger.always_log (nano::severity_level::error, "Testing system logger"); + auto inactive_node = nano::default_inactive_node (data_path, vm); + inactive_node->node->logger.always_log (nano::severity_level::error, "Testing system logger"); } else if (vm.count ("debug_account_versions")) { - nano::inactive_node node (data_path); + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; - auto transaction (node.node->store.tx_begin_read ()); + auto transaction (node->store.tx_begin_read ()); std::vector> opened_account_versions (nano::normalized_epoch (nano::epoch::max)); // Cache the accounts in a collection to make searching quicker against unchecked keys. Group by epoch - for (auto i (node.node->store.latest_begin (transaction)), n (node.node->store.latest_end ()); i != n; ++i) + for (auto i (node->store.latest_begin (transaction)), n (node->store.latest_end ()); i != n; ++i) { auto const & account (i->first); auto const & account_info (i->second); @@ -1329,7 +1339,7 @@ int main (int argc, char * const * argv) // Iterate all pending blocks and collect the highest version for each unopened account std::unordered_map> unopened_highest_pending; - for (auto i (node.node->store.pending_begin (transaction)), n (node.node->store.pending_end ()); i != n; ++i) + for (auto i (node->store.pending_begin (transaction)), n (node->store.pending_end ()); i != n; ++i) { nano::pending_key const & key (i->first); nano::pending_info const & info (i->second); diff --git a/nano/node/active_transactions.cpp b/nano/node/active_transactions.cpp index 267074986d..efcbc41103 100644 --- a/nano/node/active_transactions.cpp +++ b/nano/node/active_transactions.cpp @@ -206,7 +206,6 @@ void nano::active_transactions::block_already_cemented_callback (nano::block_has void nano::active_transactions::request_confirm (nano::unique_lock & lock_a) { debug_assert (!mutex.try_lock ()); - auto transaction_l (node.store.tx_begin_read ()); /* * Confirm frontiers when there aren't many confirmations already pending and node finished initial bootstrap * In auto mode start confirm only if node contains almost principal representative (half of required for principal weight) @@ -220,7 +219,7 @@ void nano::active_transactions::request_confirm (nano::unique_lock & if (node.config.frontiers_confirmation != nano::frontiers_confirmation_mode::disabled && bootstrap_weight_reached && probably_unconfirmed_frontiers && pending_confirmation_height_size < confirmed_frontiers_max_pending_cut_off) { lock_a.unlock (); - search_frontiers (transaction_l); + search_frontiers (node.store.tx_begin_read ()); lock_a.lock (); update_adjusted_difficulty (); // New roots sorting } diff --git a/nano/node/cli.cpp b/nano/node/cli.cpp index edb1af4ad4..12cf05b612 100644 --- a/nano/node/cli.cpp +++ b/nano/node/cli.cpp @@ -120,8 +120,11 @@ std::error_code nano::update_flags (nano::node_flags & flags_a, boost::program_o flags_a.disable_lazy_bootstrap = (vm.count ("disable_lazy_bootstrap") > 0); flags_a.disable_legacy_bootstrap = (vm.count ("disable_legacy_bootstrap") > 0); flags_a.disable_wallet_bootstrap = (vm.count ("disable_wallet_bootstrap") > 0); - flags_a.disable_bootstrap_listener = (vm.count ("disable_bootstrap_listener") > 0); - flags_a.disable_tcp_realtime = (vm.count ("disable_tcp_realtime") > 0); + if (!flags_a.inactive_node) + { + flags_a.disable_bootstrap_listener = (vm.count ("disable_bootstrap_listener") > 0); + flags_a.disable_tcp_realtime = (vm.count ("disable_tcp_realtime") > 0); + } flags_a.disable_providing_telemetry_metrics = (vm.count ("disable_providing_telemetry_metrics") > 0); if ((vm.count ("disable_udp") > 0) && (vm.count ("enable_udp") > 0)) { @@ -193,7 +196,8 @@ bool copy_database (boost::filesystem::path const & data_path, boost::program_op auto node_flags = nano::inactive_node_flag_defaults (); node_flags.read_only = !needs_to_write; - nano::inactive_node node (data_path, 24000, node_flags); + nano::update_flags (node_flags, vm); + nano::inactive_node node (data_path, node_flags); if (!node.node->init_error ()) { if (vm.count ("unchecked_clear")) @@ -253,8 +257,8 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map { password = vm["password"].as (); } - inactive_node node (data_path); - auto wallet (node.node->wallets.open (wallet_id)); + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto wallet (inactive_node->node->wallets.open (wallet_id)); if (wallet != nullptr) { auto transaction (wallet->wallets.tx_begin_write ()); @@ -438,7 +442,8 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map boost::filesystem::path data_path = vm.count ("data_path") ? boost::filesystem::path (vm["data_path"].as ()) : nano::working_path (); auto node_flags = nano::inactive_node_flag_defaults (); node_flags.read_only = false; - nano::inactive_node node (data_path, 24000, node_flags); + nano::update_flags (node_flags, vm); + nano::inactive_node node (data_path, node_flags); if (!node.node->init_error ()) { auto transaction (node.node->store.tx_begin_write ()); @@ -455,7 +460,8 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map boost::filesystem::path data_path = vm.count ("data_path") ? boost::filesystem::path (vm["data_path"].as ()) : nano::working_path (); auto node_flags = nano::inactive_node_flag_defaults (); node_flags.read_only = false; - nano::inactive_node node (data_path, 24000, node_flags); + nano::update_flags (node_flags, vm); + nano::inactive_node node (data_path, node_flags); if (!node.node->init_error ()) { auto transaction (node.node->wallets.tx_begin_write ()); @@ -472,7 +478,8 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map boost::filesystem::path data_path = vm.count ("data_path") ? boost::filesystem::path (vm["data_path"].as ()) : nano::working_path (); auto node_flags = nano::inactive_node_flag_defaults (); node_flags.read_only = false; - nano::inactive_node node (data_path, 24000, node_flags); + nano::update_flags (node_flags, vm); + nano::inactive_node node (data_path, node_flags); if (!node.node->init_error ()) { auto transaction (node.node->store.tx_begin_write ()); @@ -489,7 +496,8 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map boost::filesystem::path data_path = vm.count ("data_path") ? boost::filesystem::path (vm["data_path"].as ()) : nano::working_path (); auto node_flags = nano::inactive_node_flag_defaults (); node_flags.read_only = false; - nano::inactive_node node (data_path, 24000, node_flags); + nano::update_flags (node_flags, vm); + nano::inactive_node node (data_path, node_flags); if (!node.node->init_error ()) { auto transaction (node.node->store.tx_begin_write ()); @@ -506,7 +514,8 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map boost::filesystem::path data_path = vm.count ("data_path") ? boost::filesystem::path (vm["data_path"].as ()) : nano::working_path (); auto node_flags = nano::inactive_node_flag_defaults (); node_flags.read_only = false; - nano::inactive_node node (data_path, 24000, node_flags); + nano::update_flags (node_flags, vm); + nano::inactive_node node (data_path, node_flags); if (!node.node->init_error ()) { auto account_it = vm.find ("account"); @@ -600,7 +609,7 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map } else if (vm.count ("diagnostics")) { - inactive_node node (data_path); + auto inactive_node = nano::default_inactive_node (data_path, vm); std::cout << "Testing hash function" << std::endl; nano::raw_key key; key.data.clear (); @@ -619,7 +628,7 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map environment.dump (std::cout); std::stringstream stream; environment.dump (stream); - node.node->logger.always_log (stream.str ()); + inactive_node->node->logger.always_log (stream.str ()); } else { @@ -663,8 +672,8 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map { password = vm["password"].as (); } - inactive_node node (data_path); - auto wallet (node.node->wallets.open (wallet_id)); + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto wallet (inactive_node->node->wallets.open (wallet_id)); if (wallet != nullptr) { auto transaction (wallet->wallets.tx_begin_write ()); @@ -717,8 +726,8 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map { password = vm["password"].as (); } - inactive_node node (data_path); - auto wallet (node.node->wallets.open (wallet_id)); + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto wallet (inactive_node->node->wallets.open (wallet_id)); if (wallet != nullptr) { auto transaction (wallet->wallets.tx_begin_write ()); @@ -799,9 +808,9 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map } if (!ec) { - inactive_node node (data_path); + auto inactive_node = nano::default_inactive_node (data_path, vm); auto wallet_key = nano::random_wallet_id (); - auto wallet (node.node->wallets.create (wallet_key)); + auto wallet (inactive_node->node->wallets.create (wallet_key)); if (wallet != nullptr) { if (vm.count ("password") > 0) @@ -841,9 +850,10 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map nano::wallet_id wallet_id; if (!wallet_id.decode_hex (vm["wallet"].as ())) { - inactive_node node (data_path); - auto existing (node.node->wallets.items.find (wallet_id)); - if (existing != node.node->wallets.items.end ()) + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; + auto existing (inactive_node->node->wallets.items.find (wallet_id)); + if (existing != inactive_node->node->wallets.items.end ()) { auto transaction (existing->second->wallets.tx_begin_write ()); if (!existing->second->enter_password (transaction, password)) @@ -896,10 +906,11 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map nano::wallet_id wallet_id; if (!wallet_id.decode_hex (vm["wallet"].as ())) { - inactive_node node (data_path); - if (node.node->wallets.items.find (wallet_id) != node.node->wallets.items.end ()) + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; + if (node->wallets.items.find (wallet_id) != node->wallets.items.end ()) { - node.node->wallets.destroy (wallet_id); + node->wallets.destroy (wallet_id); } else { @@ -945,13 +956,14 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map nano::wallet_id wallet_id; if (!wallet_id.decode_hex (vm["wallet"].as ())) { - inactive_node node (data_path); - auto existing (node.node->wallets.items.find (wallet_id)); - if (existing != node.node->wallets.items.end ()) + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; + auto existing (node->wallets.items.find (wallet_id)); + if (existing != node->wallets.items.end ()) { bool valid (false); { - auto transaction (node.node->wallets.tx_begin_write ()); + auto transaction (node->wallets.tx_begin_write ()); valid = existing->second->store.valid_password (transaction); if (!valid) { @@ -987,9 +999,9 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map { bool error (true); { - nano::lock_guard lock (node.node->wallets.mutex); - auto transaction (node.node->wallets.tx_begin_write ()); - nano::wallet wallet (error, transaction, node.node->wallets, wallet_id.to_string (), contents.str ()); + nano::lock_guard lock (node->wallets.mutex); + auto transaction (node->wallets.tx_begin_write ()); + nano::wallet wallet (error, transaction, node->wallets, wallet_id.to_string (), contents.str ()); } if (error) { @@ -998,9 +1010,9 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map } else { - node.node->wallets.reload (); - nano::lock_guard lock (node.node->wallets.mutex); - release_assert (node.node->wallets.items.find (wallet_id) != node.node->wallets.items.end ()); + node->wallets.reload (); + nano::lock_guard lock (node->wallets.mutex); + release_assert (node->wallets.items.find (wallet_id) != node->wallets.items.end ()); std::cout << "Import completed\n"; } } @@ -1032,8 +1044,9 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map } else if (vm.count ("wallet_list")) { - inactive_node node (data_path); - for (auto i (node.node->wallets.items.begin ()), n (node.node->wallets.items.end ()); i != n; ++i) + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; + for (auto i (node->wallets.items.begin ()), n (node->wallets.items.end ()); i != n; ++i) { std::cout << boost::str (boost::format ("Wallet ID: %1%\n") % i->first.to_string ()); auto transaction (i->second->wallets.tx_begin_read ()); @@ -1047,12 +1060,13 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map { if (vm.count ("wallet") == 1 && vm.count ("account") == 1) { - inactive_node node (data_path); + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; nano::wallet_id wallet_id; if (!wallet_id.decode_hex (vm["wallet"].as ())) { - auto wallet (node.node->wallets.items.find (wallet_id)); - if (wallet != node.node->wallets.items.end ()) + auto wallet (node->wallets.items.find (wallet_id)); + if (wallet != node->wallets.items.end ()) { nano::account account_id; if (!account_id.decode_account (vm["account"].as ())) @@ -1100,9 +1114,10 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map nano::wallet_id wallet_id; if (!wallet_id.decode_hex (vm["wallet"].as ())) { - inactive_node node (data_path); - auto wallet (node.node->wallets.items.find (wallet_id)); - if (wallet != node.node->wallets.items.end ()) + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; + auto wallet (node->wallets.items.find (wallet_id)); + if (wallet != node->wallets.items.end ()) { auto transaction (wallet->second->wallets.tx_begin_read ()); auto representative (wallet->second->store.representative (transaction)); @@ -1138,9 +1153,10 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map nano::account account; if (!account.decode_account (vm["account"].as ())) { - inactive_node node (data_path); - auto wallet (node.node->wallets.items.find (wallet_id)); - if (wallet != node.node->wallets.items.end ()) + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; + auto wallet (node->wallets.items.find (wallet_id)); + if (wallet != node->wallets.items.end ()) { auto transaction (wallet->second->wallets.tx_begin_write ()); wallet->second->store.representative_set (transaction, account); @@ -1177,9 +1193,10 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map } else if (vm.count ("vote_dump") == 1) { - inactive_node node (data_path); - auto transaction (node.node->store.tx_begin_read ()); - for (auto i (node.node->store.vote_begin (transaction)), n (node.node->store.vote_end ()); i != n; ++i) + auto inactive_node = nano::default_inactive_node (data_path, vm); + auto node = inactive_node->node; + auto transaction (node->store.tx_begin_read ()); + for (auto i (node->store.vote_begin (transaction)), n (node->store.vote_end ()); i != n; ++i) { auto const & vote (i->second); std::cerr << boost::str (boost::format ("%1%\n") % vote->to_json ()); @@ -1193,6 +1210,13 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map return ec; } +std::unique_ptr nano::default_inactive_node (boost::filesystem::path const & path_a, boost::program_options::variables_map const & vm_a) +{ + auto node_flags = nano::inactive_node_flag_defaults (); + nano::update_flags (node_flags, vm_a); + return std::make_unique (path_a, node_flags); +} + namespace { void reset_confirmation_heights (nano::block_store & store) diff --git a/nano/node/network.cpp b/nano/node/network.cpp index 9c41f60df4..bb12834854 100644 --- a/nano/node/network.cpp +++ b/nano/node/network.cpp @@ -11,6 +11,7 @@ #include nano::network::network (nano::node & node_a, uint16_t port_a) : +syn_cookies (node_a.network_params.node.max_peers_per_ip), buffer_container (node_a.stats, nano::network::buffer_size, 4096), // 2Mb receive buffer resolver (node_a.io_ctx), limiter (node_a.config.bandwidth_limit), @@ -820,6 +821,11 @@ void nano::message_buffer_manager::stop () condition.notify_all (); } +nano::syn_cookies::syn_cookies (size_t max_cookies_per_ip_a) : +max_cookies_per_ip (max_cookies_per_ip_a) +{ +} + boost::optional nano::syn_cookies::assign (nano::endpoint const & endpoint_a) { auto ip_addr (endpoint_a.address ()); @@ -827,7 +833,7 @@ boost::optional nano::syn_cookies::assign (nano::endpoint c nano::lock_guard lock (syn_cookie_mutex); unsigned & ip_cookies = cookies_per_ip[ip_addr]; boost::optional result; - if (ip_cookies < nano::transport::max_peers_per_ip) + if (ip_cookies < max_cookies_per_ip) { if (cookies.find (endpoint_a) == cookies.end ()) { diff --git a/nano/node/network.hpp b/nano/node/network.hpp index 705c27aee2..a1c8781011 100644 --- a/nano/node/network.hpp +++ b/nano/node/network.hpp @@ -71,6 +71,7 @@ class message_buffer_manager final class syn_cookies final { public: + syn_cookies (size_t); void purge (std::chrono::steady_clock::time_point const &); // Returns boost::none if the IP is rate capped on syn cookie requests, // or if the endpoint already has a syn cookie query @@ -90,6 +91,7 @@ class syn_cookies final mutable std::mutex syn_cookie_mutex; std::unordered_map cookies; std::unordered_map cookies_per_ip; + size_t max_cookies_per_ip; }; class network final { diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 2c1602a2c3..48c0d39c17 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -1,7 +1,9 @@ +#include #include #include #include #include +#include #include #include #include @@ -1342,39 +1344,38 @@ bool nano::node::init_error () const return store.init_error () || wallets_store.init_error (); } -nano::inactive_node::inactive_node (boost::filesystem::path const & path_a, uint16_t peering_port_a, nano::node_flags const & node_flags) : -path (path_a), +nano::inactive_node::inactive_node (boost::filesystem::path const & path_a, nano::node_flags const & node_flags_a) : io_context (std::make_shared ()), alarm (*io_context), -work (1), -peering_port (peering_port_a) +work (1) { boost::system::error_code error_chmod; /* * @warning May throw a filesystem exception */ - boost::filesystem::create_directories (path); - nano::set_secure_perm_directory (path, error_chmod); - logging.max_size = std::numeric_limits::max (); - logging.init (path); - // Config overriding - nano::node_config config (peering_port, logging); - std::stringstream config_overrides_stream; - for (auto const & entry : node_flags.config_overrides) - { - config_overrides_stream << entry << std::endl; - } - config_overrides_stream << std::endl; - nano::tomlconfig toml; - toml.read (config_overrides_stream); - auto error = config.deserialize_toml (toml); + boost::filesystem::create_directories (path_a); + nano::set_secure_perm_directory (path_a, error_chmod); + nano::daemon_config daemon_config (path_a); + auto error = nano::read_node_config_toml (path_a, daemon_config, node_flags_a.config_overrides); if (error) { - std::cerr << "Error deserializing --config option" << std::endl; + std::cerr << "Error deserializing config file"; + if (!node_flags_a.config_overrides.empty ()) + { + std::cerr << " or --config option"; + } + std::cerr << "\n" + << error.get_message () << std::endl; std::exit (1); } - node = std::make_shared (*io_context, path, alarm, config, work, node_flags); + + auto & node_config = daemon_config.node; + node_config.peering_port = nano::get_available_port (); + node_config.logging.max_size = std::numeric_limits::max (); + node_config.logging.init (path_a); + + node = std::make_shared (*io_context, path_a, alarm, node_config, work, node_flags_a); node->active.stop (); } diff --git a/nano/node/node.hpp b/nano/node/node.hpp index 619646964e..36a86b56c6 100644 --- a/nano/node/node.hpp +++ b/nano/node/node.hpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -35,6 +34,7 @@ #include #include #include +#include #include #include @@ -48,7 +48,6 @@ namespace websocket { class listener; } - class node; class telemetry; class work_pool; @@ -212,14 +211,12 @@ nano::node_flags const & inactive_node_flag_defaults (); class inactive_node final { public: - inactive_node (boost::filesystem::path const & path = nano::working_path (), uint16_t = 24000, nano::node_flags const & = nano::inactive_node_flag_defaults ()); + inactive_node (boost::filesystem::path const & path_a, nano::node_flags const & node_flags_a = nano::inactive_node_flag_defaults ()); ~inactive_node (); - boost::filesystem::path path; std::shared_ptr io_context; nano::alarm alarm; - nano::logging logging; nano::work_pool work; - uint16_t peering_port; std::shared_ptr node; }; +std::unique_ptr default_inactive_node (boost::filesystem::path const &, boost::program_options::variables_map const &); } diff --git a/nano/node/nodeconfig.hpp b/nano/node/nodeconfig.hpp index dab89a6c38..2baee4d866 100644 --- a/nano/node/nodeconfig.hpp +++ b/nano/node/nodeconfig.hpp @@ -132,6 +132,7 @@ class node_flags final bool disable_block_processor_republishing{ false }; bool disable_ongoing_telemetry_requests{ false }; bool allow_bootstrap_peers_duplicates{ false }; + bool disable_max_peers_per_ip{ false }; // For testing only bool fast_bootstrap{ false }; bool read_only{ false }; nano::confirmation_height_mode confirmation_height_processor_mode{ nano::confirmation_height_mode::automatic }; diff --git a/nano/node/testing.cpp b/nano/node/testing.cpp index d4c86a268c..fa2f25bb5d 100644 --- a/nano/node/testing.cpp +++ b/nano/node/testing.cpp @@ -37,6 +37,7 @@ std::shared_ptr nano::system::add_node (nano::node_config const & no nodes.push_back (node); if (nodes.size () > 1) { + debug_assert (nodes.size () - 1 <= node->network_params.node.max_peers_per_ip); // Check that we don't start more nodes than limit for single IP address auto begin = nodes.end () - 2; for (auto i (begin), j (begin + 1), n (nodes.end ()); j != n; ++i, ++j) { diff --git a/nano/node/transport/tcp.cpp b/nano/node/transport/tcp.cpp index 450a266d6a..42d669f2da 100644 --- a/nano/node/transport/tcp.cpp +++ b/nano/node/transport/tcp.cpp @@ -116,6 +116,7 @@ bool nano::transport::tcp_channels::insert (std::shared_ptr ().erase (node_id); } channels.get ().emplace (channel_a, socket_a, bootstrap_server_a); + attempts.get ().erase (endpoint); error = false; lock.unlock (); node.network.channel_observer (channel_a); @@ -349,8 +350,16 @@ void nano::transport::tcp_channels::stop () bool nano::transport::tcp_channels::max_ip_connections (nano::tcp_endpoint const & endpoint_a) { - nano::unique_lock lock (mutex); - bool result (channels.get ().count (endpoint_a.address ()) >= nano::transport::max_peers_per_ip); + bool result (false); + if (!node.flags.disable_max_peers_per_ip) + { + nano::unique_lock lock (mutex); + result = channels.get ().count (endpoint_a.address ()) >= node.network_params.node.max_peers_per_ip; + if (!result) + { + result = attempts.get ().count (endpoint_a.address ()) >= node.network_params.node.max_peers_per_ip; + } + } return result; } @@ -396,8 +405,8 @@ void nano::transport::tcp_channels::purge (std::chrono::steady_clock::time_point auto disconnect_cutoff (channels.get ().lower_bound (cutoff_a)); channels.get ().erase (channels.get ().begin (), disconnect_cutoff); // Remove keepalive attempt tracking for attempts older than cutoff - auto attempts_cutoff (attempts.get<1> ().lower_bound (cutoff_a)); - attempts.get<1> ().erase (attempts.get<1> ().begin (), attempts_cutoff); + auto attempts_cutoff (attempts.get ().lower_bound (cutoff_a)); + attempts.get ().erase (attempts.get ().begin (), attempts_cutoff); // Cleanup any sockets which may still be existing from failed node id handshakes node_id_handshake_sockets.erase (std::remove_if (node_id_handshake_sockets.begin (), node_id_handshake_sockets.end (), [this](auto socket) { @@ -545,6 +554,7 @@ void nano::transport::tcp_channels::start_tcp (nano::endpoint const & endpoint_a if (auto socket_l = channel->socket.lock ()) { node_l->network.tcp_channels.remove_node_id_handshake_socket (socket_l); + socket_l->close (); } if (node_l->config.logging.network_node_id_handshake_logging ()) { @@ -576,6 +586,7 @@ void nano::transport::tcp_channels::start_tcp_receive_node_id (std::shared_ptrnetwork.tcp_channels.remove_node_id_handshake_socket (socket_l); + socket_l->close (); } } }; @@ -677,6 +688,10 @@ void nano::transport::tcp_channels::start_tcp_receive_node_id (std::shared_ptr)> const & callback_a) { + { + nano::lock_guard lock (mutex); + attempts.get ().erase (nano::transport::map_endpoint_to_tcp (endpoint_a)); + } if (callback_a && !node.flags.disable_udp) { auto channel_udp (node.network.udp_channels.create (endpoint_a)); diff --git a/nano/node/transport/tcp.hpp b/nano/node/transport/tcp.hpp index b71dda5a0d..6dd4738a19 100644 --- a/nano/node/transport/tcp.hpp +++ b/nano/node/transport/tcp.hpp @@ -131,6 +131,9 @@ namespace transport class last_bootstrap_attempt_tag { }; + class last_attempt_tag + { + }; class node_id_tag { }; @@ -171,10 +174,12 @@ namespace transport { public: nano::tcp_endpoint endpoint; + boost::asio::ip::address address; std::chrono::steady_clock::time_point last_attempt{ std::chrono::steady_clock::now () }; explicit tcp_endpoint_attempt (nano::tcp_endpoint const & endpoint_a) : - endpoint (endpoint_a) + endpoint (endpoint_a), + address (endpoint_a.address ()) { } }; @@ -196,9 +201,11 @@ namespace transport channels; boost::multi_index_container, mi::member>, - mi::ordered_non_unique< + mi::hashed_non_unique, + mi::member>, + mi::ordered_non_unique, mi::member>>> attempts; // clang-format on diff --git a/nano/node/transport/transport.hpp b/nano/node/transport/transport.hpp index 6de3dafbb1..6a0e7e635e 100644 --- a/nano/node/transport/transport.hpp +++ b/nano/node/transport/transport.hpp @@ -43,8 +43,6 @@ namespace transport nano::tcp_endpoint map_endpoint_to_tcp (nano::endpoint const &); // Unassigned, reserved, self bool reserved_address (nano::endpoint const &, bool = false); - // Maximum number of peers per IP - static size_t constexpr max_peers_per_ip = 10; static std::chrono::seconds constexpr syn_cookie_cutoff = std::chrono::seconds (5); enum class transport_type : uint8_t { diff --git a/nano/node/transport/udp.cpp b/nano/node/transport/udp.cpp index b2ba6896e0..4610f93690 100644 --- a/nano/node/transport/udp.cpp +++ b/nano/node/transport/udp.cpp @@ -116,6 +116,7 @@ std::shared_ptr nano::transport::udp_channels::ins { result = std::make_shared (*this, endpoint_a, network_version_a); channels.get ().insert (result); + attempts.get ().erase (endpoint_a); lock.unlock (); node.network.channel_observer (result); } @@ -638,8 +639,12 @@ std::shared_ptr nano::transport::udp_channels::create bool nano::transport::udp_channels::max_ip_connections (nano::endpoint const & endpoint_a) { - nano::unique_lock lock (mutex); - bool result (channels.get ().count (endpoint_a.address ()) >= nano::transport::max_peers_per_ip); + bool result (false); + if (!node.flags.disable_max_peers_per_ip) + { + nano::unique_lock lock (mutex); + result = channels.get ().count (endpoint_a.address ()) >= node.network_params.node.max_peers_per_ip; + } return result; } @@ -682,8 +687,8 @@ void nano::transport::udp_channels::purge (std::chrono::steady_clock::time_point auto disconnect_cutoff (channels.get ().lower_bound (cutoff_a)); channels.get ().erase (channels.get ().begin (), disconnect_cutoff); // Remove keepalive attempt tracking for attempts older than cutoff - auto attempts_cutoff (attempts.get<1> ().lower_bound (cutoff_a)); - attempts.get<1> ().erase (attempts.get<1> ().begin (), attempts_cutoff); + auto attempts_cutoff (attempts.get ().lower_bound (cutoff_a)); + attempts.get ().erase (attempts.get ().begin (), attempts_cutoff); } void nano::transport::udp_channels::ongoing_keepalive () diff --git a/nano/node/transport/udp.hpp b/nano/node/transport/udp.hpp index c201619a8a..50f0149244 100644 --- a/nano/node/transport/udp.hpp +++ b/nano/node/transport/udp.hpp @@ -124,6 +124,9 @@ namespace transport class last_bootstrap_attempt_tag { }; + class last_attempt_tag + { + }; class node_id_tag { }; @@ -191,9 +194,9 @@ namespace transport boost::multi_index_container< endpoint_attempt, mi::indexed_by< - mi::hashed_unique< + mi::hashed_unique, mi::member>, - mi::ordered_non_unique< + mi::ordered_non_unique, mi::member>>> attempts; // clang-format on diff --git a/nano/secure/common.cpp b/nano/secure/common.cpp index 4b732b4ec8..f75a57b80d 100644 --- a/nano/secure/common.cpp +++ b/nano/secure/common.cpp @@ -135,6 +135,7 @@ nano::node_constants::node_constants (nano::network_constants & network_constant peer_interval = search_pending_interval; unchecked_cleaning_interval = std::chrono::minutes (30); process_confirmed_interval = network_constants.is_test_network () ? std::chrono::milliseconds (50) : std::chrono::milliseconds (500); + max_peers_per_ip = network_constants.is_test_network () ? 10 : 5; max_weight_samples = network_constants.is_live_network () ? 4032 : 864; weight_period = 5 * 60; // 5 minutes } diff --git a/nano/secure/common.hpp b/nano/secure/common.hpp index be6e87497d..338237bccb 100644 --- a/nano/secure/common.hpp +++ b/nano/secure/common.hpp @@ -419,6 +419,8 @@ class node_constants std::chrono::seconds peer_interval; std::chrono::minutes unchecked_cleaning_interval; std::chrono::milliseconds process_confirmed_interval; + /** Maximum number of peers per IP */ + size_t max_peers_per_ip; /** The maximum amount of samples for a 2 week period on live or 3 days on beta */ uint64_t max_weight_samples; diff --git a/nano/slow_test/node.cpp b/nano/slow_test/node.cpp index 253cdd0ea6..9ee55a9509 100644 --- a/nano/slow_test/node.cpp +++ b/nano/slow_test/node.cpp @@ -187,7 +187,9 @@ TEST (store, load) // ulimit -n increasing may be required TEST (node, fork_storm) { - nano::system system (64); + nano::node_flags flags; + flags.disable_max_peers_per_ip = true; + nano::system system (64, nano::transport::transport_type::tcp, flags); system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv); auto previous (system.nodes[0]->latest (nano::test_genesis_key.pub)); auto balance (system.nodes[0]->balance (nano::test_genesis_key.pub));