From 510a91ef30f8a08986ea15f7c5a6e9b456661142 Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Thu, 24 Jan 2019 01:21:48 +0300 Subject: [PATCH] Add optional "offset" & "reverse" parameters for RPC chain (#1622) --- nano/core_test/rpc.cpp | 43 +++++++++++++++++++++ nano/node/rpc.cpp | 86 ++++++++++++++++++++++++------------------ nano/node/rpc.hpp | 1 + 3 files changed, 94 insertions(+), 36 deletions(-) diff --git a/nano/core_test/rpc.cpp b/nano/core_test/rpc.cpp index 0953dff7..4aeb5654 100644 --- a/nano/core_test/rpc.cpp +++ b/nano/core_test/rpc.cpp @@ -925,6 +925,39 @@ TEST (rpc, chain_limit) ASSERT_EQ (block->hash (), blocks[0]); } +TEST (rpc, chain_offset) +{ + nano::system system (24000, 1); + system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv); + nano::keypair key; + auto genesis (system.nodes[0]->latest (nano::test_genesis_key.pub)); + ASSERT_FALSE (genesis.is_zero ()); + auto block (system.wallet (0)->send_action (nano::test_genesis_key.pub, key.pub, 1)); + ASSERT_NE (nullptr, block); + nano::rpc rpc (system.io_ctx, *system.nodes[0], nano::rpc_config (true)); + rpc.start (); + boost::property_tree::ptree request; + request.put ("action", "chain"); + request.put ("block", block->hash ().to_string ()); + request.put ("count", std::to_string (std::numeric_limits::max ())); + request.put ("offset", 1); + test_response response (request, rpc, system.io_ctx); + system.deadline_set (5s); + while (response.status == 0) + { + ASSERT_NO_ERROR (system.poll ()); + } + ASSERT_EQ (200, response.status); + auto & blocks_node (response.json.get_child ("blocks")); + std::vector blocks; + for (auto i (blocks_node.begin ()), n (blocks_node.end ()); i != n; ++i) + { + blocks.push_back (nano::block_hash (i->second.get (""))); + } + ASSERT_EQ (1, blocks.size ()); + ASSERT_EQ (genesis, blocks[0]); +} + TEST (rpc, frontier) { nano::system system (24000, 1); @@ -2302,6 +2335,16 @@ TEST (rpc, successors) ASSERT_EQ (2, blocks.size ()); ASSERT_EQ (genesis, blocks[0]); ASSERT_EQ (block->hash (), blocks[1]); + // RPC chain "reverse" option + request.put ("action", "chain"); + request.put ("reverse", "true"); + test_response response2 (request, rpc, system.io_ctx); + while (response2.status == 0) + { + ASSERT_NO_ERROR (system.poll ()); + } + ASSERT_EQ (200, response2.status); + ASSERT_EQ (response.json, response2.json); } TEST (rpc, bootstrap_any) diff --git a/nano/node/rpc.cpp b/nano/node/rpc.cpp index 53401d15..33931973 100644 --- a/nano/node/rpc.cpp +++ b/nano/node/rpc.cpp @@ -337,6 +337,19 @@ uint64_t nano::rpc_handler::count_optional_impl (uint64_t result) return result; } +uint64_t nano::rpc_handler::offset_optional_impl (uint64_t result) +{ + boost::optional offset_text (request.get_optional ("offset")); + if (!ec && offset_text.is_initialized ()) + { + if (decode_unsigned (offset_text.get (), result)) + { + ec = nano::error_rpc::invalid_offset; + } + } + return result; +} + bool nano::rpc_handler::rpc_control_impl () { bool result (false); @@ -1388,8 +1401,10 @@ void nano::rpc_handler::bootstrap_status () void nano::rpc_handler::chain (bool successors) { + successors = successors != request.get ("reverse", false); auto hash (hash_impl ("block")); auto count (count_impl ()); + auto offset (offset_optional_impl (0)); if (!ec) { boost::property_tree::ptree blocks; @@ -1399,9 +1414,16 @@ void nano::rpc_handler::chain (bool successors) auto block_l (node.store.block_get (transaction, hash)); if (block_l != nullptr) { - boost::property_tree::ptree entry; - entry.put ("", hash.to_string ()); - blocks.push_back (std::make_pair ("", entry)); + if (offset > 0) + { + --offset; + } + else + { + boost::property_tree::ptree entry; + entry.put ("", hash.to_string ()); + blocks.push_back (std::make_pair ("", entry)); + } hash = successors ? node.store.block_successor (transaction, hash) : block_l->previous (); } else @@ -1841,50 +1863,42 @@ void nano::rpc_handler::account_history () } } auto count (count_impl ()); + auto offset (offset_optional_impl (0)); if (!ec) { - uint64_t offset = 0; - auto offset_text (request.get_optional ("offset")); - if (!offset_text || !decode_unsigned (*offset_text, offset)) + boost::property_tree::ptree history; + response_l.put ("account", account.to_account ()); + auto block (node.store.block_get (transaction, hash)); + while (block != nullptr && count > 0) { - boost::property_tree::ptree history; - response_l.put ("account", account.to_account ()); - auto block (node.store.block_get (transaction, hash)); - while (block != nullptr && count > 0) + if (offset > 0) { - if (offset > 0) + --offset; + } + else + { + boost::property_tree::ptree entry; + history_visitor visitor (*this, output_raw, transaction, entry, hash); + block->visit (visitor); + if (!entry.empty ()) { - --offset; - } - else - { - boost::property_tree::ptree entry; - history_visitor visitor (*this, output_raw, transaction, entry, hash); - block->visit (visitor); - if (!entry.empty ()) + entry.put ("hash", hash.to_string ()); + if (output_raw) { - entry.put ("hash", hash.to_string ()); - if (output_raw) - { - entry.put ("work", nano::to_string_hex (block->block_work ())); - entry.put ("signature", block->block_signature ().to_string ()); - } - history.push_back (std::make_pair ("", entry)); - --count; + entry.put ("work", nano::to_string_hex (block->block_work ())); + entry.put ("signature", block->block_signature ().to_string ()); } + history.push_back (std::make_pair ("", entry)); + --count; } - hash = block->previous (); - block = node.store.block_get (transaction, hash); - } - response_l.add_child ("history", history); - if (!hash.is_zero ()) - { - response_l.put ("previous", hash.to_string ()); } + hash = block->previous (); + block = node.store.block_get (transaction, hash); } - else + response_l.add_child ("history", history); + if (!hash.is_zero ()) { - ec = nano::error_rpc::invalid_offset; + response_l.put ("previous", hash.to_string ()); } } response_errors (); diff --git a/nano/node/rpc.hpp b/nano/node/rpc.hpp index 772e65d3..03a852ad 100644 --- a/nano/node/rpc.hpp +++ b/nano/node/rpc.hpp @@ -240,6 +240,7 @@ public: uint64_t work_optional_impl (); uint64_t count_impl (); uint64_t count_optional_impl (uint64_t = std::numeric_limits::max ()); + uint64_t offset_optional_impl (uint64_t = 0); bool rpc_control_impl (); }; /** Returns the correct RPC implementation based on TLS configuration */