RPC unopened (#1727)
* Add RPC unopened to get unopened accounts with pending blocks * Format * Faster approach using pending tables * Avoid using unordered map and exclude the burn account * Add test for burn account * Check for account number overflow * Change RPC response format * Add edge case with no accounts * Only add if pending>0 * Require RPC control * Check for errors * Add starting 'account' and total 'count' options.
This commit is contained in:
parent
a67aa3f524
commit
36b46547bb
3 changed files with 187 additions and 0 deletions
|
@ -4361,6 +4361,125 @@ TEST (rpc, stats_clear)
|
|||
ASSERT_LE (system.nodes[0]->stats.last_reset ().count (), 5);
|
||||
}
|
||||
|
||||
TEST (rpc, unopened)
|
||||
{
|
||||
nano::system system (24000, 1);
|
||||
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
|
||||
auto transaction (system.wallet (0)->wallets.tx_begin_write ());
|
||||
nano::account account1 (1), account2 (account1.number () + 1);
|
||||
auto genesis (system.nodes[0]->latest (nano::test_genesis_key.pub));
|
||||
ASSERT_FALSE (genesis.is_zero ());
|
||||
auto send (system.wallet (0)->send_action (nano::test_genesis_key.pub, account1, 1));
|
||||
ASSERT_NE (nullptr, send);
|
||||
auto send2 (system.wallet (0)->send_action (nano::test_genesis_key.pub, account2, 2));
|
||||
ASSERT_NE (nullptr, send2);
|
||||
nano::rpc rpc (system.io_ctx, *system.nodes[0], nano::rpc_config (true));
|
||||
rpc.start ();
|
||||
{
|
||||
boost::property_tree::ptree request;
|
||||
request.put ("action", "unopened");
|
||||
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 & accounts (response.json.get_child ("accounts"));
|
||||
ASSERT_EQ (2, accounts.size ());
|
||||
ASSERT_EQ ("1", accounts.get<std::string> (account1.to_account ()));
|
||||
ASSERT_EQ ("2", accounts.get<std::string> (account2.to_account ()));
|
||||
}
|
||||
{
|
||||
// starting at second account should get a single result
|
||||
boost::property_tree::ptree request;
|
||||
request.put ("action", "unopened");
|
||||
request.put ("account", account2.to_account ());
|
||||
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 & accounts (response.json.get_child ("accounts"));
|
||||
ASSERT_EQ (1, accounts.size ());
|
||||
ASSERT_EQ ("2", accounts.get<std::string> (account2.to_account ()));
|
||||
}
|
||||
{
|
||||
// starting at third account should get no results
|
||||
boost::property_tree::ptree request;
|
||||
request.put ("action", "unopened");
|
||||
request.put ("account", nano::account (account2.number () + 1).to_account ());
|
||||
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 & accounts (response.json.get_child ("accounts"));
|
||||
ASSERT_EQ (0, accounts.size ());
|
||||
}
|
||||
{
|
||||
// using count=1 should get a single result
|
||||
boost::property_tree::ptree request;
|
||||
request.put ("action", "unopened");
|
||||
request.put ("count", "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 & accounts (response.json.get_child ("accounts"));
|
||||
ASSERT_EQ (1, accounts.size ());
|
||||
ASSERT_EQ ("1", accounts.get<std::string> (account1.to_account ()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST (rpc, unopened_burn)
|
||||
{
|
||||
nano::system system (24000, 1);
|
||||
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
|
||||
auto genesis (system.nodes[0]->latest (nano::test_genesis_key.pub));
|
||||
ASSERT_FALSE (genesis.is_zero ());
|
||||
auto send (system.wallet (0)->send_action (nano::test_genesis_key.pub, nano::burn_account, 1));
|
||||
ASSERT_NE (nullptr, send);
|
||||
nano::rpc rpc (system.io_ctx, *system.nodes[0], nano::rpc_config (true));
|
||||
rpc.start ();
|
||||
boost::property_tree::ptree request;
|
||||
request.put ("action", "unopened");
|
||||
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 & accounts (response.json.get_child ("accounts"));
|
||||
ASSERT_EQ (0, accounts.size ());
|
||||
}
|
||||
|
||||
TEST (rpc, unopened_no_accounts)
|
||||
{
|
||||
nano::system system (24000, 1);
|
||||
nano::rpc rpc (system.io_ctx, *system.nodes[0], nano::rpc_config (true));
|
||||
rpc.start ();
|
||||
boost::property_tree::ptree request;
|
||||
request.put ("action", "unopened");
|
||||
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 & accounts (response.json.get_child ("accounts"));
|
||||
ASSERT_EQ (0, accounts.size ());
|
||||
}
|
||||
|
||||
TEST (rpc, uptime)
|
||||
{
|
||||
nano::system system (24000, 1);
|
||||
|
|
|
@ -3243,6 +3243,69 @@ void nano::rpc_handler::unchecked_keys ()
|
|||
response_errors ();
|
||||
}
|
||||
|
||||
void nano::rpc_handler::unopened ()
|
||||
{
|
||||
rpc_control_impl ();
|
||||
if (!ec)
|
||||
{
|
||||
auto count (count_optional_impl ());
|
||||
nano::account start (1); // exclude burn account by default
|
||||
boost::optional<std::string> account_text (request.get_optional<std::string> ("account"));
|
||||
if (account_text.is_initialized ())
|
||||
{
|
||||
if (start.decode_account (account_text.get ()))
|
||||
{
|
||||
ec = nano::error_common::bad_account_number;
|
||||
}
|
||||
}
|
||||
if (!ec)
|
||||
{
|
||||
auto transaction (node.store.tx_begin_read ());
|
||||
auto iterator (node.store.pending_begin (transaction, nano::pending_key (start, 0)));
|
||||
auto end (node.store.pending_end ());
|
||||
nano::account current_account (start);
|
||||
nano::uint128_t current_account_sum{ 0 };
|
||||
boost::property_tree::ptree accounts;
|
||||
while (iterator != end && accounts.size () < count)
|
||||
{
|
||||
nano::pending_key key (iterator->first);
|
||||
nano::account account (key.account);
|
||||
nano::pending_info info (iterator->second);
|
||||
if (node.store.account_exists (transaction, account))
|
||||
{
|
||||
if (account.number () == std::numeric_limits<nano::uint256_t>::max ())
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Skip existing accounts
|
||||
iterator = node.store.pending_begin (transaction, nano::pending_key (account.number () + 1, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (account != current_account)
|
||||
{
|
||||
if (current_account_sum > 0)
|
||||
{
|
||||
accounts.put (current_account.to_account (), current_account_sum.convert_to<std::string> ());
|
||||
current_account_sum = 0;
|
||||
}
|
||||
current_account = account;
|
||||
}
|
||||
current_account_sum += info.amount.number ();
|
||||
++iterator;
|
||||
}
|
||||
}
|
||||
// last one after iterator reaches end
|
||||
if (current_account_sum > 0 && accounts.size () < count)
|
||||
{
|
||||
accounts.put (current_account.to_account (), current_account_sum.convert_to<std::string> ());
|
||||
}
|
||||
response_l.add_child ("accounts", accounts);
|
||||
}
|
||||
}
|
||||
response_errors ();
|
||||
}
|
||||
|
||||
void nano::rpc_handler::uptime ()
|
||||
{
|
||||
response_l.put ("seconds", std::chrono::duration_cast<std::chrono::seconds> (std::chrono::steady_clock::now () - node.startup_time).count ());
|
||||
|
@ -4536,6 +4599,10 @@ void nano::rpc_handler::process_request ()
|
|||
{
|
||||
unchecked_keys ();
|
||||
}
|
||||
else if (action == "unopened")
|
||||
{
|
||||
unopened ();
|
||||
}
|
||||
else if (action == "uptime")
|
||||
{
|
||||
uptime ();
|
||||
|
|
|
@ -166,6 +166,7 @@ public:
|
|||
void unchecked_clear ();
|
||||
void unchecked_get ();
|
||||
void unchecked_keys ();
|
||||
void unopened ();
|
||||
void uptime ();
|
||||
void validate_account_number ();
|
||||
void version ();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue