diff --git a/nano/core_test/rpc.cpp b/nano/core_test/rpc.cpp index 6a3b13740..2bcedd401 100644 --- a/nano/core_test/rpc.cpp +++ b/nano/core_test/rpc.cpp @@ -1952,6 +1952,49 @@ TEST (rpc, work_generate) ASSERT_FALSE (nano::work_validate (hash1, work2)); } +TEST (rpc, work_generate_difficulty) +{ + nano::system system (24000, 1); + nano::node_init init1; + auto node1 (system.nodes[0]); + nano::rpc rpc (system.io_ctx, *system.nodes[0], nano::rpc_config (true)); + rpc.start (); + nano::block_hash hash1 (1); + uint64_t difficulty1 (0xfff0000000000000); + boost::property_tree::ptree request1; + request1.put ("action", "work_generate"); + request1.put ("hash", hash1.to_string ()); + request1.put ("difficulty", nano::to_string_hex (difficulty1)); + test_response response1 (request1, rpc, system.io_ctx); + system.deadline_set (5s); + while (response1.status == 0) + { + ASSERT_NO_ERROR (system.poll ()); + } + ASSERT_EQ (200, response1.status); + auto work_text1 (response1.json.get ("work")); + uint64_t work1; + ASSERT_FALSE (nano::from_string_hex (work_text1, work1)); + uint64_t result_difficulty1; + ASSERT_FALSE (nano::work_validate (hash1, work1, &result_difficulty1)); + ASSERT_GE (result_difficulty1, difficulty1); + uint64_t difficulty2 (0xffff000000000000); + request1.put ("difficulty", nano::to_string_hex (difficulty2)); + test_response response2 (request1, rpc, system.io_ctx); + system.deadline_set (10s); + while (response2.status == 0) + { + ASSERT_NO_ERROR (system.poll ()); + } + ASSERT_EQ (200, response2.status); + auto work_text2 (response2.json.get ("work")); + uint64_t work2; + ASSERT_FALSE (nano::from_string_hex (work_text2, work2)); + uint64_t result_difficulty2; + ASSERT_FALSE (nano::work_validate (hash1, work2, &result_difficulty2)); + ASSERT_GE (result_difficulty2, difficulty2); +} + TEST (rpc, work_cancel) { nano::system system (24000, 1); diff --git a/nano/lib/errors.cpp b/nano/lib/errors.cpp index 369abbab9..53ede4b10 100644 --- a/nano/lib/errors.cpp +++ b/nano/lib/errors.cpp @@ -116,6 +116,8 @@ std::string nano::error_rpc_messages::message (int ev) const return "Unknown error"; case nano::error_rpc::bad_destination: return "Bad destination account"; + case nano::error_rpc::bad_difficulty_format: + return "Bad difficulty"; case nano::error_rpc::bad_key: return "Bad key"; case nano::error_rpc::bad_link: diff --git a/nano/lib/errors.hpp b/nano/lib/errors.hpp index 86ac654a4..de68ea231 100644 --- a/nano/lib/errors.hpp +++ b/nano/lib/errors.hpp @@ -74,6 +74,7 @@ enum class error_rpc { generic = 1, bad_destination, + bad_difficulty_format, bad_key, bad_link, bad_previous, diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 4dd5d375a..34dfc4a39 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -2269,6 +2269,7 @@ public: boost::property_tree::ptree request; request.put ("action", "work_generate"); request.put ("hash", this_l->root.to_string ()); + request.put ("difficulty", nano::to_string_hex (this_l->difficulty)); std::stringstream ostream; boost::property_tree::write_json (ostream, request); request_string = ostream.str (); @@ -2365,14 +2366,15 @@ public: uint64_t work; if (!nano::from_string_hex (work_text, work)) { - if (!nano::work_validate (root, work)) + uint64_t result_difficulty (0); + if (!nano::work_validate (root, work, &result_difficulty) && result_difficulty >= difficulty) { set_once (work); stop (); } else { - node->logger.try_log (boost::str (boost::format ("Incorrect work response from %1% for root %2%: %3%") % address % root.to_string () % work_text)); + node->logger.try_log (boost::str (boost::format ("Incorrect work response from %1% for root %2% with diffuculty %3%: %4%") % address % root.to_string () % nano::to_string_hex (difficulty) % work_text)); handle_failure (last); } } diff --git a/nano/node/rpc.cpp b/nano/node/rpc.cpp index a89f119ee..cb2982338 100644 --- a/nano/node/rpc.cpp +++ b/nano/node/rpc.cpp @@ -4152,6 +4152,15 @@ void nano::rpc_handler::work_generate () { rpc_control_impl (); auto hash (hash_impl ()); + uint64_t difficulty (nano::work_pool::publish_threshold); + boost::optional difficulty_text (request.get_optional ("difficulty")); + if (!ec && difficulty_text.is_initialized ()) + { + if (nano::from_string_hex (difficulty_text.get (), difficulty)) + { + ec = nano::error_rpc::bad_difficulty_format; + } + } if (!ec) { bool use_peers (request.get_optional ("use_peers") == true); @@ -4170,11 +4179,11 @@ void nano::rpc_handler::work_generate () }; if (!use_peers) { - node.work.generate (hash, callback); + node.work.generate (hash, callback, difficulty); } else { - node.work_generate (hash, callback); + node.work_generate (hash, callback, difficulty); } } // Because of callback