From 45c3045649b92a2bf507fd1865f4b8af37ee0bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20W=C3=B3jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Sat, 30 Nov 2024 20:17:44 +0100 Subject: [PATCH] Move network_constants to a dedicated header (#4800) * Move network_constants to constants.hpp * Cleanup --- nano/lib/CMakeLists.txt | 2 + nano/lib/config.cpp | 215 +------------------------ nano/lib/config.hpp | 279 +-------------------------------- nano/lib/constants.cpp | 219 ++++++++++++++++++++++++++ nano/lib/constants.hpp | 285 ++++++++++++++++++++++++++++++++++ nano/lib/fwd.hpp | 9 +- nano/lib/rpcconfig.hpp | 1 + nano/lib/work.cpp | 1 + nano/load_test/entry.cpp | 2 +- nano/nano_node/daemon.cpp | 3 +- nano/nano_node/entry.cpp | 2 +- nano/nano_rpc/entry.cpp | 2 +- nano/nano_wallet/entry.cpp | 4 +- nano/node/ipc/ipc_config.cpp | 1 + nano/node/openclwork.hpp | 1 + nano/node/portmapping.cpp | 4 +- nano/node/websocketconfig.hpp | 2 +- nano/qt/qt.cpp | 8 +- nano/secure/common.hpp | 1 + nano/secure/utility.hpp | 1 + 20 files changed, 540 insertions(+), 502 deletions(-) create mode 100644 nano/lib/constants.cpp create mode 100644 nano/lib/constants.hpp diff --git a/nano/lib/CMakeLists.txt b/nano/lib/CMakeLists.txt index 9ef472a1b..c05152a28 100644 --- a/nano/lib/CMakeLists.txt +++ b/nano/lib/CMakeLists.txt @@ -39,6 +39,8 @@ add_library( config.hpp config.cpp configbase.hpp + constants.hpp + constants.cpp container_info.hpp container_info.cpp diagnosticsconfig.hpp diff --git a/nano/lib/config.cpp b/nano/lib/config.cpp index 41b73e510..13366a5d5 100644 --- a/nano/lib/config.cpp +++ b/nano/lib/config.cpp @@ -2,9 +2,9 @@ #include #include #include +#include #include #include -#include #include #include @@ -12,221 +12,8 @@ #include -namespace -{ -// useful for boost_lexical cast to allow conversion of hex strings -template -struct HexTo -{ - ElemT value; - - HexTo () = default; - - HexTo (ElemT val) : - value{ val } - { - } - - operator ElemT () const - { - return value; - } - - friend std::istream & operator>> (std::istream & in, HexTo & out) - { - in >> std::hex >> out.value; - return in; - } -}; -} // namespace - -nano::work_thresholds const nano::work_thresholds::publish_full ( -0xffffffc000000000, -0xfffffff800000000, // 8x higher than epoch_1 -0xfffffe0000000000 // 8x lower than epoch_1 -); - -nano::work_thresholds const nano::work_thresholds::publish_beta ( -0xfffff00000000000, // 64x lower than publish_full.epoch_1 -0xfffff00000000000, // same as epoch_1 -0xffffe00000000000 // 2x lower than epoch_1 -); - -nano::work_thresholds const nano::work_thresholds::publish_dev ( -0xfe00000000000000, // Very low for tests -0xffc0000000000000, // 8x higher than epoch_1 -0xf000000000000000 // 8x lower than epoch_1 -); - -nano::work_thresholds const nano::work_thresholds::publish_test ( // defaults to live network levels -nano::env::get> ("NANO_TEST_EPOCH_1").value_or (0xffffffc000000000), -nano::env::get> ("NANO_TEST_EPOCH_2").value_or (0xfffffff800000000), // 8x higher than epoch_1 -nano::env::get> ("NANO_TEST_EPOCH_2_RECV").value_or (0xfffffe0000000000) // 8x lower than epoch_1 -); - -uint64_t nano::work_thresholds::threshold_entry (nano::work_version const version_a, nano::block_type const type_a) const -{ - uint64_t result{ std::numeric_limits::max () }; - if (type_a == nano::block_type::state) - { - switch (version_a) - { - case nano::work_version::work_1: - result = entry; - break; - default: - debug_assert (false && "Invalid version specified to work_threshold_entry"); - } - } - else - { - result = epoch_1; - } - return result; -} - -#ifndef NANO_FUZZER_TEST -uint64_t nano::work_thresholds::value (nano::root const & root_a, uint64_t work_a) const -{ - uint64_t result; - blake2b_state hash; - blake2b_init (&hash, sizeof (result)); - blake2b_update (&hash, reinterpret_cast (&work_a), sizeof (work_a)); - blake2b_update (&hash, root_a.bytes.data (), root_a.bytes.size ()); - blake2b_final (&hash, reinterpret_cast (&result), sizeof (result)); - return result; -} -#else -uint64_t nano::work_thresholds::value (nano::root const & root_a, uint64_t work_a) const -{ - return base + 1; -} -#endif - -uint64_t nano::work_thresholds::threshold (nano::block_details const & details_a) const -{ - static_assert (nano::epoch::max == nano::epoch::epoch_2, "work_v1::threshold is ill-defined"); - - uint64_t result{ std::numeric_limits::max () }; - switch (details_a.epoch) - { - case nano::epoch::epoch_2: - result = (details_a.is_receive || details_a.is_epoch) ? epoch_2_receive : epoch_2; - break; - case nano::epoch::epoch_1: - case nano::epoch::epoch_0: - result = epoch_1; - break; - default: - debug_assert (false && "Invalid epoch specified to work_v1 ledger work_threshold"); - } - return result; -} - -uint64_t nano::work_thresholds::threshold (nano::work_version const version_a, nano::block_details const details_a) const -{ - uint64_t result{ std::numeric_limits::max () }; - switch (version_a) - { - case nano::work_version::work_1: - result = threshold (details_a); - break; - default: - debug_assert (false && "Invalid version specified to ledger work_threshold"); - } - return result; -} - -double nano::work_thresholds::normalized_multiplier (double const multiplier_a, uint64_t const threshold_a) const -{ - debug_assert (multiplier_a >= 1); - auto multiplier (multiplier_a); - /* Normalization rules - ratio = multiplier of max work threshold (send epoch 2) from given threshold - i.e. max = 0xfe00000000000000, given = 0xf000000000000000, ratio = 8.0 - normalized = (multiplier + (ratio - 1)) / ratio; - Epoch 1 - multiplier | normalized - 1.0 | 1.0 - 9.0 | 2.0 - 25.0 | 4.0 - Epoch 2 (receive / epoch subtypes) - multiplier | normalized - 1.0 | 1.0 - 65.0 | 2.0 - 241.0 | 4.0 - */ - if (threshold_a == epoch_1 || threshold_a == epoch_2_receive) - { - auto ratio (nano::difficulty::to_multiplier (epoch_2, threshold_a)); - debug_assert (ratio >= 1); - multiplier = (multiplier + (ratio - 1.0)) / ratio; - debug_assert (multiplier >= 1); - } - return multiplier; -} - -double nano::work_thresholds::denormalized_multiplier (double const multiplier_a, uint64_t const threshold_a) const -{ - debug_assert (multiplier_a >= 1); - auto multiplier (multiplier_a); - if (threshold_a == epoch_1 || threshold_a == epoch_2_receive) - { - auto ratio (nano::difficulty::to_multiplier (epoch_2, threshold_a)); - debug_assert (ratio >= 1); - multiplier = multiplier * ratio + 1.0 - ratio; - debug_assert (multiplier >= 1); - } - return multiplier; -} - -uint64_t nano::work_thresholds::threshold_base (nano::work_version const version_a) const -{ - uint64_t result{ std::numeric_limits::max () }; - switch (version_a) - { - case nano::work_version::work_1: - result = base; - break; - default: - debug_assert (false && "Invalid version specified to work_threshold_base"); - } - return result; -} - -uint64_t nano::work_thresholds::difficulty (nano::work_version const version_a, nano::root const & root_a, uint64_t const work_a) const -{ - uint64_t result{ 0 }; - switch (version_a) - { - case nano::work_version::work_1: - result = value (root_a, work_a); - break; - default: - debug_assert (false && "Invalid version specified to work_difficulty"); - } - return result; -} - -uint64_t nano::work_thresholds::difficulty (nano::block const & block_a) const -{ - return difficulty (block_a.work_version (), block_a.root (), block_a.block_work ()); -} - -bool nano::work_thresholds::validate_entry (nano::work_version const version_a, nano::root const & root_a, uint64_t const work_a) const -{ - return difficulty (version_a, root_a, work_a) < threshold_entry (version_a, nano::block_type::state); -} - -bool nano::work_thresholds::validate_entry (nano::block const & block_a) const -{ - return difficulty (block_a) < threshold_entry (block_a.work_version (), block_a.type ()); -} - namespace nano { -char const * network_constants::active_network_err_msg = "Invalid network. Valid values are live, test, beta and dev."; - uint8_t get_major_node_version () { return boost::numeric_cast (boost::lexical_cast (NANO_MAJOR_VERSION_STRING)); diff --git a/nano/lib/config.hpp b/nano/lib/config.hpp index 239f5ad8c..11edc9ab3 100644 --- a/nano/lib/config.hpp +++ b/nano/lib/config.hpp @@ -84,281 +84,7 @@ uint16_t test_rpc_port (); uint16_t test_ipc_port (); uint16_t test_websocket_port (); std::array test_magic_number (); -/// How often to scan for representatives in local wallet, in milliseconds -uint32_t test_scan_wallet_reps_delay (); - -/** - * Network variants with different genesis blocks and network parameters - */ -enum class networks : uint16_t -{ - invalid = 0x0, - // Low work parameters, publicly known genesis key, dev IP ports - nano_dev_network = 0x5241, // 'R', 'A' - // Normal work parameters, secret beta genesis key, beta IP ports - nano_beta_network = 0x5242, // 'R', 'B' - // Normal work parameters, secret live key, live IP ports - nano_live_network = 0x5243, // 'R', 'C' - // Normal work parameters, secret test genesis key, test IP ports - nano_test_network = 0x5258, // 'R', 'X' -}; - -std::string_view to_string (nano::networks); - -enum class block_type : uint8_t; -class root; -class block; -class block_details; -enum class work_version; - -class work_thresholds -{ -public: - uint64_t const epoch_1; - uint64_t const epoch_2; - uint64_t const epoch_2_receive; - - // Automatically calculated. The base threshold is the maximum of all thresholds and is used for all work multiplier calculations - uint64_t const base; - - // Automatically calculated. The entry threshold is the minimum of all thresholds and defines the required work to enter the node, but does not guarantee a block is processed - uint64_t const entry; - - constexpr work_thresholds (uint64_t epoch_1_a, uint64_t epoch_2_a, uint64_t epoch_2_receive_a) : - epoch_1 (epoch_1_a), epoch_2 (epoch_2_a), epoch_2_receive (epoch_2_receive_a), - base (std::max ({ epoch_1, epoch_2, epoch_2_receive })), - entry (std::min ({ epoch_1, epoch_2, epoch_2_receive })) - { - } - work_thresholds () = delete; - work_thresholds operator= (nano::work_thresholds const & other_a) - { - return other_a; - } - - uint64_t threshold_entry (nano::work_version const, nano::block_type const) const; - uint64_t threshold (nano::block_details const &) const; - // Ledger threshold - uint64_t threshold (nano::work_version const, nano::block_details const) const; - uint64_t threshold_base (nano::work_version const) const; - uint64_t value (nano::root const & root_a, uint64_t work_a) const; - double normalized_multiplier (double const, uint64_t const) const; - double denormalized_multiplier (double const, uint64_t const) const; - uint64_t difficulty (nano::work_version const, nano::root const &, uint64_t const) const; - uint64_t difficulty (nano::block const & block_a) const; - bool validate_entry (nano::work_version const, nano::root const &, uint64_t const) const; - bool validate_entry (nano::block const &) const; - - /** Network work thresholds. Define these inline as constexpr when moving to cpp17. */ - static nano::work_thresholds const publish_full; - static nano::work_thresholds const publish_beta; - static nano::work_thresholds const publish_dev; - static nano::work_thresholds const publish_test; -}; - -class network_constants -{ - static constexpr std::chrono::seconds default_cleanup_period = std::chrono::seconds (60); - -public: - network_constants (nano::work_thresholds & work_, nano::networks network_a) : - current_network (network_a), - work (work_), - principal_weight_factor (1000), // 0.1% A representative is classified as principal based on its weight and this factor - default_node_port (44000), - default_rpc_port (45000), - default_ipc_port (46000), - default_websocket_port (47000), - aec_loop_interval_ms (300), // Update AEC ~3 times per second - cleanup_period (default_cleanup_period), - merge_period (std::chrono::milliseconds (250)), - keepalive_period (std::chrono::seconds (15)), - idle_timeout (default_cleanup_period * 2), - silent_connection_tolerance_time (std::chrono::seconds (120)), - syn_cookie_cutoff (std::chrono::seconds (5)), - bootstrap_interval (std::chrono::seconds (15 * 60)), - ipv6_subnetwork_prefix_for_limiting (64), // Equivalent to network prefix /64. - peer_dump_interval (std::chrono::seconds (5 * 60)), - vote_broadcast_interval (15 * 1000), - block_broadcast_interval (150 * 1000) - { - if (is_live_network ()) - { - default_node_port = 7075; - default_rpc_port = 7076; - default_ipc_port = 7077; - default_websocket_port = 7078; - } - else if (is_beta_network ()) - { - default_node_port = 54000; - default_rpc_port = 55000; - default_ipc_port = 56000; - default_websocket_port = 57000; - } - else if (is_test_network ()) - { - default_node_port = test_node_port (); - default_rpc_port = test_rpc_port (); - default_ipc_port = test_ipc_port (); - default_websocket_port = test_websocket_port (); - } - else if (is_dev_network ()) - { - aec_loop_interval_ms = 20; - cleanup_period = std::chrono::seconds (1); - merge_period = std::chrono::milliseconds (10); - keepalive_period = std::chrono::seconds (1); - idle_timeout = cleanup_period * 15; - peer_dump_interval = std::chrono::seconds (1); - vote_broadcast_interval = 500ms; - block_broadcast_interval = 500ms; - telemetry_request_cooldown = 500ms; - telemetry_cache_cutoff = 2000ms; - telemetry_request_interval = 500ms; - telemetry_broadcast_interval = 500ms; - optimistic_activation_delay = 2s; - rep_crawler_normal_interval = 500ms; - rep_crawler_warmup_interval = 500ms; - } - } - - /** Error message when an invalid network is specified */ - static char const * active_network_err_msg; - - /** The network this param object represents. This may differ from the global active network; this is needed for certain --debug... commands */ - nano::networks current_network{ nano::network_constants::active_network }; - nano::work_thresholds & work; - - unsigned principal_weight_factor; - uint16_t default_node_port; - uint16_t default_rpc_port; - uint16_t default_ipc_port; - uint16_t default_websocket_port; - unsigned aec_loop_interval_ms; - - std::chrono::seconds cleanup_period; - std::chrono::milliseconds cleanup_period_half () const - { - return std::chrono::duration_cast (cleanup_period) / 2; - } - std::chrono::seconds cleanup_cutoff () const - { - return cleanup_period * 5; - } - /** How often to connect to other peers */ - std::chrono::milliseconds merge_period; - /** How often to send keepalive messages */ - std::chrono::seconds keepalive_period; - /** Default maximum idle time for a socket before it's automatically closed */ - std::chrono::seconds idle_timeout; - std::chrono::seconds silent_connection_tolerance_time; - std::chrono::seconds syn_cookie_cutoff; - std::chrono::seconds bootstrap_interval; - size_t ipv6_subnetwork_prefix_for_limiting; - std::chrono::seconds peer_dump_interval; - - /** Time to wait before rebroadcasts for active elections */ - std::chrono::milliseconds vote_broadcast_interval; - std::chrono::milliseconds block_broadcast_interval; - - /** We do not reply to telemetry requests made within cooldown period */ - std::chrono::milliseconds telemetry_request_cooldown{ 1000 * 15 }; - /** How often to request telemetry from peers */ - std::chrono::milliseconds telemetry_request_interval{ 1000 * 60 }; - /** How often to broadcast telemetry to peers */ - std::chrono::milliseconds telemetry_broadcast_interval{ 1000 * 60 }; - /** Telemetry data older than this value is considered stale */ - std::chrono::milliseconds telemetry_cache_cutoff{ 1000 * 130 }; // 2 * `telemetry_broadcast_interval` + some margin - - /** How much to delay activation of optimistic elections to avoid interfering with election scheduler */ - std::chrono::seconds optimistic_activation_delay{ 30 }; - - std::chrono::milliseconds rep_crawler_normal_interval{ 1000 * 7 }; - std::chrono::milliseconds rep_crawler_warmup_interval{ 1000 * 3 }; - - /** Returns the network this object contains values for */ - nano::networks network () const - { - return current_network; - } - - /** - * Optionally called on startup to override the global active network. - * If not called, the compile-time option will be used. - * @param network_a The new active network - */ - static void set_active_network (nano::networks network_a) - { - active_network = network_a; - } - - /** - * Optionally called on startup to override the global active network. - * If not called, the compile-time option will be used. - * @param network_a The new active network. Valid values are "live", "beta" and "dev" - */ - static bool set_active_network (std::string network_a) - { - auto error{ false }; - if (network_a == "live") - { - active_network = nano::networks::nano_live_network; - } - else if (network_a == "beta") - { - active_network = nano::networks::nano_beta_network; - } - else if (network_a == "dev") - { - active_network = nano::networks::nano_dev_network; - } - else if (network_a == "test") - { - active_network = nano::networks::nano_test_network; - } - else - { - error = true; - } - return error; - } - - char const * get_current_network_as_string () - { - return is_live_network () ? "live" : is_beta_network () ? "beta" - : is_test_network () ? "test" - : "dev"; - } - - bool is_live_network () const - { - return current_network == nano::networks::nano_live_network; - } - bool is_beta_network () const - { - return current_network == nano::networks::nano_beta_network; - } - bool is_dev_network () const - { - return current_network == nano::networks::nano_dev_network; - } - bool is_test_network () const - { - return current_network == nano::networks::nano_test_network; - } - - /** Initial value is ACTIVE_NETWORK compile flag, but can be overridden by a CLI flag */ - static nano::networks active_network; - - /** Current protocol version */ - uint8_t const protocol_version = 0x15; - /** Minimum accepted protocol version */ - uint8_t const protocol_version_min = 0x14; - - /** Minimum accepted protocol version used when bootstrapping */ - uint8_t const bootstrap_protocol_version_min = 0x14; -}; +uint32_t test_scan_wallet_reps_delay (); // How often to scan for representatives in local wallet, in milliseconds std::string get_node_toml_config_path (std::filesystem::path const & data_path); std::string get_rpc_toml_config_path (std::filesystem::path const & data_path); @@ -379,7 +105,10 @@ bool slow_instrumentation (); /** Set the active network to the dev network */ void force_nano_dev_network (); +} +namespace nano +{ /** * Attempt to read a configuration file from specified directory. Returns empty tomlconfig if nothing is found. * @throws std::runtime_error with error code if the file or overrides are not valid toml diff --git a/nano/lib/constants.cpp b/nano/lib/constants.cpp new file mode 100644 index 000000000..f32bbafd7 --- /dev/null +++ b/nano/lib/constants.cpp @@ -0,0 +1,219 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ +// useful for boost_lexical cast to allow conversion of hex strings +template +struct HexTo +{ + ElemT value; + + HexTo () = default; + + HexTo (ElemT val) : + value{ val } + { + } + + operator ElemT () const + { + return value; + } + + friend std::istream & operator>> (std::istream & in, HexTo & out) + { + in >> std::hex >> out.value; + return in; + } +}; +} + +nano::work_thresholds const nano::work_thresholds::publish_full ( +0xffffffc000000000, +0xfffffff800000000, // 8x higher than epoch_1 +0xfffffe0000000000 // 8x lower than epoch_1 +); + +nano::work_thresholds const nano::work_thresholds::publish_beta ( +0xfffff00000000000, // 64x lower than publish_full.epoch_1 +0xfffff00000000000, // same as epoch_1 +0xffffe00000000000 // 2x lower than epoch_1 +); + +nano::work_thresholds const nano::work_thresholds::publish_dev ( +0xfe00000000000000, // Very low for tests +0xffc0000000000000, // 8x higher than epoch_1 +0xf000000000000000 // 8x lower than epoch_1 +); + +nano::work_thresholds const nano::work_thresholds::publish_test ( // defaults to live network levels +nano::env::get> ("NANO_TEST_EPOCH_1").value_or (0xffffffc000000000), +nano::env::get> ("NANO_TEST_EPOCH_2").value_or (0xfffffff800000000), // 8x higher than epoch_1 +nano::env::get> ("NANO_TEST_EPOCH_2_RECV").value_or (0xfffffe0000000000) // 8x lower than epoch_1 +); + +uint64_t nano::work_thresholds::threshold_entry (nano::work_version const version_a, nano::block_type const type_a) const +{ + uint64_t result{ std::numeric_limits::max () }; + if (type_a == nano::block_type::state) + { + switch (version_a) + { + case nano::work_version::work_1: + result = entry; + break; + default: + debug_assert (false && "Invalid version specified to work_threshold_entry"); + } + } + else + { + result = epoch_1; + } + return result; +} + +#ifndef NANO_FUZZER_TEST +uint64_t nano::work_thresholds::value (nano::root const & root_a, uint64_t work_a) const +{ + uint64_t result; + blake2b_state hash; + blake2b_init (&hash, sizeof (result)); + blake2b_update (&hash, reinterpret_cast (&work_a), sizeof (work_a)); + blake2b_update (&hash, root_a.bytes.data (), root_a.bytes.size ()); + blake2b_final (&hash, reinterpret_cast (&result), sizeof (result)); + return result; +} +#else +uint64_t nano::work_thresholds::value (nano::root const & root_a, uint64_t work_a) const +{ + return base + 1; +} +#endif + +uint64_t nano::work_thresholds::threshold (nano::block_details const & details_a) const +{ + static_assert (nano::epoch::max == nano::epoch::epoch_2, "work_v1::threshold is ill-defined"); + + uint64_t result{ std::numeric_limits::max () }; + switch (details_a.epoch) + { + case nano::epoch::epoch_2: + result = (details_a.is_receive || details_a.is_epoch) ? epoch_2_receive : epoch_2; + break; + case nano::epoch::epoch_1: + case nano::epoch::epoch_0: + result = epoch_1; + break; + default: + debug_assert (false && "Invalid epoch specified to work_v1 ledger work_threshold"); + } + return result; +} + +uint64_t nano::work_thresholds::threshold (nano::work_version const version_a, nano::block_details const details_a) const +{ + uint64_t result{ std::numeric_limits::max () }; + switch (version_a) + { + case nano::work_version::work_1: + result = threshold (details_a); + break; + default: + debug_assert (false && "Invalid version specified to ledger work_threshold"); + } + return result; +} + +double nano::work_thresholds::normalized_multiplier (double const multiplier_a, uint64_t const threshold_a) const +{ + debug_assert (multiplier_a >= 1); + auto multiplier (multiplier_a); + /* Normalization rules + ratio = multiplier of max work threshold (send epoch 2) from given threshold + i.e. max = 0xfe00000000000000, given = 0xf000000000000000, ratio = 8.0 + normalized = (multiplier + (ratio - 1)) / ratio; + Epoch 1 + multiplier | normalized + 1.0 | 1.0 + 9.0 | 2.0 + 25.0 | 4.0 + Epoch 2 (receive / epoch subtypes) + multiplier | normalized + 1.0 | 1.0 + 65.0 | 2.0 + 241.0 | 4.0 + */ + if (threshold_a == epoch_1 || threshold_a == epoch_2_receive) + { + auto ratio (nano::difficulty::to_multiplier (epoch_2, threshold_a)); + debug_assert (ratio >= 1); + multiplier = (multiplier + (ratio - 1.0)) / ratio; + debug_assert (multiplier >= 1); + } + return multiplier; +} + +double nano::work_thresholds::denormalized_multiplier (double const multiplier_a, uint64_t const threshold_a) const +{ + debug_assert (multiplier_a >= 1); + auto multiplier (multiplier_a); + if (threshold_a == epoch_1 || threshold_a == epoch_2_receive) + { + auto ratio (nano::difficulty::to_multiplier (epoch_2, threshold_a)); + debug_assert (ratio >= 1); + multiplier = multiplier * ratio + 1.0 - ratio; + debug_assert (multiplier >= 1); + } + return multiplier; +} + +uint64_t nano::work_thresholds::threshold_base (nano::work_version const version_a) const +{ + uint64_t result{ std::numeric_limits::max () }; + switch (version_a) + { + case nano::work_version::work_1: + result = base; + break; + default: + debug_assert (false && "Invalid version specified to work_threshold_base"); + } + return result; +} + +uint64_t nano::work_thresholds::difficulty (nano::work_version const version_a, nano::root const & root_a, uint64_t const work_a) const +{ + uint64_t result{ 0 }; + switch (version_a) + { + case nano::work_version::work_1: + result = value (root_a, work_a); + break; + default: + debug_assert (false && "Invalid version specified to work_difficulty"); + } + return result; +} + +uint64_t nano::work_thresholds::difficulty (nano::block const & block_a) const +{ + return difficulty (block_a.work_version (), block_a.root (), block_a.block_work ()); +} + +bool nano::work_thresholds::validate_entry (nano::work_version const version_a, nano::root const & root_a, uint64_t const work_a) const +{ + return difficulty (version_a, root_a, work_a) < threshold_entry (version_a, nano::block_type::state); +} + +bool nano::work_thresholds::validate_entry (nano::block const & block_a) const +{ + return difficulty (block_a) < threshold_entry (block_a.work_version (), block_a.type ()); +} \ No newline at end of file diff --git a/nano/lib/constants.hpp b/nano/lib/constants.hpp new file mode 100644 index 000000000..f58438bd1 --- /dev/null +++ b/nano/lib/constants.hpp @@ -0,0 +1,285 @@ +#pragma once + +#include +#include + +#include +#include + +namespace nano +{ +/** + * Network variants with different genesis blocks and network parameters + */ +enum class networks : uint16_t +{ + invalid = 0x0, + // Low work parameters, publicly known genesis key, dev IP ports + nano_dev_network = 0x5241, // 'R', 'A' + // Normal work parameters, secret beta genesis key, beta IP ports + nano_beta_network = 0x5242, // 'R', 'B' + // Normal work parameters, secret live key, live IP ports + nano_live_network = 0x5243, // 'R', 'C' + // Normal work parameters, secret test genesis key, test IP ports + nano_test_network = 0x5258, // 'R', 'X' +}; + +std::string_view to_string (nano::networks); + +class work_thresholds +{ +public: + uint64_t const epoch_1; + uint64_t const epoch_2; + uint64_t const epoch_2_receive; + + // Automatically calculated. The base threshold is the maximum of all thresholds and is used for all work multiplier calculations + uint64_t const base; + + // Automatically calculated. The entry threshold is the minimum of all thresholds and defines the required work to enter the node, but does not guarantee a block is processed + uint64_t const entry; + + constexpr work_thresholds (uint64_t epoch_1_a, uint64_t epoch_2_a, uint64_t epoch_2_receive_a) : + epoch_1 (epoch_1_a), epoch_2 (epoch_2_a), epoch_2_receive (epoch_2_receive_a), + base (std::max ({ epoch_1, epoch_2, epoch_2_receive })), + entry (std::min ({ epoch_1, epoch_2, epoch_2_receive })) + { + } + work_thresholds () = delete; + work_thresholds operator= (nano::work_thresholds const & other_a) + { + return other_a; + } + + uint64_t threshold_entry (nano::work_version const, nano::block_type const) const; + uint64_t threshold (nano::block_details const &) const; + // Ledger threshold + uint64_t threshold (nano::work_version const, nano::block_details const) const; + uint64_t threshold_base (nano::work_version const) const; + uint64_t value (nano::root const & root_a, uint64_t work_a) const; + double normalized_multiplier (double const, uint64_t const) const; + double denormalized_multiplier (double const, uint64_t const) const; + uint64_t difficulty (nano::work_version const, nano::root const &, uint64_t const) const; + uint64_t difficulty (nano::block const & block_a) const; + bool validate_entry (nano::work_version const, nano::root const &, uint64_t const) const; + bool validate_entry (nano::block const &) const; + + /** Network work thresholds. Define these inline as constexpr when moving to cpp17. */ + static nano::work_thresholds const publish_full; + static nano::work_thresholds const publish_beta; + static nano::work_thresholds const publish_dev; + static nano::work_thresholds const publish_test; +}; + +class network_constants +{ + static constexpr std::chrono::seconds default_cleanup_period = std::chrono::seconds (60); + +public: + network_constants (nano::work_thresholds & work_, nano::networks network_a) : + current_network (network_a), + work (work_), + principal_weight_factor (1000), // 0.1% A representative is classified as principal based on its weight and this factor + default_node_port (44000), + default_rpc_port (45000), + default_ipc_port (46000), + default_websocket_port (47000), + aec_loop_interval_ms (300), // Update AEC ~3 times per second + cleanup_period (default_cleanup_period), + merge_period (std::chrono::milliseconds (250)), + keepalive_period (std::chrono::seconds (15)), + idle_timeout (default_cleanup_period * 2), + silent_connection_tolerance_time (std::chrono::seconds (120)), + syn_cookie_cutoff (std::chrono::seconds (5)), + bootstrap_interval (std::chrono::seconds (15 * 60)), + ipv6_subnetwork_prefix_for_limiting (64), // Equivalent to network prefix /64. + peer_dump_interval (std::chrono::seconds (5 * 60)), + vote_broadcast_interval (15 * 1000), + block_broadcast_interval (150 * 1000) + { + if (is_live_network ()) + { + default_node_port = 7075; + default_rpc_port = 7076; + default_ipc_port = 7077; + default_websocket_port = 7078; + } + else if (is_beta_network ()) + { + default_node_port = 54000; + default_rpc_port = 55000; + default_ipc_port = 56000; + default_websocket_port = 57000; + } + else if (is_test_network ()) + { + default_node_port = test_node_port (); + default_rpc_port = test_rpc_port (); + default_ipc_port = test_ipc_port (); + default_websocket_port = test_websocket_port (); + } + else if (is_dev_network ()) + { + aec_loop_interval_ms = 20; + cleanup_period = std::chrono::seconds (1); + merge_period = std::chrono::milliseconds (10); + keepalive_period = std::chrono::seconds (1); + idle_timeout = cleanup_period * 15; + peer_dump_interval = std::chrono::seconds (1); + vote_broadcast_interval = 500ms; + block_broadcast_interval = 500ms; + telemetry_request_cooldown = 500ms; + telemetry_cache_cutoff = 2000ms; + telemetry_request_interval = 500ms; + telemetry_broadcast_interval = 500ms; + optimistic_activation_delay = 2s; + rep_crawler_normal_interval = 500ms; + rep_crawler_warmup_interval = 500ms; + } + } + + /** The network this param object represents. This may differ from the global active network; this is needed for certain --debug... commands */ + nano::networks current_network{ nano::network_constants::active_network }; + nano::work_thresholds & work; + + unsigned principal_weight_factor; + uint16_t default_node_port; + uint16_t default_rpc_port; + uint16_t default_ipc_port; + uint16_t default_websocket_port; + unsigned aec_loop_interval_ms; + + std::chrono::seconds cleanup_period; + std::chrono::milliseconds cleanup_period_half () const + { + return std::chrono::duration_cast (cleanup_period) / 2; + } + std::chrono::seconds cleanup_cutoff () const + { + return cleanup_period * 5; + } + /** How often to connect to other peers */ + std::chrono::milliseconds merge_period; + /** How often to send keepalive messages */ + std::chrono::seconds keepalive_period; + /** Default maximum idle time for a socket before it's automatically closed */ + std::chrono::seconds idle_timeout; + std::chrono::seconds silent_connection_tolerance_time; + std::chrono::seconds syn_cookie_cutoff; + std::chrono::seconds bootstrap_interval; + size_t ipv6_subnetwork_prefix_for_limiting; + std::chrono::seconds peer_dump_interval; + + /** Time to wait before rebroadcasts for active elections */ + std::chrono::milliseconds vote_broadcast_interval; + std::chrono::milliseconds block_broadcast_interval; + + /** We do not reply to telemetry requests made within cooldown period */ + std::chrono::milliseconds telemetry_request_cooldown{ 1000 * 15 }; + /** How often to request telemetry from peers */ + std::chrono::milliseconds telemetry_request_interval{ 1000 * 60 }; + /** How often to broadcast telemetry to peers */ + std::chrono::milliseconds telemetry_broadcast_interval{ 1000 * 60 }; + /** Telemetry data older than this value is considered stale */ + std::chrono::milliseconds telemetry_cache_cutoff{ 1000 * 130 }; // 2 * `telemetry_broadcast_interval` + some margin + + /** How much to delay activation of optimistic elections to avoid interfering with election scheduler */ + std::chrono::seconds optimistic_activation_delay{ 30 }; + + std::chrono::milliseconds rep_crawler_normal_interval{ 1000 * 7 }; + std::chrono::milliseconds rep_crawler_warmup_interval{ 1000 * 3 }; + + /** Returns the network this object contains values for */ + nano::networks network () const + { + return current_network; + } + + /** + * Optionally called on startup to override the global active network. + * If not called, the compile-time option will be used. + * @param network_a The new active network + */ + static void set_active_network (nano::networks network_a) + { + active_network = network_a; + } + + /** + * Optionally called on startup to override the global active network. + * If not called, the compile-time option will be used. + * @param network_a The new active network. Valid values are "live", "beta" and "dev" + */ + static bool set_active_network (std::string network_a) + { + auto error{ false }; + if (network_a == "live") + { + active_network = nano::networks::nano_live_network; + } + else if (network_a == "beta") + { + active_network = nano::networks::nano_beta_network; + } + else if (network_a == "dev") + { + active_network = nano::networks::nano_dev_network; + } + else if (network_a == "test") + { + active_network = nano::networks::nano_test_network; + } + else + { + error = true; + } + return error; + } + + std::string_view get_current_network_as_string () const + { + switch (current_network) + { + case nano::networks::nano_live_network: + return "live"; + case nano::networks::nano_beta_network: + return "beta"; + case nano::networks::nano_dev_network: + return "dev"; + case nano::networks::nano_test_network: + return "test"; + case networks::invalid: + break; + } + release_assert (false, "invalid network"); + } + + bool is_live_network () const + { + return current_network == nano::networks::nano_live_network; + } + bool is_beta_network () const + { + return current_network == nano::networks::nano_beta_network; + } + bool is_dev_network () const + { + return current_network == nano::networks::nano_dev_network; + } + bool is_test_network () const + { + return current_network == nano::networks::nano_test_network; + } + + /** Initial value is ACTIVE_NETWORK compile flag, but can be overridden by a CLI flag */ + static nano::networks active_network; + + /** Current protocol version */ + uint8_t const protocol_version = 0x15; + /** Minimum accepted protocol version */ + uint8_t const protocol_version_min = 0x14; + + /** Minimum accepted protocol version used when bootstrapping */ + uint8_t const bootstrap_protocol_version_min = 0x14; +}; +} \ No newline at end of file diff --git a/nano/lib/fwd.hpp b/nano/lib/fwd.hpp index 0409d7629..ee283f224 100644 --- a/nano/lib/fwd.hpp +++ b/nano/lib/fwd.hpp @@ -4,21 +4,25 @@ #include struct uint8_char_traits; + namespace nano { class block; -enum class block_type : uint8_t; +class block_details; class block_visitor; class container_info; -enum class epoch : uint8_t; class jsonconfig; class mutable_block_visitor; class network_constants; class object_stream; +class root; class thread_pool; class tomlconfig; template class uniquer; + +enum class block_type : uint8_t; +enum class epoch : uint8_t; enum class work_version; using stream = std::basic_streambuf; @@ -26,6 +30,7 @@ using stream = std::basic_streambuf; namespace nano::stat { +enum class type; enum class detail; enum class dir; } diff --git a/nano/lib/rpcconfig.hpp b/nano/lib/rpcconfig.hpp index 230cbd197..012764cee 100644 --- a/nano/lib/rpcconfig.hpp +++ b/nano/lib/rpcconfig.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include diff --git a/nano/lib/work.cpp b/nano/lib/work.cpp index 3097bc412..1785e146f 100644 --- a/nano/lib/work.cpp +++ b/nano/lib/work.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include diff --git a/nano/load_test/entry.cpp b/nano/load_test/entry.cpp index aaf62fc0a..cf7362c9d 100644 --- a/nano/load_test/entry.cpp +++ b/nano/load_test/entry.cpp @@ -580,7 +580,7 @@ int main (int argc, char * const * argv) data_paths.push_back (std::move (data_path)); } - auto current_network = nano::dev::network_params.network.get_current_network_as_string (); + std::string current_network{ nano::dev::network_params.network.get_current_network_as_string () }; std::vector> nodes; std::vector> rpc_servers; for (auto const & data_path : data_paths) diff --git a/nano/nano_node/daemon.cpp b/nano/nano_node/daemon.cpp index 2922b729d..827575243 100644 --- a/nano/nano_node/daemon.cpp +++ b/nano/nano_node/daemon.cpp @@ -170,8 +170,7 @@ void nano::daemon::run (std::filesystem::path const & data_path, nano::node_flag throw std::runtime_error (std::string ("RPC is configured to spawn a new process however the file cannot be found at: ") + config.rpc.child_process.rpc_path); } - auto network = node->network_params.network.get_current_network_as_string (); - + std::string network{ node->network_params.network.get_current_network_as_string () }; rpc_process = std::make_unique (config.rpc.child_process.rpc_path, "--daemon", "--data_path", data_path.string (), "--network", network); } debug_assert (rpc || rpc_process); diff --git a/nano/nano_node/entry.cpp b/nano/nano_node/entry.cpp index 740916bb2..ec8add38d 100644 --- a/nano/nano_node/entry.cpp +++ b/nano/nano_node/entry.cpp @@ -173,7 +173,7 @@ int main (int argc, char * const * argv) auto err (nano::network_constants::set_active_network (network->second.as ())); if (err) { - std::cerr << nano::network_constants::active_network_err_msg << std::endl; + std::cerr << "Invalid network. Valid values are live, test, beta and dev." << std::endl; std::exit (1); } } diff --git a/nano/nano_rpc/entry.cpp b/nano/nano_rpc/entry.cpp index 3b5987933..1afb4b3c9 100644 --- a/nano/nano_rpc/entry.cpp +++ b/nano/nano_rpc/entry.cpp @@ -118,7 +118,7 @@ int main (int argc, char * const * argv) auto err (nano::network_constants::set_active_network (network->second.as ())); if (err) { - std::cerr << nano::network_constants::active_network_err_msg << std::endl; + std::cerr << "Invalid network. Valid values are live, test, beta and dev." << std::endl; std::exit (1); } } diff --git a/nano/nano_wallet/entry.cpp b/nano/nano_wallet/entry.cpp index a8ce90d34..195ac64f8 100644 --- a/nano/nano_wallet/entry.cpp +++ b/nano/nano_wallet/entry.cpp @@ -192,7 +192,7 @@ public: throw std::runtime_error (std::string ("RPC is configured to spawn a new process however the file cannot be found at: ") + config.rpc.child_process.rpc_path); } - auto network = node->network_params.network.get_current_network_as_string (); + std::string network{ node->network_params.network.get_current_network_as_string () }; rpc_process = std::make_unique (config.rpc.child_process.rpc_path, "--daemon", "--data_path", data_path.string (), "--network", network); } } @@ -281,7 +281,7 @@ int main (int argc, char * const * argv) auto err (nano::network_constants::set_active_network (network->second.as ())); if (err) { - daemon.show_error (nano::network_constants::active_network_err_msg); + daemon.show_error ("Invalid network. Valid values are live, test, beta and dev."); std::exit (1); } } diff --git a/nano/node/ipc/ipc_config.cpp b/nano/node/ipc/ipc_config.cpp index 323063976..7672615bb 100644 --- a/nano/node/ipc/ipc_config.cpp +++ b/nano/node/ipc/ipc_config.cpp @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/nano/node/openclwork.hpp b/nano/node/openclwork.hpp index c73b98844..27660f3c8 100644 --- a/nano/node/openclwork.hpp +++ b/nano/node/openclwork.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include diff --git a/nano/node/portmapping.cpp b/nano/node/portmapping.cpp index 0dd1605bd..6e5db0329 100644 --- a/nano/node/portmapping.cpp +++ b/nano/node/portmapping.cpp @@ -7,6 +7,8 @@ #include +#include + std::string nano::mapping_protocol::to_string () { std::stringstream ss; @@ -179,7 +181,7 @@ void nano::port_mapping::refresh_mapping () // We don't map the RPC port because, unless RPC authentication was added, this would almost always be a security risk for (auto & protocol : protocols | boost::adaptors::filtered ([] (auto const & p) { return p.enabled; })) { - auto upnp_description = std::string ("Nano Node (") + node.network_params.network.get_current_network_as_string () + ")"; + auto upnp_description = fmt::format ("Nano Node ({})", node.network_params.network.get_current_network_as_string ()); std::string address_str = address.to_string (); std::string lease_duration_str = std::to_string (node.network_params.portmapping.lease_duration.count ()); diff --git a/nano/node/websocketconfig.hpp b/nano/node/websocketconfig.hpp index 5dc0e6acd..9b44e4446 100644 --- a/nano/node/websocketconfig.hpp +++ b/nano/node/websocketconfig.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/nano/qt/qt.cpp b/nano/qt/qt.cpp index db6365077..b2a17b3d9 100644 --- a/nano/qt/qt.cpp +++ b/nano/qt/qt.cpp @@ -14,6 +14,8 @@ #include #include +#include + namespace { void show_line_error (QLineEdit & line) @@ -75,12 +77,14 @@ nano_qt::self_pane::self_pane (nano_qt::wallet & wallet_a, nano::account const & wallet (wallet_a) { your_account_label->setStyleSheet ("font-weight: bold;"); - std::string network = wallet.node.network_params.network.get_current_network_as_string (); + + // Capitalize the first letter + std::string network{ wallet.node.network_params.network.get_current_network_as_string () }; if (!network.empty ()) { network[0] = std::toupper (network[0]); } - version = new QLabel (boost::str (boost::format ("%1% %2% network") % NANO_VERSION_STRING % network).c_str ()); + version = new QLabel (fmt::format ("{} {} network", NANO_VERSION_STRING, network).c_str ()); self_layout->addWidget (your_account_label); self_layout->addStretch (); diff --git a/nano/secure/common.hpp b/nano/secure/common.hpp index 5fab9fe79..31ccfd45b 100644 --- a/nano/secure/common.hpp +++ b/nano/secure/common.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/nano/secure/utility.hpp b/nano/secure/utility.hpp index 90953eea0..c80f54a03 100644 --- a/nano/secure/utility.hpp +++ b/nano/secure/utility.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include