From eb5febfdf34605c14e994f46f83e853df9a34feb Mon Sep 17 00:00:00 2001 From: Guilherme Lawless Date: Wed, 19 Feb 2020 15:03:23 +0000 Subject: [PATCH] Work version concept (#2569) * Work version concept Adds nano::work_version which is passed to all work_generate and work_validate methods (except for tests, ensured with an assert). The functional changes are quite minimal, as every caller defaults to the only work version available (work_1): - RPC work_generate, work_validate and block_create can receive an optional "work_version" - The work websocket outputs the work version These changes constitute the pipeline necessary for conditional work validation. * Use nano::to_string to match the work version text --- nano/core_test/active_transactions.cpp | 4 +- nano/core_test/distributed_work.cpp | 24 ++--- nano/core_test/wallet.cpp | 2 +- nano/core_test/websocket.cpp | 1 + nano/core_test/work_pool.cpp | 4 +- nano/lib/errors.cpp | 2 + nano/lib/errors.hpp | 1 + nano/lib/work.cpp | 99 +++++++++++++++++---- nano/lib/work.hpp | 37 ++++++-- nano/nano_node/daemon.cpp | 6 +- nano/nano_node/entry.cpp | 34 +++---- nano/nano_wallet/entry.cpp | 6 +- nano/node/active_transactions.cpp | 6 +- nano/node/blockprocessor.cpp | 4 +- nano/node/bootstrap/bootstrap_bulk_pull.cpp | 2 +- nano/node/bootstrap/bootstrap_bulk_push.cpp | 2 +- nano/node/common.cpp | 6 +- nano/node/distributed_work.cpp | 10 +-- nano/node/distributed_work.hpp | 2 + nano/node/distributed_work_factory.cpp | 4 +- nano/node/distributed_work_factory.hpp | 4 +- nano/node/json_handler.cpp | 54 +++++++---- nano/node/json_handler.hpp | 1 + nano/node/node.cpp | 48 +++++++--- nano/node/node.hpp | 21 +++-- nano/node/openclwork.cpp | 8 +- nano/node/openclwork.hpp | 5 +- nano/node/wallet.cpp | 26 +++--- nano/node/wallet.hpp | 6 +- nano/node/websocket.cpp | 13 +-- nano/node/websocket.hpp | 8 +- nano/qt/qt.cpp | 8 +- nano/rpc_test/rpc.cpp | 48 +++++++++- nano/secure/ledger.cpp | 2 +- 34 files changed, 352 insertions(+), 156 deletions(-) diff --git a/nano/core_test/active_transactions.cpp b/nano/core_test/active_transactions.cpp index e157b5126..49eca4891 100644 --- a/nano/core_test/active_transactions.cpp +++ b/nano/core_test/active_transactions.cpp @@ -534,8 +534,8 @@ TEST (active_transactions, update_difficulty) ASSERT_NO_ERROR (system.poll ()); } // Update work with higher difficulty - auto work1 = node1.work_generate_blocking (send1->root (), difficulty1 + 1, boost::none); - auto work2 = node1.work_generate_blocking (send2->root (), difficulty2 + 1, boost::none); + auto work1 = node1.work_generate_blocking (send1->root (), difficulty1 + 1); + auto work2 = node1.work_generate_blocking (send2->root (), difficulty2 + 1); std::error_code ec; nano::state_block_builder builder; diff --git a/nano/core_test/distributed_work.cpp b/nano/core_test/distributed_work.cpp index 096e57c94..2f1fbe223 100644 --- a/nano/core_test/distributed_work.cpp +++ b/nano/core_test/distributed_work.cpp @@ -10,7 +10,7 @@ TEST (distributed_work, stopped) { nano::system system (1); system.nodes[0]->distributed_work.stop (); - ASSERT_TRUE (system.nodes[0]->distributed_work.make (nano::block_hash (), {}, {}, nano::network_constants::publish_test_threshold)); + ASSERT_TRUE (system.nodes[0]->distributed_work.make (nano::work_version::work_1, nano::block_hash (), {}, {}, nano::network_constants::publish_test_threshold)); } TEST (distributed_work, no_peers) @@ -25,7 +25,7 @@ TEST (distributed_work, no_peers) work = work_a; done = true; }; - ASSERT_FALSE (node->distributed_work.make (hash, node->config.work_peers, callback, node->network_params.network.publish_threshold, nano::account ())); + ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, node->config.work_peers, callback, node->network_params.network.publish_threshold, nano::account ())); system.deadline_set (5s); while (!done) { @@ -47,7 +47,7 @@ TEST (distributed_work, no_peers_disabled) nano::node_config node_config (nano::get_available_port (), system.logging); node_config.work_threads = 0; auto & node = *system.add_node (node_config); - ASSERT_TRUE (node.distributed_work.make (nano::block_hash (), node.config.work_peers, {}, nano::network_constants::publish_test_threshold)); + ASSERT_TRUE (node.distributed_work.make (nano::work_version::work_1, nano::block_hash (), node.config.work_peers, {}, nano::network_constants::publish_test_threshold)); } TEST (distributed_work, no_peers_cancel) @@ -63,7 +63,7 @@ TEST (distributed_work, no_peers_cancel) ASSERT_FALSE (work_a.is_initialized ()); done = true; }; - ASSERT_FALSE (node.distributed_work.make (hash, node.config.work_peers, callback_to_cancel, nano::difficulty::from_multiplier (1e6, node.network_params.network.publish_threshold))); + ASSERT_FALSE (node.distributed_work.make (nano::work_version::work_1, hash, node.config.work_peers, callback_to_cancel, nano::difficulty::from_multiplier (1e6, node.network_params.network.publish_threshold))); ASSERT_EQ (1, node.distributed_work.items.size ()); // cleanup should not cancel or remove an ongoing work node.distributed_work.cleanup_finished (); @@ -79,7 +79,7 @@ TEST (distributed_work, no_peers_cancel) // now using observer done = false; - ASSERT_FALSE (node.distributed_work.make (hash, node.config.work_peers, callback_to_cancel, nano::difficulty::from_multiplier (1e6, node.network_params.network.publish_threshold))); + ASSERT_FALSE (node.distributed_work.make (nano::work_version::work_1, hash, node.config.work_peers, callback_to_cancel, nano::difficulty::from_multiplier (1e6, node.network_params.network.publish_threshold))); ASSERT_EQ (1, node.distributed_work.items.size ()); node.observers.work_cancel.notify (hash); system.deadline_set (20s); @@ -103,7 +103,7 @@ TEST (distributed_work, no_peers_multi) // Test many works for the same root for (unsigned i{ 0 }; i < total; ++i) { - ASSERT_FALSE (node->distributed_work.make (hash, node->config.work_peers, callback, nano::difficulty::from_multiplier (10, node->network_params.network.publish_threshold))); + ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, node->config.work_peers, callback, nano::difficulty::from_multiplier (10, node->network_params.network.publish_threshold))); } // 1 root, and _total_ requests for that root are expected, but some may have already finished ASSERT_EQ (1, node->distributed_work.items.size ()); @@ -128,7 +128,7 @@ TEST (distributed_work, no_peers_multi) for (unsigned i{ 0 }; i < total; ++i) { nano::block_hash hash_i (i + 1); - ASSERT_FALSE (node->distributed_work.make (hash_i, node->config.work_peers, callback, node->network_params.network.publish_threshold)); + ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash_i, node->config.work_peers, callback, node->network_params.network.publish_threshold)); } // 10 roots expected with 1 work each, but some may have completed so test for some ASSERT_GT (node->distributed_work.items.size (), 5); @@ -171,7 +171,7 @@ TEST (distributed_work, peer) work_peer->start (); decltype (node->config.work_peers) peers; peers.emplace_back ("::ffff:127.0.0.1", work_peer->port ()); - ASSERT_FALSE (node->distributed_work.make (hash, peers, callback, node->network_params.network.publish_threshold, nano::account ())); + ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, callback, node->network_params.network.publish_threshold, nano::account ())); system.deadline_set (5s); while (!done) { @@ -201,7 +201,7 @@ TEST (distributed_work, peer_malicious) malicious_peer->start (); decltype (node->config.work_peers) peers; peers.emplace_back ("::ffff:127.0.0.1", malicious_peer->port ()); - ASSERT_FALSE (node->distributed_work.make (hash, peers, callback, node->network_params.network.publish_threshold, nano::account ())); + ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, callback, node->network_params.network.publish_threshold, nano::account ())); system.deadline_set (5s); while (!done) { @@ -226,7 +226,7 @@ TEST (distributed_work, peer_malicious) auto malicious_peer2 (std::make_shared (node->work, node->io_ctx, nano::get_available_port (), work_peer_type::malicious)); malicious_peer2->start (); peers[0].second = malicious_peer2->port (); - ASSERT_FALSE (node->distributed_work.make (hash, peers, nullptr, node->network_params.network.publish_threshold, nano::account ())); + ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, nullptr, node->network_params.network.publish_threshold, nano::account ())); system.deadline_set (5s); while (malicious_peer2->generations_bad < 2) { @@ -259,7 +259,7 @@ TEST (distributed_work, peer_multi) peers.emplace_back ("localhost", malicious_peer->port ()); peers.emplace_back ("localhost", slow_peer->port ()); peers.emplace_back ("localhost", good_peer->port ()); - ASSERT_FALSE (node->distributed_work.make (hash, peers, callback, node->network_params.network.publish_threshold, nano::account ())); + ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, callback, node->network_params.network.publish_threshold, nano::account ())); system.deadline_set (5s); while (!done) { @@ -298,7 +298,7 @@ TEST (distributed_work, fail_resolve) }; decltype (node->config.work_peers) peers; peers.emplace_back ("beeb.boop.123z", 0); - ASSERT_FALSE (node->distributed_work.make (hash, peers, callback, node->network_params.network.publish_threshold, nano::account ())); + ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, callback, node->network_params.network.publish_threshold, nano::account ())); system.deadline_set (5s); while (!done) { diff --git a/nano/core_test/wallet.cpp b/nano/core_test/wallet.cpp index d5ce14a06..3f7150634 100644 --- a/nano/core_test/wallet.cpp +++ b/nano/core_test/wallet.cpp @@ -1190,7 +1190,7 @@ TEST (wallet, work_watcher_generation_disabled) auto block (std::make_shared (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - nano::Mxrb_ratio, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (genesis.hash ()))); uint64_t difficulty (0); ASSERT_FALSE (nano::work_validate (*block, &difficulty)); - node.wallets.watcher->add (block); + node.wallets.watcher->add (block, nano::work_version::work_1); ASSERT_FALSE (node.process_local (block).code != nano::process_result::progress); ASSERT_TRUE (node.wallets.watcher->is_watched (block->qualified_root ())); auto multiplier = nano::difficulty::to_multiplier (difficulty, node.network_params.network.publish_threshold); diff --git a/nano/core_test/websocket.cpp b/nano/core_test/websocket.cpp index c2cb4069c..c4f313226 100644 --- a/nano/core_test/websocket.cpp +++ b/nano/core_test/websocket.cpp @@ -677,6 +677,7 @@ TEST (websocket, work) ASSERT_EQ (1, contents.count ("request")); auto & request = contents.get_child ("request"); + ASSERT_EQ (request.get ("version"), nano::to_string (nano::work_version::work_1)); ASSERT_EQ (request.get ("hash"), hash.to_string ()); ASSERT_EQ (request.get ("difficulty"), nano::to_string_hex (node1->network_params.network.publish_threshold)); ASSERT_EQ (request.get ("multiplier"), 1.0); diff --git a/nano/core_test/work_pool.cpp b/nano/core_test/work_pool.cpp index 2cd9a62cb..b52087204 100644 --- a/nano/core_test/work_pool.cpp +++ b/nano/core_test/work_pool.cpp @@ -96,8 +96,8 @@ TEST (work, opencl) if (opencl != nullptr) { // 0 threads, should add 1 for managing OpenCL - nano::work_pool pool (0, std::chrono::nanoseconds (0), [&opencl](nano::root const & root_a, uint64_t difficulty_a, std::atomic & ticket_a) { - return opencl->generate_work (root_a, difficulty_a); + nano::work_pool pool (0, std::chrono::nanoseconds (0), [&opencl](nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a, std::atomic & ticket_a) { + return opencl->generate_work (version_a, root_a, difficulty_a); }); ASSERT_NE (nullptr, pool.opencl); nano::root root; diff --git a/nano/lib/errors.cpp b/nano/lib/errors.cpp index 2ff739fbf..4a15fd4c6 100644 --- a/nano/lib/errors.cpp +++ b/nano/lib/errors.cpp @@ -144,6 +144,8 @@ std::string nano::error_rpc_messages::message (int ev) const return "Bad source"; case nano::error_rpc::bad_timeout: return "Bad timeout number"; + case nano::error_rpc::bad_work_version: + return "Bad work version"; case nano::error_rpc::block_create_balance_mismatch: return "Balance mismatch for previous block"; case nano::error_rpc::block_create_key_required: diff --git a/nano/lib/errors.hpp b/nano/lib/errors.hpp index 32535c02d..031eb1dbc 100644 --- a/nano/lib/errors.hpp +++ b/nano/lib/errors.hpp @@ -84,6 +84,7 @@ enum class error_rpc bad_representative_number, bad_source, bad_timeout, + bad_work_version, block_create_balance_mismatch, block_create_key_required, block_create_public_key_mismatch, diff --git a/nano/lib/work.cpp b/nano/lib/work.cpp index f7b55bd7f..50640b85c 100644 --- a/nano/lib/work.cpp +++ b/nano/lib/work.cpp @@ -6,24 +6,65 @@ #include -bool nano::work_validate (nano::root const & root_a, uint64_t work_a, uint64_t * difficulty_a) +std::string nano::to_string (nano::work_version const version_a) { - static nano::network_constants network_constants; - auto value (nano::work_value (root_a, work_a)); - if (difficulty_a != nullptr) + std::string result ("invalid"); + switch (version_a) { - *difficulty_a = value; + case nano::work_version::work_1: + result = "work_1"; + break; + case nano::work_version::unspecified: + result = "unspecified"; + break; } - return value < network_constants.publish_threshold; + return result; +} + +bool nano::work_validate (nano::work_version const version_a, nano::block const & block_a, uint64_t * difficulty_a) +{ + return nano::work_validate (version_a, block_a.root (), block_a.block_work (), difficulty_a); +} + +bool nano::work_validate (nano::work_version const version_a, nano::root const & root_a, uint64_t const work_a, uint64_t * difficulty_a) +{ + bool invalid (true); + switch (version_a) + { + case nano::work_version::work_1: + invalid = nano::work_v1::validate (root_a, work_a, difficulty_a); + break; + default: + assert (false && "Invalid version specified to work_validate"); + } + return invalid; } bool nano::work_validate (nano::block const & block_a, uint64_t * difficulty_a) { - return work_validate (block_a.root (), block_a.block_work (), difficulty_a); + return nano::work_validate (block_a.root (), block_a.block_work (), difficulty_a); +} + +bool nano::work_validate (nano::root const & root_a, uint64_t const work_a, uint64_t * difficulty_a) +{ + static nano::network_constants network_constants; + assert (network_constants.is_test_network ()); + return nano::work_validate (nano::work_version::work_1, root_a, work_a, difficulty_a); +} + +bool nano::work_v1::validate (nano::root const & root_a, uint64_t work_a, uint64_t * difficulty_a) +{ + static nano::network_constants network_constants; + auto work_value (value (root_a, work_a)); + if (difficulty_a != nullptr) + { + *difficulty_a = work_value; + } + return work_value < network_constants.publish_threshold; } #ifndef NANO_FUZZER_TEST -uint64_t nano::work_value (nano::root const & root_a, uint64_t work_a) +uint64_t nano::work_v1::value (nano::root const & root_a, uint64_t work_a) { uint64_t result; blake2b_state hash; @@ -34,7 +75,7 @@ uint64_t nano::work_value (nano::root const & root_a, uint64_t work_a) return result; } #else -uint64_t nano::work_value (nano::root const & root_a, uint64_t work_a) +uint64_t nano::work_v1::value (nano::root const & root_a, uint64_t work_a) { static nano::network_constants network_constants; if (!network_constants.is_test_network ()) @@ -46,7 +87,7 @@ uint64_t nano::work_value (nano::root const & root_a, uint64_t work_a) } #endif -nano::work_pool::work_pool (unsigned max_threads_a, std::chrono::nanoseconds pow_rate_limiter_a, std::function (nano::root const &, uint64_t, std::atomic &)> opencl_a) : +nano::work_pool::work_pool (unsigned max_threads_a, std::chrono::nanoseconds pow_rate_limiter_a, std::function (nano::work_version const, nano::root const &, uint64_t, std::atomic &)> opencl_a) : ticket (0), done (false), pow_rate_limiter (pow_rate_limiter_a), @@ -108,12 +149,12 @@ void nano::work_pool::loop (uint64_t thread) boost::optional opt_work; if (thread == 0 && opencl) { - opt_work = opencl (current_l.item, current_l.difficulty, ticket); + opt_work = opencl (current_l.version, current_l.item, current_l.difficulty, ticket); } if (opt_work.is_initialized ()) { work = *opt_work; - output = work_value (current_l.item, work); + output = nano::work_v1::value (current_l.item, work); } else { @@ -146,7 +187,7 @@ void nano::work_pool::loop (uint64_t thread) { // If the ticket matches what we started with, we're the ones that found the solution assert (output >= current_l.difficulty); - assert (current_l.difficulty == 0 || work_value (current_l.item, work) == output); + assert (current_l.difficulty == 0 || nano::work_v1::value (current_l.item, work) == output); // Signal other threads to stop their work next time they check ticket ++ticket; pending.pop_front (); @@ -206,17 +247,27 @@ void nano::work_pool::stop () void nano::work_pool::generate (nano::root const & root_a, std::function const &)> callback_a) { - generate (root_a, callback_a, network_constants.publish_threshold); + generate (nano::work_version::work_1, root_a, callback_a); +} + +void nano::work_pool::generate (nano::work_version const version_a, nano::root const & root_a, std::function const &)> callback_a) +{ + generate (version_a, root_a, callback_a, network_constants.publish_threshold); } void nano::work_pool::generate (nano::root const & root_a, std::function const &)> callback_a, uint64_t difficulty_a) +{ + generate (nano::work_version::work_1, root_a, callback_a, difficulty_a); +} + +void nano::work_pool::generate (nano::work_version const version_a, nano::root const & root_a, std::function const &)> callback_a, uint64_t difficulty_a) { assert (!root_a.is_zero ()); if (!threads.empty ()) { { nano::lock_guard lock (mutex); - pending.emplace_back (root_a, callback_a, difficulty_a); + pending.emplace_back (version_a, root_a, callback_a, difficulty_a); } producer_condition.notify_all (); } @@ -228,10 +279,24 @@ void nano::work_pool::generate (nano::root const & root_a, std::function nano::work_pool::generate (nano::root const & root_a) { - return generate (root_a, network_constants.publish_threshold); + static nano::network_constants network_constants; + assert (network_constants.is_test_network ()); + return generate (nano::work_version::work_1, root_a); +} + +boost::optional nano::work_pool::generate (nano::work_version const version_a, nano::root const & root_a) +{ + return generate (version_a, root_a, network_constants.publish_threshold); } boost::optional nano::work_pool::generate (nano::root const & root_a, uint64_t difficulty_a) +{ + static nano::network_constants network_constants; + assert (network_constants.is_test_network ()); + return generate (nano::work_version::work_1, root_a, difficulty_a); +} + +boost::optional nano::work_pool::generate (nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a) { boost::optional result; if (!threads.empty ()) @@ -239,7 +304,7 @@ boost::optional nano::work_pool::generate (nano::root const & root_a, std::promise> work; std::future> future = work.get_future (); generate ( - root_a, [&work](boost::optional work_a) { + version_a, root_a, [&work](boost::optional work_a) { work.set_value (work_a); }, difficulty_a); diff --git a/nano/lib/work.hpp b/nano/lib/work.hpp index a7125a379..2742acdc1 100644 --- a/nano/lib/work.hpp +++ b/nano/lib/work.hpp @@ -13,20 +13,35 @@ namespace nano { -class block; +enum class work_version +{ + unspecified, + work_1 +}; +std::string to_string (nano::work_version const version_a); -bool work_validate (nano::root const &, uint64_t, uint64_t * = nullptr); +class block; +bool work_validate (nano::work_version const, nano::block const &, uint64_t * = nullptr); +bool work_validate (nano::work_version const, nano::root const &, uint64_t const, uint64_t * = nullptr); +// For tests only bool work_validate (nano::block const &, uint64_t * = nullptr); -uint64_t work_value (nano::root const &, uint64_t); +// For tests only +bool work_validate (nano::root const &, uint64_t const, uint64_t * = nullptr); + +namespace work_v1 +{ + bool validate (nano::root const &, uint64_t const, uint64_t * = nullptr); + uint64_t value (nano::root const &, uint64_t); +} class opencl_work; class work_item final { public: - work_item (nano::root const & item_a, std::function const &)> const & callback_a, uint64_t difficulty_a) : - item (item_a), callback (callback_a), difficulty (difficulty_a) + work_item (nano::work_version const version_a, nano::root const & item_a, std::function const &)> const & callback_a, uint64_t difficulty_a) : + version (version_a), item (item_a), callback (callback_a), difficulty (difficulty_a) { } - + nano::work_version version; nano::root item; std::function const &)> callback; uint64_t difficulty; @@ -34,12 +49,18 @@ public: class work_pool final { public: - work_pool (unsigned, std::chrono::nanoseconds = std::chrono::nanoseconds (0), std::function (nano::root const &, uint64_t, std::atomic &)> = nullptr); + work_pool (unsigned, std::chrono::nanoseconds = std::chrono::nanoseconds (0), std::function (nano::work_version const, nano::root const &, uint64_t, std::atomic &)> = nullptr); ~work_pool (); void loop (uint64_t); void stop (); void cancel (nano::root const &); + void generate (nano::work_version const, nano::root const &, std::function const &)>); + void generate (nano::work_version const, nano::root const &, std::function const &)>, uint64_t); + boost::optional generate (nano::work_version const, nano::root const &); + boost::optional generate (nano::work_version const, nano::root const &, uint64_t); + // For tests only void generate (nano::root const &, std::function const &)>); + // For tests only void generate (nano::root const &, std::function const &)>, uint64_t); boost::optional generate (nano::root const &); boost::optional generate (nano::root const &, uint64_t); @@ -52,7 +73,7 @@ public: std::mutex mutex; nano::condition_variable producer_condition; std::chrono::nanoseconds pow_rate_limiter; - std::function (nano::root const &, uint64_t, std::atomic &)> opencl; + std::function (nano::work_version const, nano::root const &, uint64_t, std::atomic &)> opencl; nano::observer_set work_observers; }; diff --git a/nano/nano_node/daemon.cpp b/nano/nano_node/daemon.cpp index 5090aa5d0..b4d85ca29 100644 --- a/nano/nano_node/daemon.cpp +++ b/nano/nano_node/daemon.cpp @@ -47,10 +47,10 @@ void nano_daemon::daemon::run (boost::filesystem::path const & data_path, nano:: nano::logger_mt logger{ config.node.logging.min_time_between_log_output }; boost::asio::io_context io_ctx; auto opencl (nano::opencl_work::create (config.opencl_enable, config.opencl, logger)); - nano::work_pool opencl_work (config.node.work_threads, config.node.pow_sleep_interval, opencl ? [&opencl](nano::root const & root_a, uint64_t difficulty_a, std::atomic & ticket_a) { - return opencl->generate_work (root_a, difficulty_a, ticket_a); + nano::work_pool opencl_work (config.node.work_threads, config.node.pow_sleep_interval, opencl ? [&opencl](nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a, std::atomic & ticket_a) { + return opencl->generate_work (version_a, root_a, difficulty_a, ticket_a); } - : std::function (nano::root const &, uint64_t, std::atomic &)> (nullptr)); + : std::function (nano::work_version const, nano::root const &, uint64_t, std::atomic &)> (nullptr)); nano::alarm alarm (io_ctx); try { diff --git a/nano/nano_node/entry.cpp b/nano/nano_node/entry.cpp index e30b293f9..915842b95 100644 --- a/nano/nano_node/entry.cpp +++ b/nano/nano_node/entry.cpp @@ -193,7 +193,7 @@ int main (int argc, char * const * argv) << "Account: " << rep.pub.to_account () << "\n"; } nano::uint128_t balance (std::numeric_limits::max ()); - nano::open_block genesis_block (reinterpret_cast (genesis.pub), genesis.pub, genesis.pub, genesis.prv, genesis.pub, *work.generate (genesis.pub)); + nano::open_block genesis_block (reinterpret_cast (genesis.pub), genesis.pub, genesis.pub, genesis.prv, genesis.pub, *work.generate (nano::work_version::work_1, genesis.pub)); std::cout << genesis_block.to_json (); std::cout.flush (); nano::block_hash previous (genesis_block.hash ()); @@ -205,7 +205,7 @@ int main (int argc, char * const * argv) { assert (balance > weekly_distribution); balance = balance < (weekly_distribution * 2) ? 0 : balance - weekly_distribution; - nano::send_block send (previous, landing.pub, balance, genesis.prv, genesis.pub, *work.generate (previous)); + nano::send_block send (previous, landing.pub, balance, genesis.prv, genesis.pub, *work.generate (nano::work_version::work_1, previous)); previous = send.hash (); std::cout << send.to_json (); std::cout.flush (); @@ -321,7 +321,7 @@ int main (int argc, char * const * argv) { block.hashables.previous.qwords[0] += 1; auto begin1 (std::chrono::high_resolution_clock::now ()); - block.block_work_set (*work.generate (block.root ())); + block.block_work_set (*work.generate (nano::work_version::work_1, block.root ())); auto end1 (std::chrono::high_resolution_clock::now ()); std::cerr << boost::str (boost::format ("%|1$ 12d|\n") % std::chrono::duration_cast (end1 - begin1).count ()); } @@ -336,7 +336,7 @@ int main (int argc, char * const * argv) uint64_t count{ 10000000U }; // 10M for (uint64_t i (0); i < count; ++i) { - valid = nano::work_value (hash, i) > difficulty; + valid = nano::work_v1::value (hash, i) > difficulty; } std::ostringstream oss (valid ? "true" : "false"); // IO forces compiler to not dismiss the variable auto total_time (std::chrono::duration_cast (std::chrono::steady_clock::now () - start).count ()); @@ -419,17 +419,17 @@ int main (int argc, char * const * argv) nano::logger_mt logger; nano::opencl_config config (platform, device, threads); auto opencl (nano::opencl_work::create (true, config, logger)); - nano::work_pool work_pool (std::numeric_limits::max (), std::chrono::nanoseconds (0), opencl ? [&opencl](nano::root const & root_a, uint64_t difficulty_a, std::atomic &) { - return opencl->generate_work (root_a, difficulty_a); + nano::work_pool work_pool (std::numeric_limits::max (), std::chrono::nanoseconds (0), opencl ? [&opencl](nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a, std::atomic &) { + return opencl->generate_work (version_a, root_a, difficulty_a); } - : std::function (nano::root const &, uint64_t, std::atomic &)> (nullptr)); + : std::function (nano::work_version const, nano::root const &, uint64_t, std::atomic &)> (nullptr)); nano::change_block block (0, 0, nano::keypair ().prv, 0, 0); std::cerr << boost::str (boost::format ("Starting OpenCL generation profiling. Platform: %1%. Device: %2%. Threads: %3%. Difficulty: %4$#x\n") % platform % device % threads % difficulty); for (uint64_t i (0); true; ++i) { block.hashables.previous.qwords[0] += 1; auto begin1 (std::chrono::high_resolution_clock::now ()); - block.block_work_set (*work_pool.generate (block.root (), difficulty)); + block.block_work_set (*work_pool.generate (nano::work_version::work_1, block.root (), difficulty)); auto end1 (std::chrono::high_resolution_clock::now ()); std::cerr << boost::str (boost::format ("%|1$ 12d|\n") % std::chrono::duration_cast (end1 - begin1).count ()); } @@ -738,7 +738,7 @@ int main (int argc, char * const * argv) .balance (genesis_balance) .link (keys[i].pub) .sign (test_params.ledger.test_genesis_key.prv, test_params.ledger.test_genesis_key.pub) - .work (*work.generate (genesis_latest)) + .work (*work.generate (nano::work_version::work_1, genesis_latest)) .build (); genesis_latest = send->hash (); @@ -751,7 +751,7 @@ int main (int argc, char * const * argv) .balance (balances[i]) .link (genesis_latest) .sign (keys[i].prv, keys[i].pub) - .work (*work.generate (keys[i].pub)) + .work (*work.generate (nano::work_version::work_1, keys[i].pub)) .build (); frontiers[i] = open->hash (); @@ -772,7 +772,7 @@ int main (int argc, char * const * argv) .balance (balances[j]) .link (keys[other].pub) .sign (keys[j].prv, keys[j].pub) - .work (*work.generate (frontiers[j])) + .work (*work.generate (nano::work_version::work_1, frontiers[j])) .build (); frontiers[j] = send->hash (); @@ -787,7 +787,7 @@ int main (int argc, char * const * argv) .balance (balances[other]) .link (static_cast (frontiers[j])) .sign (keys[other].prv, keys[other].pub) - .work (*work.generate (frontiers[other])) + .work (*work.generate (nano::work_version::work_1, frontiers[other])) .build (); frontiers[other] = receive->hash (); @@ -859,7 +859,7 @@ int main (int argc, char * const * argv) .balance (genesis_balance) .link (keys[i].pub) .sign (test_params.ledger.test_genesis_key.prv, test_params.ledger.test_genesis_key.pub) - .work (*work.generate (genesis_latest)) + .work (*work.generate (nano::work_version::work_1, genesis_latest)) .build (); genesis_latest = send->hash (); @@ -872,7 +872,7 @@ int main (int argc, char * const * argv) .balance (balance) .link (genesis_latest) .sign (keys[i].prv, keys[i].pub) - .work (*work.generate (keys[i].pub)) + .work (*work.generate (nano::work_version::work_1, keys[i].pub)) .build (); node->ledger.process (transaction, *open); @@ -891,7 +891,7 @@ int main (int argc, char * const * argv) .balance (genesis_balance) .link (destination.pub) .sign (test_params.ledger.test_genesis_key.prv, test_params.ledger.test_genesis_key.pub) - .work (*work.generate (genesis_latest)) + .work (*work.generate (nano::work_version::work_1, genesis_latest)) .build (); genesis_latest = send->hash (); @@ -1104,7 +1104,7 @@ int main (int argc, char * const * argv) std::cerr << boost::str (boost::format ("Incorrect sideband block details for block %1%\n") % hash.to_string ()); } // Check if block work value is correct - if (nano::work_validate (*block.get ())) + if (nano::work_validate (nano::work_version::work_1, *block)) { std::cerr << boost::str (boost::format ("Invalid work for block %1% value: %2%\n") % hash.to_string () % nano::to_string_hex (block->block_work ())); } @@ -1416,4 +1416,4 @@ bool address_library_pair::operator== (const address_library_pair & other) const { return address == other.address; } -} \ No newline at end of file +} diff --git a/nano/nano_wallet/entry.cpp b/nano/nano_wallet/entry.cpp index 72cf3f15d..883026468 100644 --- a/nano/nano_wallet/entry.cpp +++ b/nano/nano_wallet/entry.cpp @@ -108,10 +108,10 @@ int run_wallet (QApplication & application, int argc, char * const * argv, boost std::shared_ptr gui; nano::set_application_icon (application); auto opencl (nano::opencl_work::create (config.opencl_enable, config.opencl, logger)); - nano::work_pool work (config.node.work_threads, config.node.pow_sleep_interval, opencl ? [&opencl](nano::root const & root_a, uint64_t difficulty_a, std::atomic &) { - return opencl->generate_work (root_a, difficulty_a); + nano::work_pool work (config.node.work_threads, config.node.pow_sleep_interval, opencl ? [&opencl](nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a, std::atomic &) { + return opencl->generate_work (version_a, root_a, difficulty_a); } - : std::function (nano::root const &, uint64_t, std::atomic &)> (nullptr)); + : std::function (nano::work_version const, nano::root const &, uint64_t, std::atomic &)> (nullptr)); nano::alarm alarm (io_ctx); node = std::make_shared (io_ctx, data_path, alarm, config.node, work, flags); if (!node->init_error ()) diff --git a/nano/node/active_transactions.cpp b/nano/node/active_transactions.cpp index 9e4bdbc14..0f0cff6ef 100644 --- a/nano/node/active_transactions.cpp +++ b/nano/node/active_transactions.cpp @@ -582,7 +582,7 @@ std::pair, bool> nano::active_transactions::inse auto hash (block_a->hash ()); result.first = nano::make_shared (node, block_a, skip_delay_a, confirmation_action_a); uint64_t difficulty (0); - release_assert (!nano::work_validate (*block_a, &difficulty)); + release_assert (!nano::work_validate (nano::work_version::work_1, *block_a, &difficulty)); roots.get ().emplace (nano::conflict_info{ root, difficulty, difficulty, result.first }); blocks.emplace (hash, result.first); adjust_difficulty (hash); @@ -680,7 +680,7 @@ void nano::active_transactions::update_difficulty (std::shared_ptr if (existing_election != roots.get ().end ()) { uint64_t difficulty; - auto error (nano::work_validate (*block_a, &difficulty)); + auto error (nano::work_validate (nano::work_version::work_1, *block_a, &difficulty)); (void)error; assert (!error); if (difficulty > existing_election->difficulty) @@ -714,7 +714,7 @@ void nano::active_transactions::update_difficulty (std::shared_ptr { uint64_t existing_difficulty; uint64_t new_difficulty; - if (!nano::work_validate (*block_a, &new_difficulty) && !nano::work_validate (*existing_block, &existing_difficulty)) + if (!nano::work_validate (nano::work_version::work_1, *block_a, &new_difficulty) && !nano::work_validate (nano::work_version::work_1, *existing_block, &existing_difficulty)) { if (new_difficulty > existing_difficulty) { diff --git a/nano/node/blockprocessor.cpp b/nano/node/blockprocessor.cpp index dc390831b..c372893ef 100644 --- a/nano/node/blockprocessor.cpp +++ b/nano/node/blockprocessor.cpp @@ -69,7 +69,7 @@ void nano::block_processor::add (std::shared_ptr block_a, uint64_t void nano::block_processor::add (nano::unchecked_info const & info_a) { - if (!nano::work_validate (info_a.block->root (), info_a.block->block_work ())) + if (!nano::work_validate (nano::work_version::work_1, info_a.block->root (), info_a.block->block_work ())) { { auto hash (info_a.block->hash ()); @@ -375,7 +375,7 @@ void nano::block_processor::process_live (nano::block_hash const & hash_a, std:: // Add to work watcher to prevent dropping the election if (watch_work_a) { - node.wallets.watcher->add (block_a); + node.wallets.watcher->add (block_a, nano::work_version::work_1); } // Start collecting quorum on block diff --git a/nano/node/bootstrap/bootstrap_bulk_pull.cpp b/nano/node/bootstrap/bootstrap_bulk_pull.cpp index 04fe23703..0a8a21c66 100644 --- a/nano/node/bootstrap/bootstrap_bulk_pull.cpp +++ b/nano/node/bootstrap/bootstrap_bulk_pull.cpp @@ -214,7 +214,7 @@ void nano::bulk_pull_client::received_block (boost::system::error_code const & e { nano::bufferstream stream (connection->receive_buffer->data (), size_a); std::shared_ptr block (nano::deserialize_block (stream, type_a)); - if (block != nullptr && !nano::work_validate (*block)) + if (block != nullptr && !nano::work_validate (nano::work_version::work_1, *block)) { auto hash (block->hash ()); if (connection->node->config.logging.bulk_pull_logging ()) diff --git a/nano/node/bootstrap/bootstrap_bulk_push.cpp b/nano/node/bootstrap/bootstrap_bulk_push.cpp index fc2290463..f50d154b7 100644 --- a/nano/node/bootstrap/bootstrap_bulk_push.cpp +++ b/nano/node/bootstrap/bootstrap_bulk_push.cpp @@ -240,7 +240,7 @@ void nano::bulk_push_server::received_block (boost::system::error_code const & e { nano::bufferstream stream (receive_buffer->data (), size_a); auto block (nano::deserialize_block (stream, type_a)); - if (block != nullptr && !nano::work_validate (*block)) + if (block != nullptr && !nano::work_validate (nano::work_version::work_1, *block)) { connection->node->process_active (std::move (block)); throttled_receive (); diff --git a/nano/node/common.cpp b/nano/node/common.cpp index 9e2cb2c68..3628d511d 100644 --- a/nano/node/common.cpp +++ b/nano/node/common.cpp @@ -418,7 +418,7 @@ void nano::message_parser::deserialize_publish (nano::stream & stream_a, nano::m nano::publish incoming (error, stream_a, header_a, &block_uniquer); if (!error && at_end (stream_a)) { - if (!nano::work_validate (*incoming.block)) + if (!nano::work_validate (nano::work_version::work_1, *incoming.block)) { visitor.publish (incoming); } @@ -439,7 +439,7 @@ void nano::message_parser::deserialize_confirm_req (nano::stream & stream_a, nan nano::confirm_req incoming (error, stream_a, header_a, &block_uniquer); if (!error && at_end (stream_a)) { - if (incoming.block == nullptr || !nano::work_validate (*incoming.block)) + if (incoming.block == nullptr || !nano::work_validate (nano::work_version::work_1, *incoming.block)) { visitor.confirm_req (incoming); } @@ -465,7 +465,7 @@ void nano::message_parser::deserialize_confirm_ack (nano::stream & stream_a, nan if (!vote_block.which ()) { auto block (boost::get> (vote_block)); - if (nano::work_validate (*block)) + if (nano::work_validate (nano::work_version::work_1, *block)) { status = parse_status::insufficient_work; break; diff --git a/nano/node/distributed_work.cpp b/nano/node/distributed_work.cpp index 5496cb4d0..e4e1ff5be 100644 --- a/nano/node/distributed_work.cpp +++ b/nano/node/distributed_work.cpp @@ -43,15 +43,15 @@ nano::distributed_work::~distributed_work () nano::websocket::message_builder builder; if (status == work_generation_status::success) { - node_l->websocket_server->broadcast (builder.work_generation (request.root, work_result, request.difficulty, node_l->network_params.network.publish_threshold, elapsed.value (), winner, bad_peers)); + node_l->websocket_server->broadcast (builder.work_generation (request.version, request.root, work_result, request.difficulty, node_l->network_params.network.publish_threshold, elapsed.value (), winner, bad_peers)); } else if (status == work_generation_status::cancelled) { - node_l->websocket_server->broadcast (builder.work_cancelled (request.root, request.difficulty, node_l->network_params.network.publish_threshold, elapsed.value (), bad_peers)); + node_l->websocket_server->broadcast (builder.work_cancelled (request.version, request.root, request.difficulty, node_l->network_params.network.publish_threshold, elapsed.value (), bad_peers)); } else if (status == work_generation_status::failure_local || status == work_generation_status::failure_peers) { - node_l->websocket_server->broadcast (builder.work_failed (request.root, request.difficulty, node_l->network_params.network.publish_threshold, elapsed.value (), bad_peers)); + node_l->websocket_server->broadcast (builder.work_failed (request.version, request.root, request.difficulty, node_l->network_params.network.publish_threshold, elapsed.value (), bad_peers)); } } stop_once (true); @@ -108,7 +108,7 @@ void nano::distributed_work::start_local () auto this_l (shared_from_this ()); local_generation_started = true; node.work.generate ( - request.root, [this_l](boost::optional const & work_a) { + request.version, request.root, [this_l](boost::optional const & work_a) { if (work_a.is_initialized ()) { this_l->set_once (*work_a); @@ -242,7 +242,7 @@ void nano::distributed_work::success (std::string const & body_a, nano::tcp_endp if (!nano::from_string_hex (work_text, work)) { uint64_t result_difficulty (0); - if (!nano::work_validate (request.root, work, &result_difficulty) && result_difficulty >= request.difficulty) + if (!nano::work_validate (request.version, request.root, work, &result_difficulty) && result_difficulty >= request.difficulty) { error = false; node.unresponsive_work_peers = false; diff --git a/nano/node/distributed_work.hpp b/nano/node/distributed_work.hpp index 3ff00e71a..29a26ba8c 100644 --- a/nano/node/distributed_work.hpp +++ b/nano/node/distributed_work.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -28,6 +29,7 @@ class node; struct work_request final { + nano::work_version version; nano::root root; uint64_t difficulty; boost::optional const account; diff --git a/nano/node/distributed_work_factory.cpp b/nano/node/distributed_work_factory.cpp index 8e505ee7a..fba9261ab 100644 --- a/nano/node/distributed_work_factory.cpp +++ b/nano/node/distributed_work_factory.cpp @@ -11,9 +11,9 @@ nano::distributed_work_factory::~distributed_work_factory () stop (); } -bool nano::distributed_work_factory::make (nano::root const & root_a, std::vector> const & peers_a, std::function)> const & callback_a, uint64_t difficulty_a, boost::optional const & account_a) +bool nano::distributed_work_factory::make (nano::work_version const version_a, nano::root const & root_a, std::vector> const & peers_a, std::function)> const & callback_a, uint64_t difficulty_a, boost::optional const & account_a) { - return make (std::chrono::seconds (1), nano::work_request{ root_a, difficulty_a, account_a, callback_a, peers_a }); + return make (std::chrono::seconds (1), nano::work_request{ version_a, root_a, difficulty_a, account_a, callback_a, peers_a }); } bool nano::distributed_work_factory::make (std::chrono::seconds const & backoff_a, nano::work_request const & request_a) diff --git a/nano/node/distributed_work_factory.hpp b/nano/node/distributed_work_factory.hpp index 7bf7e0359..56905dad4 100644 --- a/nano/node/distributed_work_factory.hpp +++ b/nano/node/distributed_work_factory.hpp @@ -22,7 +22,7 @@ class distributed_work_factory final public: distributed_work_factory (nano::node &); ~distributed_work_factory (); - bool make (nano::root const &, std::vector> const &, std::function)> const &, uint64_t, boost::optional const & = boost::none); + bool make (nano::work_version const, nano::root const &, std::vector> const &, std::function)> const &, uint64_t, boost::optional const & = boost::none); bool make (std::chrono::seconds const &, nano::work_request const &); void cancel (nano::root const &, bool const local_stop = false); void cleanup_finished (); @@ -36,4 +36,4 @@ public: class container_info_component; std::unique_ptr collect_container_info (distributed_work_factory & distributed_work, const std::string & name); -} \ No newline at end of file +} diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index a207b8e71..2dc4ad370 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -375,6 +375,24 @@ double nano::json_handler::multiplier_optional_impl (uint64_t & difficulty) return multiplier; } +nano::work_version nano::json_handler::work_version_optional_impl (nano::work_version const default_a) +{ + nano::work_version result = default_a; + boost::optional version_text (request.get_optional ("version")); + if (!ec && version_text.is_initialized ()) + { + if (*version_text == nano::to_string (nano::work_version::work_1)) + { + result = nano::work_version::work_1; + } + else + { + ec = nano::error_rpc::bad_work_version; + } + } + return result; +} + namespace { bool decode_unsigned (std::string const & text, uint64_t & number) @@ -697,7 +715,7 @@ void nano::json_handler::account_representative_set () auto info (rpc_l->account_info_impl (block_transaction, account)); if (!rpc_l->ec) { - if (nano::work_validate (info.head, work)) + if (nano::work_validate (nano::work_version::work_1, info.head, work)) { rpc_l->ec = nano::error_common::invalid_work; } @@ -1277,6 +1295,8 @@ void nano::json_handler::block_create () } } auto work (work_optional_impl ()); + // Default to work_1 if not specified + auto work_version (work_version_optional_impl (nano::work_version::work_1)); nano::raw_key prv; prv.data.clear (); nano::block_hash previous (0); @@ -1542,7 +1562,7 @@ void nano::json_handler::block_create () { if (work == 0) { - node.work_generate (root_l, get_callback_l (block_l), nano::account (pub)); + node.work_generate (work_version, root_l, get_callback_l (block_l), nano::account (pub)); } else { @@ -2103,10 +2123,10 @@ void epoch_upgrader (std::shared_ptr node_a, nano::private_key const .balance (info.balance) .link (link) .sign (raw_key, signer) - .work (node_a->work_generate_blocking (info.head).value_or (0)) + .work (node_a->work_generate_blocking (nano::work_version::work_1, info.head).value_or (0)) .build (); bool valid_signature (!nano::validate_message (signer, epoch->hash (), epoch->block_signature ())); - bool valid_work (!nano::work_validate (*epoch.get ())); + bool valid_work (!nano::work_validate (nano::work_version::work_1, *epoch.get ())); nano::process_result result (nano::process_result::old); if (valid_signature && valid_work) { @@ -2162,10 +2182,10 @@ void epoch_upgrader (std::shared_ptr node_a, nano::private_key const .balance (0) .link (link) .sign (raw_key, signer) - .work (node_a->work_generate_blocking (key.account).value_or (0)) + .work (node_a->work_generate_blocking (nano::work_version::work_1, key.account).value_or (0)) .build (); bool valid_signature (!nano::validate_message (signer, epoch->hash (), epoch->block_signature ())); - bool valid_work (!nano::work_validate (*epoch.get ())); + bool valid_work (!nano::work_validate (nano::work_version::work_1, *epoch.get ())); nano::process_result result (nano::process_result::old); if (valid_signature && valid_work) { @@ -3232,7 +3252,7 @@ void nano::json_handler::process () } if (!rpc_l->ec) { - if (!nano::work_validate (*block)) + if (!nano::work_validate (nano::work_version::work_1, *block)) { auto result (rpc_l->node.process_local (block, watch_work_l)); switch (result.code) @@ -3345,7 +3365,7 @@ void nano::json_handler::receive () { head = account; } - if (nano::work_validate (head, work)) + if (nano::work_validate (nano::work_version::work_1, head, work)) { ec = nano::error_common::invalid_work; } @@ -3688,7 +3708,7 @@ void nano::json_handler::send () } if (!ec && work) { - if (nano::work_validate (info.head, work)) + if (nano::work_validate (nano::work_version::work_1, info.head, work)) { ec = nano::error_common::invalid_work; } @@ -4895,7 +4915,9 @@ void nano::json_handler::work_generate () { boost::optional account; auto account_opt (request.get_optional ("account")); - if (account_opt.is_initialized ()) + // Default to work_1 if not specified + auto work_version (work_version_optional_impl (nano::work_version::work_1)); + if (!ec && account_opt.is_initialized ()) { account = account_impl (account_opt.get ()); } @@ -4912,7 +4934,7 @@ void nano::json_handler::work_generate () { auto use_peers (request.get ("use_peers", false)); auto rpc_l (shared_from_this ()); - auto callback = [rpc_l, hash, this](boost::optional const & work_a) { + auto callback = [rpc_l, hash, work_version, this](boost::optional const & work_a) { if (work_a) { boost::property_tree::ptree response_l; @@ -4921,7 +4943,7 @@ void nano::json_handler::work_generate () response_l.put ("work", nano::to_string_hex (work)); std::stringstream ostream; uint64_t result_difficulty; - nano::work_validate (hash, work, &result_difficulty); + nano::work_validate (work_version, hash, work, &result_difficulty); response_l.put ("difficulty", nano::to_string_hex (result_difficulty)); auto result_multiplier = nano::difficulty::to_multiplier (result_difficulty, this->node.network_params.network.publish_threshold); response_l.put ("multiplier", nano::to_string (result_multiplier)); @@ -4937,7 +4959,7 @@ void nano::json_handler::work_generate () { if (node.local_work_generation_enabled ()) { - node.work.generate (hash, callback, difficulty); + node.work.generate (work_version, hash, callback, difficulty); } else { @@ -4959,7 +4981,7 @@ void nano::json_handler::work_generate () auto const & peers_l (secondary_work_peers_l ? node.config.secondary_work_peers : node.config.work_peers); if (node.work_generation_enabled (peers_l)) { - node.work_generate (hash, callback, difficulty, account, secondary_work_peers_l); + node.work_generate (work_version, hash, callback, difficulty, account, secondary_work_peers_l); } else { @@ -5031,10 +5053,12 @@ void nano::json_handler::work_validate () auto work (work_optional_impl ()); auto difficulty (difficulty_optional_impl ()); multiplier_optional_impl (difficulty); + // Default to work_1 if not specified + auto work_version (work_version_optional_impl (nano::work_version::work_1)); if (!ec) { uint64_t result_difficulty (0); - nano::work_validate (hash, work, &result_difficulty); + nano::work_validate (work_version, hash, work, &result_difficulty); response_l.put ("valid", (result_difficulty >= difficulty) ? "1" : "0"); response_l.put ("difficulty", nano::to_string_hex (result_difficulty)); auto result_multiplier = nano::difficulty::to_multiplier (result_difficulty, node.network_params.network.publish_threshold); diff --git a/nano/node/json_handler.hpp b/nano/node/json_handler.hpp index ff8face8e..2a7b6ff7f 100644 --- a/nano/node/json_handler.hpp +++ b/nano/node/json_handler.hpp @@ -158,6 +158,7 @@ public: uint64_t offset_optional_impl (uint64_t = 0); uint64_t difficulty_optional_impl (); double multiplier_optional_impl (uint64_t &); + nano::work_version work_version_optional_impl (nano::work_version const default_a); bool enable_sign_hash{ false }; std::function stop_callback; nano::node_rpc_config const & node_rpc_config; diff --git a/nano/node/node.cpp b/nano/node/node.cpp index a131596e7..6044ccf21 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -1006,14 +1006,14 @@ bool nano::node::work_generation_enabled (std::vector nano::node::work_generate_blocking (nano::block & block_a) +boost::optional nano::node::work_generate_blocking (nano::work_version const version_a, nano::block & block_a) { - return work_generate_blocking (block_a, network_params.network.publish_threshold); + return work_generate_blocking (version_a, block_a, network_params.network.publish_threshold); } -boost::optional nano::node::work_generate_blocking (nano::block & block_a, uint64_t difficulty_a) +boost::optional nano::node::work_generate_blocking (nano::work_version const version_a, nano::block & block_a, uint64_t difficulty_a) { - auto opt_work_l (work_generate_blocking (block_a.root (), difficulty_a, block_a.account ())); + auto opt_work_l (work_generate_blocking (version_a, block_a.root (), difficulty_a, block_a.account ())); if (opt_work_l.is_initialized ()) { block_a.block_work_set (*opt_work_l); @@ -1021,37 +1021,61 @@ boost::optional nano::node::work_generate_blocking (nano::block & bloc return opt_work_l; } -void nano::node::work_generate (nano::root const & root_a, std::function)> callback_a, boost::optional const & account_a) +void nano::node::work_generate (nano::work_version const version_a, nano::root const & root_a, std::function)> callback_a, boost::optional const & account_a) { - work_generate (root_a, callback_a, network_params.network.publish_threshold, account_a); + work_generate (version_a, root_a, callback_a, network_params.network.publish_threshold, account_a); } -void nano::node::work_generate (nano::root const & root_a, std::function)> callback_a, uint64_t difficulty_a, boost::optional const & account_a, bool secondary_work_peers_a) +void nano::node::work_generate (nano::work_version const version_a, nano::root const & root_a, std::function)> callback_a, uint64_t difficulty_a, boost::optional const & account_a, bool secondary_work_peers_a) { auto const & peers_l (secondary_work_peers_a ? config.secondary_work_peers : config.work_peers); - if (distributed_work.make (root_a, peers_l, callback_a, difficulty_a, account_a)) + if (distributed_work.make (version_a, root_a, peers_l, callback_a, difficulty_a, account_a)) { // Error in creating the job (either stopped or work generation is not possible) callback_a (boost::none); } } -boost::optional nano::node::work_generate_blocking (nano::root const & root_a, boost::optional const & account_a) +boost::optional nano::node::work_generate_blocking (nano::work_version const version_a, nano::root const & root_a, boost::optional const & account_a) { - return work_generate_blocking (root_a, network_params.network.publish_threshold, account_a); + return work_generate_blocking (version_a, root_a, network_params.network.publish_threshold, account_a); } -boost::optional nano::node::work_generate_blocking (nano::root const & root_a, uint64_t difficulty_a, boost::optional const & account_a) +boost::optional nano::node::work_generate_blocking (nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a, boost::optional const & account_a) { std::promise> promise; work_generate ( - root_a, [&promise](boost::optional opt_work_a) { + version_a, root_a, [&promise](boost::optional opt_work_a) { promise.set_value (opt_work_a); }, difficulty_a, account_a); return promise.get_future ().get (); } +boost::optional nano::node::work_generate_blocking (nano::block & block_a) +{ + assert (network_params.network.is_test_network ()); + return work_generate_blocking (block_a, network_params.network.publish_threshold); +} + +boost::optional nano::node::work_generate_blocking (nano::block & block_a, uint64_t difficulty_a) +{ + assert (network_params.network.is_test_network ()); + return work_generate_blocking (nano::work_version::work_1, block_a, difficulty_a); +} + +boost::optional nano::node::work_generate_blocking (nano::root const & root_a) +{ + assert (network_params.network.is_test_network ()); + return work_generate_blocking (root_a, network_params.network.publish_threshold); +} + +boost::optional nano::node::work_generate_blocking (nano::root const & root_a, uint64_t difficulty_a) +{ + assert (network_params.network.is_test_network ()); + return work_generate_blocking (nano::work_version::work_1, root_a, difficulty_a); +} + void nano::node::add_initial_peers () { auto transaction (store.tx_begin_read ()); diff --git a/nano/node/node.hpp b/nano/node/node.hpp index 0938cb3b0..8dceb5305 100644 --- a/nano/node/node.hpp +++ b/nano/node/node.hpp @@ -129,12 +129,12 @@ public: bool local_work_generation_enabled () const; bool work_generation_enabled () const; bool work_generation_enabled (std::vector> const &) const; - boost::optional work_generate_blocking (nano::block &, uint64_t); - boost::optional work_generate_blocking (nano::block &); - boost::optional work_generate_blocking (nano::root const &, uint64_t, boost::optional const & = boost::none); - boost::optional work_generate_blocking (nano::root const &, boost::optional const & = boost::none); - void work_generate (nano::root const &, std::function)>, uint64_t, boost::optional const & = boost::none, bool const = false); - void work_generate (nano::root const &, std::function)>, boost::optional const & = boost::none); + boost::optional work_generate_blocking (nano::work_version const, nano::block &, uint64_t); + boost::optional work_generate_blocking (nano::work_version const, nano::block &); + boost::optional work_generate_blocking (nano::work_version const, nano::root const &, uint64_t, boost::optional const & = boost::none); + boost::optional work_generate_blocking (nano::work_version const, nano::root const &, boost::optional const & = boost::none); + void work_generate (nano::work_version const, nano::root const &, std::function)>, uint64_t, boost::optional const & = boost::none, bool const = false); + void work_generate (nano::work_version const, nano::root const &, std::function)>, boost::optional const & = boost::none); void add_initial_peers (); void block_confirm (std::shared_ptr); bool block_confirmed_or_being_confirmed (nano::transaction const &, nano::block_hash const &); @@ -195,6 +195,15 @@ public: static double constexpr price_max = 16.0; static double constexpr free_cutoff = 1024.0; + // For tests only + boost::optional work_generate_blocking (nano::block &, uint64_t); + // For tests only + boost::optional work_generate_blocking (nano::block &); + // For tests only + boost::optional work_generate_blocking (nano::root const &, uint64_t); + // For tests only + boost::optional work_generate_blocking (nano::root const &); + private: void long_inactivity_cleanup (); }; diff --git a/nano/node/openclwork.cpp b/nano/node/openclwork.cpp index 14a8f15a5..bce14c3f5 100644 --- a/nano/node/openclwork.cpp +++ b/nano/node/openclwork.cpp @@ -687,13 +687,13 @@ nano::opencl_work::~opencl_work () } } -boost::optional nano::opencl_work::generate_work (nano::root const & root_a, uint64_t const difficulty_a) +boost::optional nano::opencl_work::generate_work (nano::work_version const version_a, nano::root const & root_a, uint64_t const difficulty_a) { std::atomic ticket_l{ 0 }; - return generate_work (root_a, difficulty_a, ticket_l); + return generate_work (version_a, root_a, difficulty_a, ticket_l); } -boost::optional nano::opencl_work::generate_work (nano::root const & root_a, uint64_t const difficulty_a, std::atomic & ticket_a) +boost::optional nano::opencl_work::generate_work (nano::work_version const version_a, nano::root const & root_a, uint64_t const difficulty_a, std::atomic & ticket_a) { nano::lock_guard lock (mutex); bool error (false); @@ -702,7 +702,7 @@ boost::optional nano::opencl_work::generate_work (nano::root const & r uint64_t computed_difficulty (0); unsigned thread_count (config.threads); size_t work_size[] = { thread_count, 0, 0 }; - while ((nano::work_validate (root_a, result, &computed_difficulty) || computed_difficulty < difficulty_a) && !error && ticket_a == ticket_l) + while ((nano::work_validate (version_a, root_a, result, &computed_difficulty) || computed_difficulty < difficulty_a) && !error && ticket_a == ticket_l) { result = rand.next (); cl_int write_error1 = clEnqueueWriteBuffer (queue, attempt_buffer, false, 0, sizeof (uint64_t), &result, 0, nullptr, nullptr); diff --git a/nano/node/openclwork.hpp b/nano/node/openclwork.hpp index 1ca55b46e..2b1de6040 100644 --- a/nano/node/openclwork.hpp +++ b/nano/node/openclwork.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -40,8 +41,8 @@ class opencl_work public: opencl_work (bool &, nano::opencl_config const &, nano::opencl_environment &, nano::logger_mt &); ~opencl_work (); - boost::optional generate_work (nano::root const &, uint64_t const); - boost::optional generate_work (nano::root const &, uint64_t const, std::atomic &); + boost::optional generate_work (nano::work_version const, nano::root const &, uint64_t const); + boost::optional generate_work (nano::work_version const, nano::root const &, uint64_t const, std::atomic &); static std::unique_ptr create (bool, nano::opencl_config const &, nano::logger_mt &); nano::opencl_config const & config; std::mutex mutex; diff --git a/nano/node/wallet.cpp b/nano/node/wallet.cpp index 868c0ae61..3fb2842aa 100644 --- a/nano/node/wallet.cpp +++ b/nano/node/wallet.cpp @@ -1134,10 +1134,10 @@ bool nano::wallet::action_complete (std::shared_ptr const & block_a bool error{ false }; if (block_a != nullptr) { - if (nano::work_validate (*block_a)) + if (nano::work_validate (nano::work_version::work_1, *block_a)) { wallets.node.logger.try_log (boost::str (boost::format ("Cached or provided work for block %1% account %2% is invalid, regenerating") % block_a->hash ().to_string () % account_a.to_account ())); - error = !wallets.node.work_generate_blocking (*block_a, wallets.node.active.limited_active_difficulty ()).is_initialized (); + error = !wallets.node.work_generate_blocking (nano::work_version::work_1, *block_a, wallets.node.active.limited_active_difficulty ()).is_initialized (); } if (!error) { @@ -1217,7 +1217,7 @@ void nano::wallet::send_async (nano::account const & source_a, nano::account con // Update work for account if latest root is root_a void nano::wallet::work_update (nano::transaction const & transaction_a, nano::account const & account_a, nano::root const & root_a, uint64_t work_a) { - assert (!nano::work_validate (root_a, work_a)); + assert (!nano::work_validate (nano::work_version::work_1, root_a, work_a)); assert (store.exists (transaction_a, account_a)); auto block_transaction (wallets.node.store.tx_begin_read ()); auto latest (wallets.node.ledger.latest_root (block_transaction, account_a)); @@ -1364,7 +1364,7 @@ void nano::wallet::work_cache_blocking (nano::account const & account_a, nano::r { if (wallets.node.work_generation_enabled ()) { - auto opt_work_l (wallets.node.work_generate_blocking (root_a, account_a)); + auto opt_work_l (wallets.node.work_generate_blocking (nano::work_version::work_1, root_a, account_a)); if (opt_work_l.is_initialized ()) { auto transaction_l (wallets.tx_begin_write ()); @@ -1401,7 +1401,7 @@ void nano::work_watcher::stop () stopped = true; } -void nano::work_watcher::add (std::shared_ptr block_a) +void nano::work_watcher::add (std::shared_ptr block_a, nano::work_version const work_version_a) { auto block_l (std::dynamic_pointer_cast (block_a)); if (!stopped && block_l != nullptr) @@ -1410,7 +1410,7 @@ void nano::work_watcher::add (std::shared_ptr block_a) nano::unique_lock lock (mutex); watched[root_l] = block_l; lock.unlock (); - watching (root_l, block_l); + watching (work_version_a, root_l, block_l); } } @@ -1420,10 +1420,10 @@ void nano::work_watcher::update (nano::qualified_root const & root_a, std::share watched[root_a] = block_a; } -void nano::work_watcher::watching (nano::qualified_root const & root_a, std::shared_ptr block_a) +void nano::work_watcher::watching (nano::work_version const version_a, nano::qualified_root const & root_a, std::shared_ptr block_a) { std::weak_ptr watcher_w (shared_from_this ()); - node.alarm.add (std::chrono::steady_clock::now () + node.config.work_watcher_period, [block_a, root_a, watcher_w]() { + node.alarm.add (std::chrono::steady_clock::now () + node.config.work_watcher_period, [block_a, version_a, root_a, watcher_w]() { auto watcher_l = watcher_w.lock (); if (watcher_l && !watcher_l->stopped && block_a != nullptr) { @@ -1433,7 +1433,7 @@ void nano::work_watcher::watching (nano::qualified_root const & root_a, std::sha lock.unlock (); uint64_t difficulty (0); auto root_l (block_a->root ()); - nano::work_validate (root_l, block_a->block_work (), &difficulty); + nano::work_validate (version_a, root_l, block_a->block_work (), &difficulty); auto active_difficulty (watcher_l->node.active.limited_active_difficulty ()); /* * Work watcher should still watch blocks even without work generation, although no rework is done @@ -1442,7 +1442,7 @@ void nano::work_watcher::watching (nano::qualified_root const & root_a, std::sha if (active_difficulty > difficulty && watcher_l->node.work_generation_enabled ()) { watcher_l->node.work_generate ( - root_l, [watcher_l, block_a, root_a](boost::optional work_a) { + version_a, root_l, [watcher_l, block_a, version_a, root_a](boost::optional work_a) { if (block_a != nullptr && watcher_l != nullptr && !watcher_l->stopped) { bool updated_l{ false }; @@ -1457,12 +1457,12 @@ void nano::work_watcher::watching (nano::qualified_root const & root_a, std::sha watcher_l->node.active.update_difficulty (block); watcher_l->update (root_a, block); updated_l = true; - watcher_l->watching (root_a, block); + watcher_l->watching (version_a, root_a, block); } } if (!updated_l) { - watcher_l->watching (root_a, block_a); + watcher_l->watching (version_a, root_a, block_a); } } }, @@ -1470,7 +1470,7 @@ void nano::work_watcher::watching (nano::qualified_root const & root_a, std::sha } else { - watcher_l->watching (root_a, block_a); + watcher_l->watching (version_a, root_a, block_a); } } } diff --git a/nano/node/wallet.hpp b/nano/node/wallet.hpp index 3d302b8cf..c447c8605 100644 --- a/nano/node/wallet.hpp +++ b/nano/node/wallet.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -10,7 +11,6 @@ #include #include #include - namespace nano { class node; @@ -168,9 +168,9 @@ public: work_watcher (nano::node &); ~work_watcher (); void stop (); - void add (std::shared_ptr); + void add (std::shared_ptr, nano::work_version const); void update (nano::qualified_root const &, std::shared_ptr); - void watching (nano::qualified_root const &, std::shared_ptr); + void watching (work_version const, nano::qualified_root const &, std::shared_ptr); void remove (std::shared_ptr); bool is_watched (nano::qualified_root const &); size_t size (); diff --git a/nano/node/websocket.cpp b/nano/node/websocket.cpp index f4febe491..8b2134571 100644 --- a/nano/node/websocket.cpp +++ b/nano/node/websocket.cpp @@ -773,7 +773,7 @@ nano::websocket::message nano::websocket::message_builder::difficulty_changed (u return message_l; } -nano::websocket::message nano::websocket::message_builder::work_generation (nano::block_hash const & root_a, uint64_t work_a, uint64_t difficulty_a, uint64_t publish_threshold_a, std::chrono::milliseconds const & duration_a, std::string const & peer_a, std::vector const & bad_peers_a, bool completed_a, bool cancelled_a) +nano::websocket::message nano::websocket::message_builder::work_generation (nano::work_version const version_a, nano::block_hash const & root_a, uint64_t work_a, uint64_t difficulty_a, uint64_t publish_threshold_a, std::chrono::milliseconds const & duration_a, std::string const & peer_a, std::vector const & bad_peers_a, bool completed_a, bool cancelled_a) { nano::websocket::message message_l (nano::websocket::topic::work); set_common_fields (message_l); @@ -785,6 +785,7 @@ nano::websocket::message nano::websocket::message_builder::work_generation (nano work_l.put ("duration", duration_a.count ()); boost::property_tree::ptree request_l; + request_l.put ("version", nano::to_string (version_a)); request_l.put ("hash", root_a.to_string ()); request_l.put ("difficulty", nano::to_string_hex (difficulty_a)); auto request_multiplier_l (nano::difficulty::to_multiplier (difficulty_a, publish_threshold_a)); @@ -797,7 +798,7 @@ nano::websocket::message nano::websocket::message_builder::work_generation (nano result_l.put ("source", peer_a); result_l.put ("work", nano::to_string_hex (work_a)); uint64_t result_difficulty_l; - nano::work_validate (root_a, work_a, &result_difficulty_l); + nano::work_validate (version_a, root_a, work_a, &result_difficulty_l); result_l.put ("difficulty", nano::to_string_hex (result_difficulty_l)); auto result_multiplier_l (nano::difficulty::to_multiplier (result_difficulty_l, publish_threshold_a)); result_l.put ("multiplier", nano::to_string (result_multiplier_l)); @@ -817,14 +818,14 @@ nano::websocket::message nano::websocket::message_builder::work_generation (nano return message_l; } -nano::websocket::message nano::websocket::message_builder::work_cancelled (nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector const & bad_peers_a) +nano::websocket::message nano::websocket::message_builder::work_cancelled (nano::work_version const version_a, nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector const & bad_peers_a) { - return work_generation (root_a, 0, difficulty_a, publish_threshold_a, duration_a, "", bad_peers_a, false, true); + return work_generation (version_a, root_a, 0, difficulty_a, publish_threshold_a, duration_a, "", bad_peers_a, false, true); } -nano::websocket::message nano::websocket::message_builder::work_failed (nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector const & bad_peers_a) +nano::websocket::message nano::websocket::message_builder::work_failed (nano::work_version const version_a, nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector const & bad_peers_a) { - return work_generation (root_a, 0, difficulty_a, publish_threshold_a, duration_a, "", bad_peers_a, false, false); + return work_generation (version_a, root_a, 0, difficulty_a, publish_threshold_a, duration_a, "", bad_peers_a, false, false); } nano::websocket::message nano::websocket::message_builder::bootstrap_started (std::string const & id_a, std::string const & mode_a) diff --git a/nano/node/websocket.hpp b/nano/node/websocket.hpp index 4838c2522..6b0f7c3f5 100644 --- a/nano/node/websocket.hpp +++ b/nano/node/websocket.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -88,9 +89,10 @@ namespace websocket message stopped_election (nano::block_hash const & hash_a); message vote_received (std::shared_ptr vote_a, nano::vote_code code_a); message difficulty_changed (uint64_t publish_threshold_a, uint64_t difficulty_active_a); - message work_generation (nano::block_hash const & root_a, uint64_t const work_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::string const & peer_a, std::vector const & bad_peers_a, bool const completed_a = true, bool const cancelled_a = false); - message work_cancelled (nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector const & bad_peers_a); - message work_failed (nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector const & bad_peers_a); + + message work_generation (nano::work_version const version_a, nano::block_hash const & root_a, uint64_t const work_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::string const & peer_a, std::vector const & bad_peers_a, bool const completed_a = true, bool const cancelled_a = false); + message work_cancelled (nano::work_version const version_a, nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector const & bad_peers_a); + message work_failed (nano::work_version const version_a, nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector const & bad_peers_a); message bootstrap_started (std::string const & id_a, std::string const & mode_a); message bootstrap_exited (std::string const & id_a, std::string const & mode_a, std::chrono::steady_clock::time_point const start_time_a, uint64_t const total_blocks_a); diff --git a/nano/qt/qt.cpp b/nano/qt/qt.cpp index fab7b6157..38019d081 100644 --- a/nano/qt/qt.cpp +++ b/nano/qt/qt.cpp @@ -2229,7 +2229,7 @@ void nano_qt::block_creation::create_send () (void)error; assert (!error); nano::state_block send (account_l, info.head, info.representative, balance - amount_l.number (), destination_l, key, account_l, 0); - if (wallet.node.work_generate_blocking (send).is_initialized ()) + if (wallet.node.work_generate_blocking (nano::work_version::work_1, send).is_initialized ()) { std::string block_l; send.serialize_json (block_l); @@ -2308,7 +2308,7 @@ void nano_qt::block_creation::create_receive () if (!error) { nano::state_block receive (pending_key.account, info.head, info.representative, info.balance.number () + pending.amount.number (), source_l, key, pending_key.account, 0); - if (wallet.node.work_generate_blocking (receive).is_initialized ()) + if (wallet.node.work_generate_blocking (nano::work_version::work_1, receive).is_initialized ()) { std::string block_l; receive.serialize_json (block_l); @@ -2387,7 +2387,7 @@ void nano_qt::block_creation::create_change () if (!error) { nano::state_block change (account_l, info.head, representative_l, info.balance, 0, key, account_l, 0); - if (wallet.node.work_generate_blocking (change).is_initialized ()) + if (wallet.node.work_generate_blocking (nano::work_version::work_1, change).is_initialized ()) { std::string block_l; change.serialize_json (block_l); @@ -2464,7 +2464,7 @@ void nano_qt::block_creation::create_open () if (!error) { nano::state_block open (pending_key.account, 0, representative_l, pending.amount, source_l, key, pending_key.account, 0); - if (wallet.node.work_generate_blocking (open).is_initialized ()) + if (wallet.node.work_generate_blocking (nano::work_version::work_1, open).is_initialized ()) { std::string block_l; open.serialize_json (block_l); diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index 8b2278982..db7d54328 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -3045,7 +3045,7 @@ TEST (rpc, work_peer_bad) node2.config.work_peers.push_back (std::make_pair (boost::asio::ip::address_v6::any ().to_string (), 0)); nano::block_hash hash1 (1); std::atomic work (0); - node2.work_generate (hash1, [&work](boost::optional work_a) { + node2.work_generate (nano::work_version::work_1, hash1, [&work](boost::optional work_a) { ASSERT_TRUE (work_a.is_initialized ()); work = *work_a; }); @@ -3075,7 +3075,7 @@ TEST (rpc, work_peer_one) node2.config.work_peers.push_back (std::make_pair (node1.network.endpoint ().address ().to_string (), rpc.config.port)); nano::keypair key1; uint64_t work (0); - node2.work_generate (key1.pub, [&work](boost::optional work_a) { + node2.work_generate (nano::work_version::work_1, key1.pub, [&work](boost::optional work_a) { ASSERT_TRUE (work_a.is_initialized ()); work = *work_a; }); @@ -3122,7 +3122,7 @@ TEST (rpc, work_peer_many) for (auto i (0); i < works.size (); ++i) { nano::keypair key1; - node1.work_generate (key1.pub, [& work = works[i]](boost::optional work_a) { + node1.work_generate (nano::work_version::work_1, key1.pub, [& work = works[i]](boost::optional work_a) { work = *work_a; }); while (nano::work_validate (key1.pub, works[i])) @@ -3136,6 +3136,48 @@ TEST (rpc, work_peer_many) node1.stop (); } +TEST (rpc, work_version_invalid) +{ + nano::system system; + auto node = add_ipc_enabled_node (system); + scoped_io_thread_name_change scoped_thread_name_io; + nano::node_rpc_config node_rpc_config; + nano::ipc::ipc_server ipc_server (*node, node_rpc_config); + nano::rpc_config rpc_config (nano::get_available_port (), true); + rpc_config.rpc_process.ipc_port = node->config.ipc_config.transport_tcp.port; + nano::ipc_rpc_processor ipc_rpc_processor (system.io_ctx, rpc_config); + nano::rpc rpc (system.io_ctx, rpc_config, ipc_rpc_processor); + rpc.start (); + nano::block_hash hash (1); + boost::property_tree::ptree request; + request.put ("action", "work_generate"); + request.put ("hash", hash.to_string ()); + request.put ("version", "work_invalid"); + { + test_response response (request, rpc.config.port, system.io_ctx); + system.deadline_set (5s); + while (response.status == 0) + { + ASSERT_NO_ERROR (system.poll ()); + } + ASSERT_EQ (200, response.status); + ASSERT_EQ (1, response.json.count ("error")); + ASSERT_EQ (std::error_code (nano::error_rpc::bad_work_version).message (), response.json.get ("error")); + } + request.put ("action", "work_validate"); + { + test_response response (request, rpc.config.port, system.io_ctx); + system.deadline_set (5s); + while (response.status == 0) + { + ASSERT_NO_ERROR (system.poll ()); + } + ASSERT_EQ (200, response.status); + ASSERT_EQ (1, response.json.count ("error")); + ASSERT_EQ (std::error_code (nano::error_rpc::bad_work_version).message (), response.json.get ("error")); + } +} + TEST (rpc, block_count) { { diff --git a/nano/secure/ledger.cpp b/nano/secure/ledger.cpp index 38dd17488..0fbdde352 100644 --- a/nano/secure/ledger.cpp +++ b/nano/secure/ledger.cpp @@ -754,7 +754,7 @@ nano::uint128_t nano::ledger::account_pending (nano::transaction const & transac nano::process_return nano::ledger::process (nano::write_transaction const & transaction_a, nano::block const & block_a, nano::signature_verification verification) { - assert (!nano::work_validate (block_a)); + assert (!nano::work_validate (nano::work_version::work_1, block_a)); ledger_processor processor (*this, transaction_a, verification); block_a.visit (processor); if (processor.result.code == nano::process_result::progress)