From 67b02d35cf4932c07508099e33f08b659c6ebfaa Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Fri, 1 May 2020 13:24:31 +0300 Subject: [PATCH 01/12] Simplify block_impl () json/text retrieval --- nano/node/json_handler.cpp | 72 +++++++++----------------------------- nano/node/json_handler.hpp | 1 - 2 files changed, 17 insertions(+), 56 deletions(-) diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index 3120afda19..8ac53063df 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -268,19 +268,27 @@ nano::amount nano::json_handler::amount_impl () std::shared_ptr nano::json_handler::block_impl (bool signature_work_required) { + const bool json_block_l = request.get ("json_block", false); std::shared_ptr result{ nullptr }; if (!ec) { - std::string block_text (request.get ("block")); boost::property_tree::ptree block_l; - std::stringstream block_stream (block_text); - try + if (json_block_l) { - boost::property_tree::read_json (block_stream, block_l); + block_l = request.get_child ("block"); } - catch (...) + else { - ec = nano::error_blocks::invalid_block; + std::string block_text (request.get ("block")); + std::stringstream block_stream (block_text); + try + { + boost::property_tree::read_json (block_stream, block_l); + } + catch (...) + { + ec = nano::error_blocks::invalid_block; + } } if (!ec) { @@ -299,26 +307,6 @@ std::shared_ptr nano::json_handler::block_impl (bool signature_work return result; } -std::shared_ptr nano::json_handler::block_json_impl (bool signature_work_required) -{ - std::shared_ptr result; - if (!ec) - { - auto block_l (request.get_child ("block")); - if (!signature_work_required) - { - block_l.put ("signature", "0"); - block_l.put ("work", "0"); - } - result = nano::deserialize_block_json (block_l); - if (result == nullptr) - { - ec = nano::error_blocks::invalid_block; - } - } - return result; -} - nano::block_hash nano::json_handler::hash_impl (std::string search_text) { nano::block_hash result (0); @@ -1610,16 +1598,7 @@ void nano::json_handler::block_create () void nano::json_handler::block_hash () { - const bool json_block_l = request.get ("json_block", false); - std::shared_ptr block; - if (json_block_l) - { - block = block_json_impl (true); - } - else - { - block = block_impl (true); - } + auto block (block_impl (true)); if (!ec) { @@ -3014,17 +2993,8 @@ void nano::json_handler::payment_wait () void nano::json_handler::process () { node.worker.push_task (create_worker_task ([](std::shared_ptr const & rpc_l) { - const bool json_block_l = rpc_l->request.get ("json_block", false); const bool watch_work_l = rpc_l->request.get ("watch_work", true); - std::shared_ptr block; - if (json_block_l) - { - block = rpc_l->block_json_impl (true); - } - else - { - block = rpc_l->block_impl (true); - } + auto block (rpc_l->block_impl (true)); // State blocks subtype check if (!rpc_l->ec && block->type () == nano::block_type::state) @@ -3607,7 +3577,6 @@ void nano::json_handler::send () void nano::json_handler::sign () { - const bool json_block_l = request.get ("json_block", false); // Retrieving hash nano::block_hash hash (0); boost::optional hash_text (request.get_optional ("hash")); @@ -3620,14 +3589,7 @@ void nano::json_handler::sign () boost::optional block_text (request.get_optional ("block")); if (!ec && block_text.is_initialized ()) { - if (json_block_l) - { - block = block_json_impl (true); - } - else - { - block = block_impl (true); - } + block = block_impl (true); if (block != nullptr) { hash = block->hash (); diff --git a/nano/node/json_handler.hpp b/nano/node/json_handler.hpp index 2cd970d79e..78fa327197 100644 --- a/nano/node/json_handler.hpp +++ b/nano/node/json_handler.hpp @@ -154,7 +154,6 @@ class json_handler : public std::enable_shared_from_this nano::account_info account_info_impl (nano::transaction const &, nano::account const &); nano::amount amount_impl (); std::shared_ptr block_impl (bool = true); - std::shared_ptr block_json_impl (bool = true); nano::block_hash hash_impl (std::string = "hash"); nano::amount threshold_optional_impl (); uint64_t work_optional_impl (); From 758e5c0a23302cc699c73122c7fdf2f67f8d0f5b Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Fri, 1 May 2020 13:50:41 +0300 Subject: [PATCH 02/12] Optional block for work_generate () --- nano/lib/errors.cpp | 2 ++ nano/lib/errors.hpp | 1 + nano/node/json_handler.cpp | 27 ++++++++++++++++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/nano/lib/errors.cpp b/nano/lib/errors.cpp index ca29b70125..696ad77b36 100644 --- a/nano/lib/errors.cpp +++ b/nano/lib/errors.cpp @@ -163,6 +163,8 @@ std::string nano::error_rpc_messages::message (int ev) const return "Representative account and previous hash required"; case nano::error_rpc::block_create_requirements_send: return "Destination account, previous hash, current balance and amount required"; + case nano::error_rpc::block_root_mismatch: + return "Root mismatch for block"; case nano::error_rpc::confirmation_height_not_processing: return "There are no blocks currently being processed for adding confirmation height"; case nano::error_rpc::confirmation_not_found: diff --git a/nano/lib/errors.hpp b/nano/lib/errors.hpp index 570a3cabf0..d48d3e4222 100644 --- a/nano/lib/errors.hpp +++ b/nano/lib/errors.hpp @@ -94,6 +94,7 @@ enum class error_rpc block_create_requirements_receive, block_create_requirements_change, block_create_requirements_send, + block_root_mismatch, confirmation_height_not_processing, confirmation_not_found, difficulty_limit, diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index 8ac53063df..d87712fee0 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -4747,7 +4747,32 @@ void nano::json_handler::work_generate () { ec = nano::error_rpc::difficulty_limit; } - if (!ec) + // Retrieving optional block + std::shared_ptr block; + boost::optional block_text (request.get_optional ("block")); + if (!ec && block_text.is_initialized ()) + { + block = block_impl (true); + if (block != nullptr) + { + if (hash != block->root ()) + { + ec = nano::error_rpc::block_root_mismatch; + } + if (!ec && block->difficulty () >= difficulty) + { + // If optional block difficulty if higher than requested difficulty, send response immediately + response_l.put ("hash", hash.to_string ()); + response_l.put ("work", nano::to_string_hex (block->block_work ())); + auto result_difficulty (nano::work_difficulty (work_version, hash, block->block_work ())); + response_l.put ("difficulty", nano::to_string_hex (result_difficulty)); + auto result_multiplier = nano::difficulty::to_multiplier (result_difficulty, node.default_difficulty (work_version)); + response_l.put ("multiplier", nano::to_string (result_multiplier)); + response_errors (); + } + } + } + if (!ec && response_l.empty ()) { auto use_peers (request.get ("use_peers", false)); auto rpc_l (shared_from_this ()); From 4c3f0ab0beefbfde008452b13822798ec96e35b6 Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Fri, 1 May 2020 15:02:43 +0300 Subject: [PATCH 03/12] Test for "work_generate" with block --- nano/node/json_handler.cpp | 1 + nano/rpc_test/rpc.cpp | 134 +++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index d87712fee0..4c46da5da0 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -3577,6 +3577,7 @@ void nano::json_handler::send () void nano::json_handler::sign () { + const bool json_block_l = request.get ("json_block", false); // Retrieving hash nano::block_hash hash (0); boost::optional hash_text (request.get_optional ("hash")); diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index b4b33c0cc9..f9f666bdc8 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -3157,6 +3157,140 @@ TEST (rpc, work_generate_epoch_2) } } +TEST (rpc, work_generate_block) +{ + 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::keypair key; + nano::state_block block (key.pub, 0, nano::test_genesis_key.pub, nano::Gxrb_ratio, 123, key.prv, key.pub, *node->work_generate_blocking (key.pub)); + nano::block_hash hash (block.root ()); + auto block_difficulty (nano::work_difficulty (nano::work_version::work_1, hash, block.block_work ())); + boost::property_tree::ptree request; + request.put ("action", "work_generate"); + request.put ("hash", hash.to_string ()); + request.put ("json_block", "true"); + boost::property_tree::ptree json; + block.serialize_json (json); + request.add_child ("block", json); + { + 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); + auto work_text (response.json.get_optional ("work")); + if (!work_text) + { + std::cout << response.json.get ("error") << std::endl; + } + ASSERT_TRUE (work_text.is_initialized ()); + uint64_t work; + ASSERT_FALSE (nano::from_string_hex (*work_text, work)); + ASSERT_EQ (block.block_work (), work); + auto result_difficulty (nano::work_difficulty (nano::work_version::work_1, hash, work)); + 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); + ASSERT_EQ (block_difficulty, result_difficulty); + } +} + +TEST (rpc, work_generate_block_low) +{ + 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::keypair key; + nano::state_block block (key.pub, 0, nano::test_genesis_key.pub, nano::Gxrb_ratio, 123, key.prv, key.pub, *node->work_generate_blocking (key.pub)); + nano::block_hash hash (block.root ()); + auto block_difficulty (nano::work_difficulty (nano::work_version::work_1, hash, block.block_work ())); + boost::property_tree::ptree request; + request.put ("action", "work_generate"); + request.put ("hash", hash.to_string ()); + request.put ("difficulty", nano::to_string_hex (block_difficulty + 1)); + request.put ("json_block", "false"); + std::string json; + block.serialize_json (json); + request.put ("block", json); + { + 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_optional ("work")); + if (!work_text) + { + std::cout << response.json.get ("error") << std::endl; + } + ASSERT_TRUE (work_text.is_initialized ()); + uint64_t work; + ASSERT_FALSE (nano::from_string_hex (*work_text, work)); + ASSERT_NE (block.block_work (), work); + auto result_difficulty (nano::work_difficulty (nano::work_version::work_1, hash, work)); + 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); + ASSERT_LT (block_difficulty, result_difficulty); + } +} + +TEST (rpc, work_generate_block_root_mismatch) +{ + 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::keypair key; + nano::state_block block (key.pub, 0, nano::test_genesis_key.pub, nano::Gxrb_ratio, 123, key.prv, key.pub, *node->work_generate_blocking (key.pub)); + nano::block_hash hash (1); + boost::property_tree::ptree request; + request.put ("action", "work_generate"); + request.put ("hash", hash.to_string ()); + request.put ("json_block", "false"); + std::string json; + block.serialize_json (json); + request.put ("block", json); + { + 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::block_root_mismatch).message (), response.json.get ("error")); + } +} + TEST (rpc, work_cancel) { nano::system system; From 72b0ed99ba3f5a14761b09d577709aa1d01b8593 Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Fri, 1 May 2020 15:39:12 +0300 Subject: [PATCH 04/12] Apply Guilherme review --- nano/node/json_handler.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index 4c46da5da0..0b4fa33576 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -3587,8 +3587,7 @@ void nano::json_handler::sign () } // Retrieving block std::shared_ptr block; - boost::optional block_text (request.get_optional ("block")); - if (!ec && block_text.is_initialized ()) + if (!ec && request.count ("block")) { block = block_impl (true); if (block != nullptr) @@ -4750,8 +4749,7 @@ void nano::json_handler::work_generate () } // Retrieving optional block std::shared_ptr block; - boost::optional block_text (request.get_optional ("block")); - if (!ec && block_text.is_initialized ()) + if (!ec && request.count ("block")) { block = block_impl (true); if (block != nullptr) @@ -4762,7 +4760,7 @@ void nano::json_handler::work_generate () } if (!ec && block->difficulty () >= difficulty) { - // If optional block difficulty if higher than requested difficulty, send response immediately + // If optional block difficulty is higher than requested difficulty, send response immediately response_l.put ("hash", hash.to_string ()); response_l.put ("work", nano::to_string_hex (block->block_work ())); auto result_difficulty (nano::work_difficulty (work_version, hash, block->block_work ())); From 5767ede3d75350d380933627223eaaaaab4883e6 Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Fri, 1 May 2020 16:41:24 +0300 Subject: [PATCH 05/12] Difficulty from previous block function for "block_create" & "work_generate" --- nano/node/json_handler.cpp | 78 ++++++++++++++++++++++---------------- nano/node/json_handler.hpp | 1 + nano/rpc_test/rpc.cpp | 57 ++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 32 deletions(-) diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index 0b4fa33576..05f608178f 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -363,6 +363,45 @@ uint64_t nano::json_handler::difficulty_optional_impl (nano::work_version const return difficulty; } +uint64_t nano::json_handler::difficulty_ledger (nano::block const & block_a, nano::work_version const version_a) +{ + uint64_t difficulty (0); + nano::block_details details (nano::epoch::epoch_0, false, false, false); + bool details_found (false); + auto transaction (node.store.tx_begin_read ()); + // Previous block find + std::shared_ptr block_previous (nullptr); + auto previous (block_a.previous ()); + if (!previous.is_zero ()) + { + block_previous = node.store.block_get (transaction, previous); + } + // Send check + if (block_previous != nullptr) + { + details.is_send = node.store.block_balance (transaction, previous) > block_a.balance ().number (); + details_found = true; + } + // Epoch check + if (block_previous != nullptr) + { + details.epoch = block_previous->sideband ().details.epoch; + } + auto link (block_a.link ()); + if (!link.is_zero () && !details.is_send) + { + auto block_link (node.store.block_get (transaction, link)); + if (block_link != nullptr && node.store.pending_exists (transaction, nano::pending_key (block_a.account (), link))) + { + details.epoch = std::max (details.epoch, block_link->sideband ().details.epoch); + details.is_receive = true; + details_found = true; + } + } + difficulty = details_found ? nano::work_threshold (version_a, details) : node.default_difficulty (version_a); + return difficulty; +} + double nano::json_handler::multiplier_optional_impl (nano::work_version const version_a, uint64_t & difficulty) { double multiplier (1.); @@ -1543,37 +1582,7 @@ void nano::json_handler::block_create () // Difficulty calculation if (request.count ("difficulty") == 0) { - nano::block_details details (nano::epoch::epoch_0, false, false, false); - bool details_found (false); - auto transaction (node.store.tx_begin_read ()); - // Previous block find - std::shared_ptr block_previous (nullptr); - if (!previous.is_zero ()) - { - block_previous = node.store.block_get (transaction, previous); - } - // Send check - if (block_previous != nullptr) - { - details.is_send = node.store.block_balance (transaction, previous) > balance.number (); - details_found = true; - } - // Epoch check - if (block_previous != nullptr) - { - details.epoch = block_previous->sideband ().details.epoch; - } - if (!link.is_zero () && !details.is_send) - { - auto block_link (node.store.block_get (transaction, link)); - if (block_link != nullptr && node.store.pending_exists (transaction, nano::pending_key (pub, link))) - { - details.epoch = std::max (details.epoch, block_link->sideband ().details.epoch); - details.is_receive = true; - details_found = true; - } - } - difficulty_l = details_found ? nano::work_threshold (work_version, details) : node.default_difficulty (work_version); + difficulty_l = difficulty_ledger (*block_l, work_version); } node.work_generate (work_version, root_l, difficulty_l, get_callback_l (block_l), nano::account (pub)); } @@ -4758,9 +4767,14 @@ void nano::json_handler::work_generate () { ec = nano::error_rpc::block_root_mismatch; } + // Difficulty calculation + if (!ec && request.count ("difficulty") == 0 && request.count ("multiplier") == 0) + { + difficulty = difficulty_ledger (*block, work_version); + } + // If optional block difficulty is higher than requested difficulty, send response immediately if (!ec && block->difficulty () >= difficulty) { - // If optional block difficulty is higher than requested difficulty, send response immediately response_l.put ("hash", hash.to_string ()); response_l.put ("work", nano::to_string_hex (block->block_work ())); auto result_difficulty (nano::work_difficulty (work_version, hash, block->block_work ())); diff --git a/nano/node/json_handler.hpp b/nano/node/json_handler.hpp index 78fa327197..35568500a7 100644 --- a/nano/node/json_handler.hpp +++ b/nano/node/json_handler.hpp @@ -161,6 +161,7 @@ class json_handler : public std::enable_shared_from_this uint64_t count_optional_impl (uint64_t = std::numeric_limits::max ()); uint64_t offset_optional_impl (uint64_t = 0); uint64_t difficulty_optional_impl (nano::work_version const); + uint64_t difficulty_ledger (nano::block const &, nano::work_version const); double multiplier_optional_impl (nano::work_version const, uint64_t &); nano::work_version work_version_optional_impl (nano::work_version const default_a); bool enable_sign_hash{ false }; diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index f9f666bdc8..4eda610f83 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -3291,6 +3291,63 @@ TEST (rpc, work_generate_block_root_mismatch) } } +TEST (rpc, work_generate_block_ledger_epoch_2) +{ + nano::system system; + auto node = add_ipc_enabled_node (system); + auto epoch1 = system.upgrade_genesis_epoch (*node, nano::epoch::epoch_1); + ASSERT_NE (nullptr, epoch1); + auto epoch2 = system.upgrade_genesis_epoch (*node, nano::epoch::epoch_2); + ASSERT_NE (nullptr, epoch2); + nano::keypair key; + system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv); + auto send_block (system.wallet (0)->send_action (nano::test_genesis_key.pub, key.pub, nano::Gxrb_ratio)); + ASSERT_NE (nullptr, send_block); + 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::state_block block (key.pub, 0, nano::test_genesis_key.pub, nano::Gxrb_ratio, send_block->hash (), key.prv, key.pub, 0); + nano::block_hash hash (block.root ()); + boost::property_tree::ptree request; + request.put ("action", "work_generate"); + request.put ("hash", hash.to_string ()); + request.put ("json_block", "false"); + std::string json; + block.serialize_json (json); + request.put ("block", json); + bool finished (false); + while (!finished) + { + 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_optional ("work")); + if (!work_text) + { + std::cout << response.json.get ("error") << std::endl; + } + ASSERT_TRUE (work_text.is_initialized ()); + uint64_t work; + ASSERT_FALSE (nano::from_string_hex (*work_text, work)); + auto result_difficulty (nano::work_difficulty (nano::work_version::work_1, hash, work)); + 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); + ASSERT_GE (result_difficulty, node->network_params.network.publish_thresholds.epoch_2_receive); + finished = result_difficulty < node->network_params.network.publish_thresholds.epoch_1; + } +} + TEST (rpc, work_cancel) { nano::system system; From f1eebc6f556be404ebd0346227ac7797cb9e7255 Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Fri, 1 May 2020 16:42:41 +0300 Subject: [PATCH 06/12] Limit iterations for test --- nano/rpc_test/rpc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index 4eda610f83..2b6015b4a5 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -3321,6 +3321,7 @@ TEST (rpc, work_generate_block_ledger_epoch_2) block.serialize_json (json); request.put ("block", json); bool finished (false); + auto iteration (0); while (!finished) { test_response response (request, rpc.config.port, system.io_ctx); @@ -3345,6 +3346,7 @@ TEST (rpc, work_generate_block_ledger_epoch_2) ASSERT_EQ (result_difficulty, response_difficulty); ASSERT_GE (result_difficulty, node->network_params.network.publish_thresholds.epoch_2_receive); finished = result_difficulty < node->network_params.network.publish_thresholds.epoch_1; + ASSERT_LT (++iteration, 200); } } From 1d718aa1228ba57bda4ecb60949e0282d6104c28 Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Mon, 4 May 2020 14:54:11 +0300 Subject: [PATCH 07/12] Use work version from block, return error if provided work is enough --- nano/lib/errors.cpp | 4 ++++ nano/lib/errors.hpp | 2 ++ nano/node/json_handler.cpp | 26 ++++++++++++++------------ nano/node/json_handler.hpp | 2 +- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/nano/lib/errors.cpp b/nano/lib/errors.cpp index 696ad77b36..29aac08de1 100644 --- a/nano/lib/errors.cpp +++ b/nano/lib/errors.cpp @@ -165,6 +165,10 @@ std::string nano::error_rpc_messages::message (int ev) const return "Destination account, previous hash, current balance and amount required"; case nano::error_rpc::block_root_mismatch: return "Root mismatch for block"; + case nano::error_rpc::block_work_enough: + return "Provided work is already enough for given difficulty"; + case nano::error_rpc::block_work_version_mismatch: + return "Work version mismatch for block"; case nano::error_rpc::confirmation_height_not_processing: return "There are no blocks currently being processed for adding confirmation height"; case nano::error_rpc::confirmation_not_found: diff --git a/nano/lib/errors.hpp b/nano/lib/errors.hpp index d48d3e4222..6a78034d1d 100644 --- a/nano/lib/errors.hpp +++ b/nano/lib/errors.hpp @@ -95,6 +95,8 @@ enum class error_rpc block_create_requirements_change, block_create_requirements_send, block_root_mismatch, + block_work_enough, + block_work_version_mismatch, confirmation_height_not_processing, confirmation_not_found, difficulty_limit, diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index 05f608178f..4a2d4f1c3a 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -363,7 +363,7 @@ uint64_t nano::json_handler::difficulty_optional_impl (nano::work_version const return difficulty; } -uint64_t nano::json_handler::difficulty_ledger (nano::block const & block_a, nano::work_version const version_a) +uint64_t nano::json_handler::difficulty_ledger (nano::block const & block_a) { uint64_t difficulty (0); nano::block_details details (nano::epoch::epoch_0, false, false, false); @@ -398,7 +398,7 @@ uint64_t nano::json_handler::difficulty_ledger (nano::block const & block_a, nan details_found = true; } } - difficulty = details_found ? nano::work_threshold (version_a, details) : node.default_difficulty (version_a); + difficulty = details_found ? nano::work_threshold (block_a.work_version (), details) : node.default_difficulty (block_a.work_version ()); return difficulty; } @@ -1582,7 +1582,7 @@ void nano::json_handler::block_create () // Difficulty calculation if (request.count ("difficulty") == 0) { - difficulty_l = difficulty_ledger (*block_l, work_version); + difficulty_l = difficulty_ledger (*block_l); } node.work_generate (work_version, root_l, difficulty_l, get_callback_l (block_l), nano::account (pub)); } @@ -4767,21 +4767,23 @@ void nano::json_handler::work_generate () { ec = nano::error_rpc::block_root_mismatch; } + if (request.count ("version") == 0) + { + work_version = block->work_version (); + } + else if (!ec && work_version != block->work_version ()) + { + ec = nano::error_rpc::block_work_version_mismatch; + } // Difficulty calculation if (!ec && request.count ("difficulty") == 0 && request.count ("multiplier") == 0) { - difficulty = difficulty_ledger (*block, work_version); + difficulty = difficulty_ledger (*block); } - // If optional block difficulty is higher than requested difficulty, send response immediately + // If optional block difficulty is higher than requested difficulty, send error if (!ec && block->difficulty () >= difficulty) { - response_l.put ("hash", hash.to_string ()); - response_l.put ("work", nano::to_string_hex (block->block_work ())); - auto result_difficulty (nano::work_difficulty (work_version, hash, block->block_work ())); - response_l.put ("difficulty", nano::to_string_hex (result_difficulty)); - auto result_multiplier = nano::difficulty::to_multiplier (result_difficulty, node.default_difficulty (work_version)); - response_l.put ("multiplier", nano::to_string (result_multiplier)); - response_errors (); + ec = nano::error_rpc::block_work_enough; } } } diff --git a/nano/node/json_handler.hpp b/nano/node/json_handler.hpp index 35568500a7..f739ab6eca 100644 --- a/nano/node/json_handler.hpp +++ b/nano/node/json_handler.hpp @@ -161,7 +161,7 @@ class json_handler : public std::enable_shared_from_this uint64_t count_optional_impl (uint64_t = std::numeric_limits::max ()); uint64_t offset_optional_impl (uint64_t = 0); uint64_t difficulty_optional_impl (nano::work_version const); - uint64_t difficulty_ledger (nano::block const &, nano::work_version const); + uint64_t difficulty_ledger (nano::block const &); double multiplier_optional_impl (nano::work_version const, uint64_t &); nano::work_version work_version_optional_impl (nano::work_version const default_a); bool enable_sign_hash{ false }; From 708126ccd8b3edb0517faea64c489ad8d59071dc Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Mon, 4 May 2020 17:31:31 +0300 Subject: [PATCH 08/12] Change test for new behavior --- nano/rpc_test/rpc.cpp | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index 2b6015b4a5..f431eca02d 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -3157,7 +3157,7 @@ TEST (rpc, work_generate_epoch_2) } } -TEST (rpc, work_generate_block) +TEST (rpc, work_generate_block_high) { nano::system system; auto node = add_ipc_enabled_node (system); @@ -3188,21 +3188,8 @@ TEST (rpc, work_generate_block) ASSERT_NO_ERROR (system.poll ()); } ASSERT_EQ (200, response.status); - auto work_text (response.json.get_optional ("work")); - if (!work_text) - { - std::cout << response.json.get ("error") << std::endl; - } - ASSERT_TRUE (work_text.is_initialized ()); - uint64_t work; - ASSERT_FALSE (nano::from_string_hex (*work_text, work)); - ASSERT_EQ (block.block_work (), work); - auto result_difficulty (nano::work_difficulty (nano::work_version::work_1, hash, work)); - 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); - ASSERT_EQ (block_difficulty, result_difficulty); + ASSERT_EQ (1, response.json.count ("error")); + ASSERT_EQ (std::error_code (nano::error_rpc::block_work_enough).message (), response.json.get ("error")); } } From 56f5c15fcc268a576ecf6ea3b6a4fee575f1d359 Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Tue, 5 May 2020 16:21:25 +0300 Subject: [PATCH 09/12] Remove leftover --- nano/rpc_test/rpc.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index f431eca02d..fd2558ce2a 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -3226,10 +3226,6 @@ TEST (rpc, work_generate_block_low) } ASSERT_EQ (200, response.status); auto work_text (response.json.get_optional ("work")); - if (!work_text) - { - std::cout << response.json.get ("error") << std::endl; - } ASSERT_TRUE (work_text.is_initialized ()); uint64_t work; ASSERT_FALSE (nano::from_string_hex (*work_text, work)); @@ -3319,10 +3315,6 @@ TEST (rpc, work_generate_block_ledger_epoch_2) } ASSERT_EQ (200, response.status); auto work_text (response.json.get_optional ("work")); - if (!work_text) - { - std::cout << response.json.get ("error") << std::endl; - } ASSERT_TRUE (work_text.is_initialized ()); uint64_t work; ASSERT_FALSE (nano::from_string_hex (*work_text, work)); From 6b11c10887e0797994177db670dbf5059989a132 Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Tue, 5 May 2020 16:45:34 +0300 Subject: [PATCH 10/12] Simplify difficulty_ledger () --- nano/node/json_handler.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index 4a2d4f1c3a..6b23e9dafa 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -365,7 +365,6 @@ uint64_t nano::json_handler::difficulty_optional_impl (nano::work_version const uint64_t nano::json_handler::difficulty_ledger (nano::block const & block_a) { - uint64_t difficulty (0); nano::block_details details (nano::epoch::epoch_0, false, false, false); bool details_found (false); auto transaction (node.store.tx_begin_read ()); @@ -398,8 +397,7 @@ uint64_t nano::json_handler::difficulty_ledger (nano::block const & block_a) details_found = true; } } - difficulty = details_found ? nano::work_threshold (block_a.work_version (), details) : node.default_difficulty (block_a.work_version ()); - return difficulty; + return details_found ? nano::work_threshold (block_a.work_version (), details) : node.default_difficulty (block_a.work_version ()); } double nano::json_handler::multiplier_optional_impl (nano::work_version const version_a, uint64_t & difficulty) From 5d0ef12181ac2948a12e839b3922a843ae1bd922 Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Fri, 8 May 2020 20:02:55 +0300 Subject: [PATCH 11/12] Apply Guilherme patch --- nano/rpc_test/rpc.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index fd2558ce2a..e5cc7c291a 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -3054,10 +3054,6 @@ TEST (rpc, work_generate_multiplier) } ASSERT_EQ (200, response.status); auto work_text (response.json.get_optional ("work")); - if (!work_text) - { - std::cout << response.json.get ("error") << std::endl; - } ASSERT_TRUE (work_text.is_initialized ()); uint64_t work; ASSERT_FALSE (nano::from_string_hex (*work_text, work)); @@ -3206,9 +3202,11 @@ TEST (rpc, work_generate_block_low) nano::rpc rpc (system.io_ctx, rpc_config, ipc_rpc_processor); rpc.start (); nano::keypair key; - nano::state_block block (key.pub, 0, nano::test_genesis_key.pub, nano::Gxrb_ratio, 123, key.prv, key.pub, *node->work_generate_blocking (key.pub)); + nano::state_block block (key.pub, 0, nano::test_genesis_key.pub, nano::Gxrb_ratio, 123, key.prv, key.pub, 0); + auto threshold (node->default_difficulty (block.work_version ())); + block.block_work_set (system.work_generate_limited (block.root (), threshold, nano::difficulty::from_multiplier (node->config.max_work_generate_multiplier / 10, threshold))); nano::block_hash hash (block.root ()); - auto block_difficulty (nano::work_difficulty (nano::work_version::work_1, hash, block.block_work ())); + auto block_difficulty (block.difficulty ()); boost::property_tree::ptree request; request.put ("action", "work_generate"); request.put ("hash", hash.to_string ()); @@ -3295,6 +3293,8 @@ TEST (rpc, work_generate_block_ledger_epoch_2) nano::rpc rpc (system.io_ctx, rpc_config, ipc_rpc_processor); rpc.start (); nano::state_block block (key.pub, 0, nano::test_genesis_key.pub, nano::Gxrb_ratio, send_block->hash (), key.prv, key.pub, 0); + auto threshold (nano::work_threshold (block.work_version (), nano::block_details (nano::epoch::epoch_2, false, true, false))); + block.block_work_set (system.work_generate_limited (block.root (), 0, threshold - 1)); nano::block_hash hash (block.root ()); boost::property_tree::ptree request; request.put ("action", "work_generate"); From a95852efb3c4443a7a4ccd3e48b24125beca7d5a Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Fri, 8 May 2020 20:24:12 +0300 Subject: [PATCH 12/12] Apply Guilherme patch --- nano/node/testing.cpp | 1 + nano/rpc_test/rpc.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/nano/node/testing.cpp b/nano/node/testing.cpp index 3b25ed1a39..0bb20d45dc 100644 --- a/nano/node/testing.cpp +++ b/nano/node/testing.cpp @@ -164,6 +164,7 @@ nano::account nano::system::account (nano::transaction const & transaction_a, si uint64_t nano::system::work_generate_limited (nano::block_hash const & root_a, uint64_t min_a, uint64_t max_a) { + debug_assert (min_a > 0); uint64_t result = 0; do { diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index d18105f4d3..e623fee4e9 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -3362,7 +3362,7 @@ TEST (rpc, work_generate_block_ledger_epoch_2) rpc.start (); nano::state_block block (key.pub, 0, nano::test_genesis_key.pub, nano::Gxrb_ratio, send_block->hash (), key.prv, key.pub, 0); auto threshold (nano::work_threshold (block.work_version (), nano::block_details (nano::epoch::epoch_2, false, true, false))); - block.block_work_set (system.work_generate_limited (block.root (), 0, threshold - 1)); + block.block_work_set (system.work_generate_limited (block.root (), 1, threshold - 1)); nano::block_hash hash (block.root ()); boost::property_tree::ptree request; request.put ("action", "work_generate");