From c50a0489a0596f240e428f1b0b27d4ca1040fe7e Mon Sep 17 00:00:00 2001 From: Guilherme Lawless Date: Sun, 14 Jul 2019 14:08:46 +0100 Subject: [PATCH] Accept multiplier in work_generate and work_validate Add difficulty_optional_impl() and multiplier_optional_impl() Multiplier overrides difficulty if both given --- nano/lib/errors.cpp | 2 ++ nano/lib/errors.hpp | 1 + nano/node/json_handler.cpp | 60 ++++++++++++++++++++++------------ nano/node/json_handler.hpp | 2 ++ nano/rpc_test/rpc.cpp | 67 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 20 deletions(-) diff --git a/nano/lib/errors.cpp b/nano/lib/errors.cpp index 0c70e3c7d3..3adc7af8ba 100644 --- a/nano/lib/errors.cpp +++ b/nano/lib/errors.cpp @@ -124,6 +124,8 @@ std::string nano::error_rpc_messages::message (int ev) const return "Bad key"; case nano::error_rpc::bad_link: return "Bad link number"; + case nano::error_rpc::bad_multiplier_format: + return "Bad multiplier"; case nano::error_rpc::bad_previous: return "Bad previous"; case nano::error_rpc::bad_representative_number: diff --git a/nano/lib/errors.hpp b/nano/lib/errors.hpp index 2eba2ca6c8..3a5ec2fb52 100644 --- a/nano/lib/errors.hpp +++ b/nano/lib/errors.hpp @@ -75,6 +75,7 @@ enum class error_rpc bad_difficulty_format, bad_key, bad_link, + bad_multiplier_format, bad_previous, bad_representative_number, bad_source, diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index 385c57b31c..f700202392 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -321,6 +321,39 @@ uint64_t nano::json_handler::work_optional_impl () return result; } +uint64_t nano::json_handler::difficulty_optional_impl () +{ + uint64_t difficulty (node.network_params.network.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; + } + } + return difficulty; +} + +double nano::json_handler::multiplier_optional_impl (uint64_t & difficulty) +{ + double multiplier (1.); + boost::optional multiplier_text (request.get_optional ("multiplier")); + if (!ec && multiplier_text.is_initialized ()) + { + auto success = boost::conversion::try_lexical_convert (multiplier_text.get (), multiplier); + if (success && multiplier > 0.) + { + difficulty = nano::difficulty::from_multiplier (multiplier, node.network_params.network.publish_threshold); + } + else + { + ec = nano::error_rpc::bad_multiplier_format; + } + } + return multiplier; +} + namespace { bool decode_unsigned (std::string const & text, uint64_t & number) @@ -4387,15 +4420,8 @@ void nano::json_handler::wallet_work_get () void nano::json_handler::work_generate () { auto hash (hash_impl ()); - uint64_t difficulty (node.network_params.network.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; - } - } + auto difficulty (difficulty_optional_impl ()); + auto multiplier (multiplier_optional_impl (difficulty)); if (!ec && (difficulty > node_rpc_config.max_work_generate_difficulty || difficulty < node.network_params.network.publish_threshold)) { ec = nano::error_rpc::difficulty_limit; @@ -4491,23 +4517,17 @@ void nano::json_handler::work_validate () { auto hash (hash_impl ()); auto work (work_optional_impl ()); - uint64_t difficulty (node.network_params.network.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; - } - } + auto difficulty (difficulty_optional_impl ()); + auto multiplier (multiplier_optional_impl (difficulty)); + (void)multiplier; if (!ec) { uint64_t result_difficulty (0); nano::work_validate (hash, work, &result_difficulty); response_l.put ("valid", (result_difficulty >= difficulty) ? "1" : "0"); response_l.put ("difficulty", nano::to_string_hex (result_difficulty)); - auto multiplier = nano::difficulty::to_multiplier (result_difficulty, node.network_params.network.publish_threshold); - response_l.put ("multiplier", nano::to_string (multiplier)); + auto result_multiplier = nano::difficulty::to_multiplier (result_difficulty, node.network_params.network.publish_threshold); + response_l.put ("multiplier", nano::to_string (result_multiplier)); } response_errors (); } diff --git a/nano/node/json_handler.hpp b/nano/node/json_handler.hpp index 5fee7670ed..11796b07be 100644 --- a/nano/node/json_handler.hpp +++ b/nano/node/json_handler.hpp @@ -153,6 +153,8 @@ class json_handler : public std::enable_shared_from_this uint64_t count_impl (); uint64_t count_optional_impl (uint64_t = std::numeric_limits::max ()); uint64_t offset_optional_impl (uint64_t = 0); + uint64_t difficulty_optional_impl (); + double multiplier_optional_impl (uint64_t &); bool enable_sign_hash{ false }; std::function stop_callback; nano::node_rpc_config const & node_rpc_config; diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index b8e25d2742..41f54a5db5 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -2539,6 +2539,73 @@ TEST (rpc, work_generate_difficulty) } } +TEST (rpc, work_generate_multiplier) +{ + nano::system system (24000, 1); + auto node (system.nodes[0]); + enable_ipc_transport_tcp (node->config.ipc_config.transport_tcp); + nano::node_rpc_config node_rpc_config; + nano::ipc::ipc_server ipc_server (*node, node_rpc_config); + nano::rpc_config rpc_config (true); + 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 ()); + { + // When both difficulty and multiplier are given, should use multiplier + // Give base difficulty and very high multiplier to test + request.put ("difficulty", nano::to_string_hex (0xff00000000000000)); + double multiplier{ 100.0 }; + request.put ("multiplier", multiplier); + test_response response (request, rpc.config.port, system.io_ctx); + system.deadline_set (10s); + while (response.status == 0) + { + ASSERT_NO_ERROR (system.poll ()); + } + ASSERT_EQ (200, response.status); + auto work_text (response.json.get ("work")); + uint64_t work; + ASSERT_FALSE (nano::from_string_hex (work_text, work)); + uint64_t result_difficulty; + ASSERT_FALSE (nano::work_validate (hash, work, &result_difficulty)); + auto response_difficulty_text (response.json.get ("difficulty")); + uint64_t response_difficulty; + ASSERT_FALSE (nano::from_string_hex (response_difficulty_text, response_difficulty)); + ASSERT_EQ (result_difficulty, response_difficulty); + auto result_multiplier = response.json.get ("multiplier"); + ASSERT_GE (result_multiplier, multiplier); + } + { + request.put ("multiplier", -1.5); + 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); + std::error_code ec (nano::error_rpc::bad_multiplier_format); + ASSERT_EQ (response.json.get ("error"), ec.message ()); + } + { + double max_multiplier (nano::difficulty::to_multiplier (node_rpc_config.max_work_generate_difficulty, node->network_params.network.publish_threshold)); + request.put ("multiplier", max_multiplier + 1); + 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); + std::error_code ec (nano::error_rpc::difficulty_limit); + ASSERT_EQ (response.json.get ("error"), ec.message ()); + } +} + TEST (rpc, work_cancel) { nano::system system (24000, 1);