diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index 7dfd06e39..5e35d99e0 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -1028,9 +1028,11 @@ void nano::json_handler::blocks_info () const bool pending = request.get ("pending", false); const bool source = request.get ("source", false); const bool json_block_l = request.get ("json_block", false); + const bool include_not_found = request.get ("include_not_found", false); std::vector hashes; boost::property_tree::ptree blocks; + boost::property_tree::ptree blocks_not_found; auto transaction (node.store.tx_begin_read ()); for (boost::property_tree::ptree::value_type & hashes : request.get_child ("hashes")) { @@ -1098,6 +1100,12 @@ void nano::json_handler::blocks_info () } blocks.push_back (std::make_pair (hash_text, entry)); } + else if (include_not_found) + { + boost::property_tree::ptree entry; + entry.put ("", hash_text); + blocks_not_found.push_back (std::make_pair ("", entry)); + } else { ec = nano::error_blocks::not_found; @@ -1109,7 +1117,14 @@ void nano::json_handler::blocks_info () } } } - response_l.add_child ("blocks", blocks); + if (!ec) + { + response_l.add_child ("blocks", blocks); + if (include_not_found) + { + response_l.add_child ("blocks_not_found", blocks_not_found); + } + } response_errors (); } diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index edab59215..4ab87e286 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -4467,54 +4467,89 @@ TEST (rpc, blocks_info) 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 (); + auto check_blocks = [&system](test_response & response) { + for (auto & blocks : response.json.get_child ("blocks")) + { + std::string hash_text (blocks.first); + ASSERT_EQ (system.nodes[0]->latest (nano::genesis_account).to_string (), hash_text); + std::string account_text (blocks.second.get ("block_account")); + ASSERT_EQ (nano::test_genesis_key.pub.to_account (), account_text); + std::string amount_text (blocks.second.get ("amount")); + ASSERT_EQ (nano::genesis_amount.convert_to (), amount_text); + std::string blocks_text (blocks.second.get ("contents")); + ASSERT_FALSE (blocks_text.empty ()); + boost::optional pending (blocks.second.get_optional ("pending")); + ASSERT_FALSE (pending.is_initialized ()); + boost::optional source (blocks.second.get_optional ("source_account")); + ASSERT_FALSE (source.is_initialized ()); + std::string balance_text (blocks.second.get ("balance")); + ASSERT_EQ (nano::genesis_amount.convert_to (), balance_text); + ASSERT_TRUE (blocks.second.get ("confirmed")); // Genesis block is confirmed by default + } + }; boost::property_tree::ptree request; request.put ("action", "blocks_info"); boost::property_tree::ptree entry; - boost::property_tree::ptree peers_l; + boost::property_tree::ptree hashes; entry.put ("", system.nodes[0]->latest (nano::genesis_account).to_string ()); - peers_l.push_back (std::make_pair ("", entry)); - request.add_child ("hashes", peers_l); - test_response response (request, rpc.config.port, system.io_ctx); - system.deadline_set (5s); - while (response.status == 0) + hashes.push_back (std::make_pair ("", entry)); + request.add_child ("hashes", hashes); { - ASSERT_NO_ERROR (system.poll ()); + 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); + check_blocks (response); } - ASSERT_EQ (200, response.status); - for (auto & blocks : response.json.get_child ("blocks")) + std::string random_hash = nano::block_hash ().to_string (); + entry.put ("", random_hash); + hashes.push_back (std::make_pair ("", entry)); + request.erase ("hashes"); + request.add_child ("hashes", hashes); { - std::string hash_text (blocks.first); - ASSERT_EQ (system.nodes[0]->latest (nano::genesis_account).to_string (), hash_text); - std::string account_text (blocks.second.get ("block_account")); - ASSERT_EQ (nano::test_genesis_key.pub.to_account (), account_text); - std::string amount_text (blocks.second.get ("amount")); - ASSERT_EQ (nano::genesis_amount.convert_to (), amount_text); - std::string blocks_text (blocks.second.get ("contents")); - ASSERT_FALSE (blocks_text.empty ()); - boost::optional pending (blocks.second.get_optional ("pending")); - ASSERT_FALSE (pending.is_initialized ()); - boost::optional source (blocks.second.get_optional ("source_account")); - ASSERT_FALSE (source.is_initialized ()); - std::string balance_text (blocks.second.get ("balance")); - ASSERT_EQ (nano::genesis_amount.convert_to (), balance_text); - ASSERT_TRUE (blocks.second.get ("confirmed")); // Genesis block is confirmed by default + 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 ("Block not found", response.json.get ("error")); + } + request.put ("include_not_found", "true"); + { + 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); + check_blocks (response); + auto & blocks_not_found (response.json.get_child ("blocks_not_found")); + ASSERT_EQ (1, blocks_not_found.size ()); + ASSERT_EQ (random_hash, blocks_not_found.begin ()->second.get ("")); } - // Test for optional values request.put ("source", "true"); request.put ("pending", "1"); - test_response response2 (request, rpc.config.port, system.io_ctx); - system.deadline_set (5s); - while (response2.status == 0) { - ASSERT_NO_ERROR (system.poll ()); - } - ASSERT_EQ (200, response2.status); - for (auto & blocks : response2.json.get_child ("blocks")) - { - std::string source (blocks.second.get ("source_account")); - ASSERT_EQ ("0", source); - std::string pending (blocks.second.get ("pending")); - ASSERT_EQ ("0", pending); + 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); + for (auto & blocks : response.json.get_child ("blocks")) + { + std::string source (blocks.second.get ("source_account")); + ASSERT_EQ ("0", source); + std::string pending (blocks.second.get ("pending")); + ASSERT_EQ ("0", pending); + } } } @@ -4540,15 +4575,15 @@ TEST (rpc, blocks_info_subtype) rpc.start (); boost::property_tree::ptree request; request.put ("action", "blocks_info"); - boost::property_tree::ptree peers_l; + boost::property_tree::ptree hashes; boost::property_tree::ptree entry; entry.put ("", send->hash ().to_string ()); - peers_l.push_back (std::make_pair ("", entry)); + hashes.push_back (std::make_pair ("", entry)); entry.put ("", receive->hash ().to_string ()); - peers_l.push_back (std::make_pair ("", entry)); + hashes.push_back (std::make_pair ("", entry)); entry.put ("", change->hash ().to_string ()); - peers_l.push_back (std::make_pair ("", entry)); - request.add_child ("hashes", peers_l); + hashes.push_back (std::make_pair ("", entry)); + request.add_child ("hashes", hashes); test_response response (request, rpc.config.port, system.io_ctx); system.deadline_set (5s); while (response.status == 0)