RPC pending - sort by amount (#1748)

* Add 'sorting' option to 'pending' RPC. Change response to include the amount even if threshold is not provided.

* Change to not break the RPC, response is still a list if using the simple version
This commit is contained in:
Guilherme Lawless 2019-03-10 21:11:30 +00:00 committed by Sergey Kroshnin
commit 02db8a6dbf
2 changed files with 97 additions and 56 deletions

View file

@ -1758,74 +1758,98 @@ TEST (rpc, pending)
request.put ("action", "pending");
request.put ("account", key1.pub.to_account ());
request.put ("count", "100");
test_response response (request, rpc, system.io_ctx);
system.deadline_set (5s);
while (response.status == 0)
{
ASSERT_NO_ERROR (system.poll ());
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"));
ASSERT_EQ (1, blocks_node.size ());
nano::block_hash hash (blocks_node.begin ()->second.get<std::string> (""));
ASSERT_EQ (block1->hash (), hash);
}
request.put ("sorting", "true"); // Sorting test
{
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"));
ASSERT_EQ (1, blocks_node.size ());
nano::block_hash hash (blocks_node.begin ()->first);
ASSERT_EQ (block1->hash (), hash);
std::string amount (blocks_node.begin ()->second.get<std::string> (""));
ASSERT_EQ ("100", amount);
}
ASSERT_EQ (200, response.status);
auto & blocks_node (response.json.get_child ("blocks"));
ASSERT_EQ (1, blocks_node.size ());
nano::block_hash hash1 (blocks_node.begin ()->second.get<std::string> (""));
ASSERT_EQ (block1->hash (), hash1);
request.put ("threshold", "100"); // Threshold test
test_response response0 (request, rpc, system.io_ctx);
system.deadline_set (5s);
while (response0.status == 0)
{
ASSERT_NO_ERROR (system.poll ());
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"));
ASSERT_EQ (1, blocks_node.size ());
std::unordered_map<nano::block_hash, nano::uint128_union> blocks;
for (auto i (blocks_node.begin ()), j (blocks_node.end ()); i != j; ++i)
{
nano::block_hash hash;
hash.decode_hex (i->first);
nano::uint128_union amount;
amount.decode_dec (i->second.get<std::string> (""));
blocks[hash] = amount;
boost::optional<std::string> source (i->second.get_optional<std::string> ("source"));
ASSERT_FALSE (source.is_initialized ());
boost::optional<uint8_t> min_version (i->second.get_optional<uint8_t> ("min_version"));
ASSERT_FALSE (min_version.is_initialized ());
}
ASSERT_EQ (blocks[block1->hash ()], 100);
}
ASSERT_EQ (200, response0.status);
blocks_node = response0.json.get_child ("blocks");
ASSERT_EQ (1, blocks_node.size ());
std::unordered_map<nano::block_hash, nano::uint128_union> blocks;
for (auto i (blocks_node.begin ()), j (blocks_node.end ()); i != j; ++i)
{
nano::block_hash hash;
hash.decode_hex (i->first);
nano::uint128_union amount;
amount.decode_dec (i->second.get<std::string> (""));
blocks[hash] = amount;
boost::optional<std::string> source (i->second.get_optional<std::string> ("source"));
ASSERT_FALSE (source.is_initialized ());
boost::optional<uint8_t> min_version (i->second.get_optional<uint8_t> ("min_version"));
ASSERT_FALSE (min_version.is_initialized ());
}
ASSERT_EQ (blocks[block1->hash ()], 100);
request.put ("threshold", "101");
test_response response1 (request, rpc, system.io_ctx);
while (response1.status == 0)
{
ASSERT_NO_ERROR (system.poll ());
test_response response (request, rpc, system.io_ctx);
while (response.status == 0)
{
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (200, response.status);
auto & blocks_node (response.json.get_child ("blocks"));
ASSERT_EQ (0, blocks_node.size ());
}
ASSERT_EQ (200, response1.status);
blocks_node = response1.json.get_child ("blocks");
ASSERT_EQ (0, blocks_node.size ());
request.put ("threshold", "0");
request.put ("source", "true");
request.put ("min_version", "true");
test_response response2 (request, rpc, system.io_ctx);
system.deadline_set (5s);
while (response2.status == 0)
{
ASSERT_NO_ERROR (system.poll ());
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"));
ASSERT_EQ (1, blocks_node.size ());
std::unordered_map<nano::block_hash, nano::uint128_union> amounts;
std::unordered_map<nano::block_hash, nano::account> sources;
for (auto i (blocks_node.begin ()), j (blocks_node.end ()); i != j; ++i)
{
nano::block_hash hash;
hash.decode_hex (i->first);
amounts[hash].decode_dec (i->second.get<std::string> ("amount"));
sources[hash].decode_account (i->second.get<std::string> ("source"));
ASSERT_EQ (i->second.get<uint8_t> ("min_version"), 0);
}
ASSERT_EQ (amounts[block1->hash ()], 100);
ASSERT_EQ (sources[block1->hash ()], nano::test_genesis_key.pub);
}
ASSERT_EQ (200, response2.status);
blocks_node = response2.json.get_child ("blocks");
ASSERT_EQ (1, blocks_node.size ());
std::unordered_map<nano::block_hash, nano::uint128_union> amounts;
std::unordered_map<nano::block_hash, nano::account> sources;
for (auto i (blocks_node.begin ()), j (blocks_node.end ()); i != j; ++i)
{
nano::block_hash hash;
hash.decode_hex (i->first);
amounts[hash].decode_dec (i->second.get<std::string> ("amount"));
sources[hash].decode_account (i->second.get<std::string> ("source"));
ASSERT_EQ (i->second.get<uint8_t> ("min_version"), 0);
}
ASSERT_EQ (amounts[block1->hash ()], 100);
ASSERT_EQ (sources[block1->hash ()], nano::test_genesis_key.pub);
}
TEST (rpc_config, serialization)

View file

@ -2319,6 +2319,8 @@ void nano::rpc_handler::pending ()
const bool source = request.get<bool> ("source", false);
const bool min_version = request.get<bool> ("min_version", false);
const bool include_active = request.get<bool> ("include_active", false);
const bool sorting = request.get<bool> ("sorting", false);
auto simple (threshold.is_zero () && !source && !min_version && !sorting); // if simple, response is a list of hashes
if (!ec)
{
boost::property_tree::ptree peers_l;
@ -2328,7 +2330,7 @@ void nano::rpc_handler::pending ()
nano::pending_key key (i->first);
if (include_active || node.ledger.block_confirmed (transaction, key.hash))
{
if (threshold.is_zero () && !source && !min_version)
if (simple)
{
boost::property_tree::ptree entry;
entry.put ("", key.hash.to_string ());
@ -2361,6 +2363,21 @@ void nano::rpc_handler::pending ()
}
}
}
if (sorting && !simple)
{
if (source || min_version)
{
peers_l.sort ([](const auto & child1, const auto & child2) -> bool {
return child1.second.template get<nano::uint128_t> ("amount") > child2.second.template get<nano::uint128_t> ("amount");
});
}
else
{
peers_l.sort ([](const auto & child1, const auto & child2) -> bool {
return child1.second.template get<nano::uint128_t> ("") > child2.second.template get<nano::uint128_t> ("");
});
}
}
response_l.add_child ("blocks", peers_l);
}
response_errors ();