From 039428066acae5a3bf14f90e2f073aed72782d94 Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Sat, 4 Apr 2020 04:49:04 +0300 Subject: [PATCH 1/2] Difficulty calculation for RPC block_create --- nano/node/json_handler.cpp | 35 ++++++++ nano/rpc_test/rpc.cpp | 172 +++++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+) diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index 4b89e6666b..8a72ddf5ff 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -1574,6 +1574,41 @@ void nano::json_handler::block_create () { if (work == 0) { + // Difficulty calculation + if (!request.get_optional ("difficulty").is_initialized ()) + { + 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); + } node.work_generate (work_version, root_l, difficulty_l, get_callback_l (block_l), nano::account (pub)); } else diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index 7e92190ec8..6a28385e68 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -5999,10 +5999,14 @@ TEST (rpc, block_create_state_open) ASSERT_NE (nullptr, state_block); ASSERT_EQ (nano::block_type::state, state_block->type ()); ASSERT_EQ (state_hash, state_block->hash ().to_string ()); + auto difficulty (state_block->difficulty ()); + ASSERT_GT (difficulty, nano::work_threshold (state_block->work_version (), nano::block_details (nano::epoch::epoch_0, false, true, false))); ASSERT_TRUE (node->latest (key.pub).is_zero ()); scoped_thread_name_io.reset (); auto process_result (node->process (*state_block)); ASSERT_EQ (nano::process_result::progress, process_result.code); + ASSERT_EQ (state_block->sideband ().details.epoch, nano::epoch::epoch_0); + ASSERT_TRUE (state_block->sideband ().details.is_receive); ASSERT_FALSE (node->latest (key.pub).is_zero ()); } @@ -6054,6 +6058,174 @@ TEST (rpc, block_create_state_request_work) } } +TEST (rpc, block_create_open_epoch_v2) +{ + nano::system system; + auto node = add_ipc_enabled_node (system); + nano::keypair key; + nano::genesis genesis; + system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv); + ASSERT_NE (nullptr, system.upgrade_genesis_epoch (*node, nano::epoch::epoch_1)); + ASSERT_NE (nullptr, system.upgrade_genesis_epoch (*node, nano::epoch::epoch_2)); + auto send_block (system.wallet (0)->send_action (nano::test_genesis_key.pub, key.pub, nano::Gxrb_ratio)); + ASSERT_NE (nullptr, send_block); + boost::property_tree::ptree request; + request.put ("action", "block_create"); + request.put ("type", "state"); + request.put ("key", key.prv.data.to_string ()); + request.put ("account", key.pub.to_account ()); + request.put ("previous", 0); + request.put ("representative", nano::test_genesis_key.pub.to_account ()); + request.put ("balance", nano::Gxrb_ratio.convert_to ()); + request.put ("link", send_block->hash ().to_string ()); + 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 (); + 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::string state_hash (response.json.get ("hash")); + auto state_text (response.json.get ("block")); + std::stringstream block_stream (state_text); + boost::property_tree::ptree block_l; + boost::property_tree::read_json (block_stream, block_l); + auto state_block (nano::deserialize_block_json (block_l)); + ASSERT_NE (nullptr, state_block); + ASSERT_EQ (nano::block_type::state, state_block->type ()); + ASSERT_EQ (state_hash, state_block->hash ().to_string ()); + auto difficulty (state_block->difficulty ()); + ASSERT_GT (difficulty, nano::work_threshold (state_block->work_version (), nano::block_details (nano::epoch::epoch_2, false, true, false))); + ASSERT_TRUE (node->latest (key.pub).is_zero ()); + scoped_thread_name_io.reset (); + auto process_result (node->process (*state_block)); + ASSERT_EQ (nano::process_result::progress, process_result.code); + ASSERT_EQ (state_block->sideband ().details.epoch, nano::epoch::epoch_2); + ASSERT_TRUE (state_block->sideband ().details.is_receive); + ASSERT_FALSE (node->latest (key.pub).is_zero ()); +} + +TEST (rpc, block_create_receive_epoch_v2) +{ + nano::system system; + auto node = add_ipc_enabled_node (system); + nano::keypair key; + nano::genesis genesis; + system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv); + ASSERT_NE (nullptr, system.upgrade_genesis_epoch (*node, nano::epoch::epoch_1)); + auto send_block (system.wallet (0)->send_action (nano::test_genesis_key.pub, key.pub, nano::Gxrb_ratio)); + ASSERT_NE (nullptr, send_block); + nano::state_block open (key.pub, 0, nano::test_genesis_key.pub, nano::Gxrb_ratio, send_block->hash (), key.prv, key.pub, *node->work_generate_blocking (key.pub)); + ASSERT_EQ (nano::process_result::progress, node->process (open).code); + ASSERT_NE (nullptr, system.upgrade_genesis_epoch (*node, nano::epoch::epoch_2)); + auto send_block_2 (system.wallet (0)->send_action (nano::test_genesis_key.pub, key.pub, nano::Gxrb_ratio)); + boost::property_tree::ptree request; + request.put ("action", "block_create"); + request.put ("type", "state"); + request.put ("key", key.prv.data.to_string ()); + request.put ("account", key.pub.to_account ()); + request.put ("previous", open.hash ().to_string ()); + request.put ("representative", nano::test_genesis_key.pub.to_account ()); + request.put ("balance", (2 * nano::Gxrb_ratio).convert_to ()); + request.put ("link", send_block_2->hash ().to_string ()); + 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 (); + 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::string state_hash (response.json.get ("hash")); + auto state_text (response.json.get ("block")); + std::stringstream block_stream (state_text); + boost::property_tree::ptree block_l; + boost::property_tree::read_json (block_stream, block_l); + auto state_block (nano::deserialize_block_json (block_l)); + ASSERT_NE (nullptr, state_block); + ASSERT_EQ (nano::block_type::state, state_block->type ()); + ASSERT_EQ (state_hash, state_block->hash ().to_string ()); + auto difficulty (state_block->difficulty ()); + ASSERT_GT (difficulty, nano::work_threshold (state_block->work_version (), nano::block_details (nano::epoch::epoch_2, false, true, false))); + scoped_thread_name_io.reset (); + auto process_result (node->process (*state_block)); + ASSERT_EQ (nano::process_result::progress, process_result.code); + ASSERT_EQ (state_block->sideband ().details.epoch, nano::epoch::epoch_2); + ASSERT_TRUE (state_block->sideband ().details.is_receive); + ASSERT_FALSE (node->latest (key.pub).is_zero ()); +} + +TEST (rpc, block_create_send_epoch_v2) +{ + nano::system system; + auto node = add_ipc_enabled_node (system); + nano::keypair key; + nano::genesis genesis; + system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv); + ASSERT_NE (nullptr, system.upgrade_genesis_epoch (*node, nano::epoch::epoch_1)); + ASSERT_NE (nullptr, system.upgrade_genesis_epoch (*node, nano::epoch::epoch_2)); + auto send_block (system.wallet (0)->send_action (nano::test_genesis_key.pub, key.pub, nano::Gxrb_ratio)); + ASSERT_NE (nullptr, send_block); + nano::state_block open (key.pub, 0, nano::test_genesis_key.pub, nano::Gxrb_ratio, send_block->hash (), key.prv, key.pub, *node->work_generate_blocking (key.pub)); + ASSERT_EQ (nano::process_result::progress, node->process (open).code); + boost::property_tree::ptree request; + request.put ("action", "block_create"); + request.put ("type", "state"); + request.put ("key", key.prv.data.to_string ()); + request.put ("account", key.pub.to_account ()); + request.put ("previous", open.hash ().to_string ()); + request.put ("representative", nano::test_genesis_key.pub.to_account ()); + request.put ("balance", 0); + request.put ("link", nano::test_genesis_key.pub.to_string ()); + 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 (); + 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::string state_hash (response.json.get ("hash")); + auto state_text (response.json.get ("block")); + std::stringstream block_stream (state_text); + boost::property_tree::ptree block_l; + boost::property_tree::read_json (block_stream, block_l); + auto state_block (nano::deserialize_block_json (block_l)); + ASSERT_NE (nullptr, state_block); + ASSERT_EQ (nano::block_type::state, state_block->type ()); + ASSERT_EQ (state_hash, state_block->hash ().to_string ()); + auto difficulty (state_block->difficulty ()); + ASSERT_GT (difficulty, nano::work_threshold (state_block->work_version (), nano::block_details (nano::epoch::epoch_2, true, false, false))); + scoped_thread_name_io.reset (); + auto process_result (node->process (*state_block)); + ASSERT_EQ (nano::process_result::progress, process_result.code); + ASSERT_EQ (state_block->sideband ().details.epoch, nano::epoch::epoch_2); + ASSERT_TRUE (state_block->sideband ().details.is_send); + ASSERT_FALSE (node->latest (key.pub).is_zero ()); +} + TEST (rpc, block_hash) { nano::system system; From 9fceedf64ce9b0e1981e19222c78bc8cbb7a9042 Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Mon, 6 Apr 2020 17:19:09 +0300 Subject: [PATCH 2/2] Use count to find out if difficulty is defined --- nano/node/json_handler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index 8a72ddf5ff..fd376c048e 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -1575,7 +1575,7 @@ void nano::json_handler::block_create () if (work == 0) { // Difficulty calculation - if (!request.get_optional ("difficulty").is_initialized ()) + if (request.count ("difficulty") == 0) { nano::block_details details (nano::epoch::epoch_0, false, false, false); bool details_found (false);