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:
		
					parent
					
						
							
								8f4c02c196
							
						
					
				
			
			
				commit
				
					
						02db8a6dbf
					
				
			
		
					 2 changed files with 97 additions and 56 deletions
				
			
		| 
						 | 
					@ -1758,74 +1758,98 @@ TEST (rpc, pending)
 | 
				
			||||||
	request.put ("action", "pending");
 | 
						request.put ("action", "pending");
 | 
				
			||||||
	request.put ("account", key1.pub.to_account ());
 | 
						request.put ("account", key1.pub.to_account ());
 | 
				
			||||||
	request.put ("count", "100");
 | 
						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
 | 
						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");
 | 
						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 ("threshold", "0");
 | 
				
			||||||
	request.put ("source", "true");
 | 
						request.put ("source", "true");
 | 
				
			||||||
	request.put ("min_version", "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)
 | 
					TEST (rpc_config, serialization)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2319,6 +2319,8 @@ void nano::rpc_handler::pending ()
 | 
				
			||||||
	const bool source = request.get<bool> ("source", false);
 | 
						const bool source = request.get<bool> ("source", false);
 | 
				
			||||||
	const bool min_version = request.get<bool> ("min_version", false);
 | 
						const bool min_version = request.get<bool> ("min_version", false);
 | 
				
			||||||
	const bool include_active = request.get<bool> ("include_active", 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)
 | 
						if (!ec)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		boost::property_tree::ptree peers_l;
 | 
							boost::property_tree::ptree peers_l;
 | 
				
			||||||
| 
						 | 
					@ -2328,7 +2330,7 @@ void nano::rpc_handler::pending ()
 | 
				
			||||||
			nano::pending_key key (i->first);
 | 
								nano::pending_key key (i->first);
 | 
				
			||||||
			if (include_active || node.ledger.block_confirmed (transaction, key.hash))
 | 
								if (include_active || node.ledger.block_confirmed (transaction, key.hash))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				if (threshold.is_zero () && !source && !min_version)
 | 
									if (simple)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					boost::property_tree::ptree entry;
 | 
										boost::property_tree::ptree entry;
 | 
				
			||||||
					entry.put ("", key.hash.to_string ());
 | 
										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_l.add_child ("blocks", peers_l);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	response_errors ();
 | 
						response_errors ();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue