From 78c4e1c6423717514969df826027fd5be4061ca6 Mon Sep 17 00:00:00 2001 From: Guilherme Lawless Date: Tue, 14 May 2019 13:15:01 +0100 Subject: [PATCH] Finish up difficulty/multiplier semantics in RPC work_generate and work_validate (#1981) * Add value and multiplier to RPC work_generate response * Use double for multiplier everywhere, no reason to lose precision * Change semantics in RPC responses from value to difficulty. - Changes for RPC work_generate and work_validate - Fixes getting lower precision in the multiplier of work_validate due to converting with std::string - Re-organize tests --- nano/node/json_handler.cpp | 15 ++-- nano/rpc_test/rpc.cpp | 151 +++++++++++++++++++++---------------- 2 files changed, 95 insertions(+), 71 deletions(-) diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index 14d56b11d..be455aab6 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -838,7 +838,7 @@ void nano::json_handler::active_difficulty () response_l.put ("difficulty_threshold", nano::to_string_hex (node.network_params.network.publish_threshold)); auto difficulty_active = node.active.active_difficulty (); response_l.put ("difficulty_active", nano::to_string_hex (difficulty_active)); - float multiplier = nano::difficulty::to_multiplier (difficulty_active, node.network_params.network.publish_threshold); + auto multiplier = nano::difficulty::to_multiplier (difficulty_active, node.network_params.network.publish_threshold); response_l.put ("multiplier", std::to_string (multiplier)); response_errors (); } @@ -4352,12 +4352,17 @@ void nano::json_handler::work_generate () { bool use_peers (request.get_optional ("use_peers") == true); auto rpc_l (shared_from_this ()); - auto callback = [rpc_l](boost::optional const & work_a) { + auto callback = [rpc_l, &hash, this](boost::optional const & work_a) { if (work_a) { boost::property_tree::ptree response_l; response_l.put ("work", nano::to_string_hex (work_a.value ())); std::stringstream ostream; + uint64_t result_difficulty; + nano::work_validate (hash, work_a.value (), &result_difficulty); + response_l.put ("difficulty", nano::to_string_hex (result_difficulty)); + auto multiplier = nano::difficulty::to_multiplier (result_difficulty, this->node.network_params.network.publish_threshold); + response_l.put ("multiplier", multiplier); boost::property_tree::write_json (ostream, response_l); rpc_l->response (ostream.str ()); } @@ -4448,9 +4453,9 @@ void nano::json_handler::work_validate () bool invalid (nano::work_validate (hash, work, &result_difficulty)); bool valid (!invalid && result_difficulty >= difficulty); response_l.put ("valid", valid ? "1" : "0"); - response_l.put ("value", nano::to_string_hex (result_difficulty)); - float multiplier = nano::difficulty::to_multiplier (result_difficulty, node.network_params.network.publish_threshold); - response_l.put ("multiplier", std::to_string (multiplier)); + 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", multiplier); } response_errors (); } diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index 0d26603e5..5d96f8e5a 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -2431,90 +2431,109 @@ TEST (rpc, version) TEST (rpc, work_generate) { nano::system system (24000, 1); - auto node1 (system.nodes[0]); + auto node (system.nodes[0]); nano::keypair key; system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv); system.wallet (0)->insert_adhoc (key.prv); - enable_ipc_transport_tcp (node1->config.ipc_config.transport_tcp); + enable_ipc_transport_tcp (node->config.ipc_config.transport_tcp); nano::node_rpc_config node_rpc_config; - nano::ipc::ipc_server ipc_server (*node1, 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 hash1 (1); - boost::property_tree::ptree request1; - request1.put ("action", "work_generate"); - request1.put ("hash", hash1.to_string ()); - test_response response1 (request1, rpc.config.port, system.io_ctx); + nano::block_hash hash (1); + boost::property_tree::ptree request; + request.put ("action", "work_generate"); + request.put ("hash", hash.to_string ()); + test_response response (request, rpc.config.port, system.io_ctx); system.deadline_set (5s); - while (response1.status == 0) + while (response.status == 0) { ASSERT_NO_ERROR (system.poll ()); } - ASSERT_EQ (200, response1.status); - auto work1 (response1.json.get ("work")); - uint64_t work2; - ASSERT_FALSE (nano::from_string_hex (work1, work2)); - ASSERT_FALSE (nano::work_validate (hash1, work2)); + ASSERT_EQ (200, response.status); + auto work_text (response.json.get ("work")); + uint64_t work, result_difficulty; + ASSERT_FALSE (nano::from_string_hex (work_text, work)); + 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 multiplier = response.json.get ("multiplier"); + ASSERT_EQ (nano::difficulty::to_multiplier (result_difficulty, node->network_params.network.publish_threshold), multiplier); } TEST (rpc, work_generate_difficulty) { nano::system system (24000, 1); - auto node1 (system.nodes[0]); - enable_ipc_transport_tcp (node1->config.ipc_config.transport_tcp); + 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 (*node1, 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 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.config.port, system.io_ctx); - system.deadline_set (10s); - while (response1.status == 0) + nano::block_hash hash (1); + boost::property_tree::ptree request; + request.put ("action", "work_generate"); + request.put ("hash", hash.to_string ()); { - ASSERT_NO_ERROR (system.poll ()); + uint64_t difficulty (0xfff0000000000000); + request.put ("difficulty", nano::to_string_hex (difficulty)); + 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 multiplier = response.json.get ("multiplier"); + // Expected multiplier from base threshold, not from the given difficulty + ASSERT_EQ (nano::difficulty::to_multiplier (result_difficulty, node->network_params.network.publish_threshold), multiplier); + ASSERT_GE (result_difficulty, difficulty); } - 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.config.port, system.io_ctx); - system.deadline_set (20s); - while (response2.status == 0) { - ASSERT_NO_ERROR (system.poll ()); + uint64_t difficulty (0xffff000000000000); + request.put ("difficulty", nano::to_string_hex (difficulty)); + test_response response (request, rpc.config.port, system.io_ctx); + system.deadline_set (20s); + 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)); + ASSERT_GE (result_difficulty, difficulty); } - 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); - uint64_t difficulty3 (node_rpc_config.max_work_generate_difficulty + 1); - request1.put ("difficulty", nano::to_string_hex (difficulty3)); - test_response response3 (request1, rpc.config.port, system.io_ctx); - system.deadline_set (5s); - while (response3.status == 0) { - ASSERT_NO_ERROR (system.poll ()); + uint64_t difficulty (node_rpc_config.max_work_generate_difficulty + 1); + request.put ("difficulty", nano::to_string_hex (difficulty)); + 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 ()); } - ASSERT_EQ (200, response3.status); - std::error_code ec (nano::error_rpc::difficulty_limit); - ASSERT_EQ (response3.json.get ("error"), ec.message ()); } TEST (rpc, work_cancel) @@ -3212,12 +3231,12 @@ TEST (rpc, work_validate) ASSERT_EQ (200, response.status); std::string validate_text (response.json.get ("valid")); ASSERT_EQ ("1", validate_text); - std::string value_text (response.json.get ("value")); - uint64_t value; - ASSERT_FALSE (nano::from_string_hex (value_text, value)); - ASSERT_GE (value, params.network.publish_threshold); + std::string difficulty_text (response.json.get ("difficulty")); + uint64_t difficulty; + ASSERT_FALSE (nano::from_string_hex (difficulty_text, difficulty)); + ASSERT_GE (difficulty, params.network.publish_threshold); double multiplier (response.json.get ("multiplier")); - ASSERT_NEAR (multiplier, nano::difficulty::to_multiplier (value, params.network.publish_threshold), 1e-6); + ASSERT_NEAR (multiplier, nano::difficulty::to_multiplier (difficulty, params.network.publish_threshold), 1e-6); } uint64_t work2 (0); request.put ("work", nano::to_string_hex (work2)); @@ -3231,12 +3250,12 @@ TEST (rpc, work_validate) ASSERT_EQ (200, response.status); std::string validate_text (response.json.get ("valid")); ASSERT_EQ ("0", validate_text); - std::string value_text (response.json.get ("value")); - uint64_t value; - ASSERT_FALSE (nano::from_string_hex (value_text, value)); - ASSERT_GE (params.network.publish_threshold, value); + std::string difficulty_text (response.json.get ("difficulty")); + uint64_t difficulty; + ASSERT_FALSE (nano::from_string_hex (difficulty_text, difficulty)); + ASSERT_GE (params.network.publish_threshold, difficulty); double multiplier (response.json.get ("multiplier")); - ASSERT_NEAR (multiplier, nano::difficulty::to_multiplier (value, params.network.publish_threshold), 1e-6); + ASSERT_NEAR (multiplier, nano::difficulty::to_multiplier (difficulty, params.network.publish_threshold), 1e-6); } uint64_t result_difficulty; ASSERT_FALSE (nano::work_validate (hash, work1, &result_difficulty));