[Pruning] Support pruned chains in RPC & QT wallet (#2977)
* [Pruning] Support pruned chains in RPC & QT wallet Splitting https://github.com/nanocurrency/nano-node/pull/2881 * Several RPC calls are modified to support pruned blocks related to main request block. * RPC “history”: if previous block is pruned, “amount” field is not returned for all blocks, “account” field is not returned for state blocks, also state block type/subtype is “unknown” . If source is pruned, then “account” field is not returned for receive/open legacy & for receive/open state blocks. * RPC “block_info”/“blocks_info”: if previous block is pruned, “amount” field is not returned. RPC “block_count”: for nodes with enabled pruning returns 2 new fields: “full” blocks & “pruned” blocks. “full” + “pruned” = total “blocks”. * QT wallet history support for pruned chains * Remove not yet possible function * Update tests to cement blocks before pruning
This commit is contained in:
parent
22689a79ab
commit
8462acbc8a
4 changed files with 453 additions and 41 deletions
|
@ -1003,8 +1003,12 @@ void nano::json_handler::block_info ()
|
|||
{
|
||||
nano::account account (block->account ().is_zero () ? block->sideband ().account : block->account ());
|
||||
response_l.put ("block_account", account.to_account ());
|
||||
auto amount (node.ledger.amount (transaction, hash));
|
||||
response_l.put ("amount", amount.convert_to<std::string> ());
|
||||
bool error_or_pruned (false);
|
||||
auto amount (node.ledger.amount_safe (transaction, hash, error_or_pruned));
|
||||
if (!error_or_pruned)
|
||||
{
|
||||
response_l.put ("amount", amount.convert_to<std::string> ());
|
||||
}
|
||||
auto balance (node.ledger.balance (transaction, hash));
|
||||
response_l.put ("balance", balance.convert_to<std::string> ());
|
||||
response_l.put ("height", std::to_string (block->sideband ().height));
|
||||
|
@ -1067,11 +1071,15 @@ void nano::json_handler::block_confirm ()
|
|||
// Trigger callback for confirmed block
|
||||
node.block_arrival.add (hash);
|
||||
auto account (node.ledger.account (transaction, hash));
|
||||
auto amount (node.ledger.amount (transaction, hash));
|
||||
bool error_or_pruned (false);
|
||||
auto amount (node.ledger.amount_safe (transaction, hash, error_or_pruned));
|
||||
bool is_state_send (false);
|
||||
if (auto state = dynamic_cast<nano::state_block *> (block_l.get ()))
|
||||
if (!error_or_pruned)
|
||||
{
|
||||
is_state_send = node.ledger.is_send (transaction, *state);
|
||||
if (auto state = dynamic_cast<nano::state_block *> (block_l.get ()))
|
||||
{
|
||||
is_state_send = node.ledger.is_send (transaction, *state);
|
||||
}
|
||||
}
|
||||
node.observers.blocks.notify (status, account, amount, is_state_send);
|
||||
}
|
||||
|
@ -1153,8 +1161,12 @@ void nano::json_handler::blocks_info ()
|
|||
boost::property_tree::ptree entry;
|
||||
nano::account account (block->account ().is_zero () ? block->sideband ().account : block->account ());
|
||||
entry.put ("block_account", account.to_account ());
|
||||
auto amount (node.ledger.amount (transaction, hash));
|
||||
entry.put ("amount", amount.convert_to<std::string> ());
|
||||
bool error_or_pruned (false);
|
||||
auto amount (node.ledger.amount_safe (transaction, hash, error_or_pruned));
|
||||
if (!error_or_pruned)
|
||||
{
|
||||
entry.put ("amount", amount.convert_to<std::string> ());
|
||||
}
|
||||
auto balance (node.ledger.balance (transaction, hash));
|
||||
entry.put ("balance", balance.convert_to<std::string> ());
|
||||
entry.put ("height", std::to_string (block->sideband ().height));
|
||||
|
@ -1257,6 +1269,11 @@ void nano::json_handler::block_count ()
|
|||
response_l.put ("count", std::to_string (node.ledger.cache.block_count));
|
||||
response_l.put ("unchecked", std::to_string (node.store.unchecked_count (node.store.tx_begin_read ())));
|
||||
response_l.put ("cemented", std::to_string (node.ledger.cache.cemented_count));
|
||||
if (node.flags.enable_pruning)
|
||||
{
|
||||
response_l.put ("full", std::to_string (node.ledger.cache.block_count - node.ledger.cache.pruned_count));
|
||||
response_l.put ("pruned", std::to_string (node.ledger.cache.pruned_count));
|
||||
}
|
||||
response_errors ();
|
||||
}
|
||||
|
||||
|
@ -2180,8 +2197,12 @@ public:
|
|||
tree.put ("type", "send");
|
||||
auto account (block_a.hashables.destination.to_account ());
|
||||
tree.put ("account", account);
|
||||
auto amount (handler.node.ledger.amount (transaction, hash).convert_to<std::string> ());
|
||||
tree.put ("amount", amount);
|
||||
bool error_or_pruned (false);
|
||||
auto amount (handler.node.ledger.amount_safe (transaction, hash, error_or_pruned).convert_to<std::string> ());
|
||||
if (!error_or_pruned)
|
||||
{
|
||||
tree.put ("amount", amount);
|
||||
}
|
||||
if (raw)
|
||||
{
|
||||
tree.put ("destination", account);
|
||||
|
@ -2192,10 +2213,17 @@ public:
|
|||
void receive_block (nano::receive_block const & block_a)
|
||||
{
|
||||
tree.put ("type", "receive");
|
||||
auto account (handler.node.ledger.account (transaction, block_a.hashables.source).to_account ());
|
||||
tree.put ("account", account);
|
||||
auto amount (handler.node.ledger.amount (transaction, hash).convert_to<std::string> ());
|
||||
tree.put ("amount", amount);
|
||||
bool error_or_pruned (false);
|
||||
auto amount (handler.node.ledger.amount_safe (transaction, hash, error_or_pruned).convert_to<std::string> ());
|
||||
if (!error_or_pruned)
|
||||
{
|
||||
auto source_account (handler.node.ledger.account_safe (transaction, block_a.hashables.source, error_or_pruned));
|
||||
if (!error_or_pruned)
|
||||
{
|
||||
tree.put ("account", source_account.to_account ());
|
||||
}
|
||||
tree.put ("amount", amount);
|
||||
}
|
||||
if (raw)
|
||||
{
|
||||
tree.put ("source", block_a.hashables.source.to_string ());
|
||||
|
@ -2218,8 +2246,17 @@ public:
|
|||
}
|
||||
if (block_a.hashables.source != network_params.ledger.genesis_account)
|
||||
{
|
||||
tree.put ("account", handler.node.ledger.account (transaction, block_a.hashables.source).to_account ());
|
||||
tree.put ("amount", handler.node.ledger.amount (transaction, hash).convert_to<std::string> ());
|
||||
bool error_or_pruned (false);
|
||||
auto amount (handler.node.ledger.amount_safe (transaction, hash, error_or_pruned).convert_to<std::string> ());
|
||||
if (!error_or_pruned)
|
||||
{
|
||||
auto source_account (handler.node.ledger.account_safe (transaction, block_a.hashables.source, error_or_pruned));
|
||||
if (!error_or_pruned)
|
||||
{
|
||||
tree.put ("account", source_account.to_account ());
|
||||
}
|
||||
tree.put ("amount", amount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2247,8 +2284,20 @@ public:
|
|||
tree.put ("previous", block_a.hashables.previous.to_string ());
|
||||
}
|
||||
auto balance (block_a.hashables.balance.number ());
|
||||
auto previous_balance (handler.node.ledger.balance (transaction, block_a.hashables.previous));
|
||||
if (balance < previous_balance)
|
||||
bool error_or_pruned (false);
|
||||
auto previous_balance (handler.node.ledger.balance_safe (transaction, block_a.hashables.previous, error_or_pruned));
|
||||
if (error_or_pruned)
|
||||
{
|
||||
if (raw)
|
||||
{
|
||||
tree.put ("subtype", "unknown");
|
||||
}
|
||||
else
|
||||
{
|
||||
tree.put ("type", "unknown");
|
||||
}
|
||||
}
|
||||
else if (balance < previous_balance)
|
||||
{
|
||||
if (should_ignore_account (block_a.hashables.link.as_account ()))
|
||||
{
|
||||
|
@ -2285,8 +2334,8 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
auto account (handler.node.ledger.account (transaction, block_a.hashables.link.as_block_hash ()));
|
||||
if (should_ignore_account (account))
|
||||
auto source_account (handler.node.ledger.account_safe (transaction, block_a.hashables.link.as_block_hash (), error_or_pruned));
|
||||
if (!error_or_pruned && should_ignore_account (source_account))
|
||||
{
|
||||
tree.clear ();
|
||||
return;
|
||||
|
@ -2299,7 +2348,10 @@ public:
|
|||
{
|
||||
tree.put ("type", "receive");
|
||||
}
|
||||
tree.put ("account", account.to_account ());
|
||||
if (!error_or_pruned)
|
||||
{
|
||||
tree.put ("account", source_account.to_account ());
|
||||
}
|
||||
tree.put ("amount", (balance - previous_balance).convert_to<std::string> ());
|
||||
}
|
||||
}
|
||||
|
@ -3176,14 +3228,15 @@ void nano::json_handler::receive ()
|
|||
auto block (node.store.block_get (block_transaction, hash));
|
||||
if (block != nullptr)
|
||||
{
|
||||
if (node.store.pending_exists (block_transaction, nano::pending_key (account, hash)))
|
||||
nano::pending_info pending_info;
|
||||
if (!node.store.pending_get (block_transaction, nano::pending_key (account, hash), pending_info))
|
||||
{
|
||||
auto work (work_optional_impl ());
|
||||
if (!ec && work)
|
||||
{
|
||||
nano::account_info info;
|
||||
nano::root head;
|
||||
nano::epoch epoch = block->sideband ().details.epoch;
|
||||
nano::epoch epoch = pending_info.epoch;
|
||||
if (!node.store.account_get (block_transaction, account, info))
|
||||
{
|
||||
head = info.head;
|
||||
|
@ -4681,7 +4734,14 @@ void nano::json_handler::wallet_republish ()
|
|||
{
|
||||
hashes.push_back (latest);
|
||||
block = node.store.block_get (block_transaction, latest);
|
||||
latest = block->previous ();
|
||||
if (block != nullptr)
|
||||
{
|
||||
latest = block->previous ();
|
||||
}
|
||||
else
|
||||
{
|
||||
latest.clear ();
|
||||
}
|
||||
}
|
||||
std::reverse (hashes.begin (), hashes.end ());
|
||||
for (auto & hash : hashes)
|
||||
|
|
|
@ -522,13 +522,23 @@ public:
|
|||
{
|
||||
type = "Send";
|
||||
account = block_a.hashables.destination;
|
||||
amount = ledger.amount (transaction, block_a.hash ());
|
||||
bool error_or_pruned (false);
|
||||
amount = ledger.amount_safe (transaction, block_a.hash (), error_or_pruned);
|
||||
if (error_or_pruned)
|
||||
{
|
||||
type = "Send (pruned)";
|
||||
}
|
||||
}
|
||||
void receive_block (nano::receive_block const & block_a)
|
||||
{
|
||||
type = "Receive";
|
||||
account = ledger.account (transaction, block_a.source ());
|
||||
amount = ledger.amount (transaction, block_a.source ());
|
||||
bool error_or_pruned (false);
|
||||
account = ledger.account_safe (transaction, block_a.hashables.source, error_or_pruned);
|
||||
amount = ledger.amount_safe (transaction, block_a.hash (), error_or_pruned);
|
||||
if (error_or_pruned)
|
||||
{
|
||||
type = "Receive (pruned)";
|
||||
}
|
||||
}
|
||||
void open_block (nano::open_block const & block_a)
|
||||
{
|
||||
|
@ -536,8 +546,13 @@ public:
|
|||
type = "Receive";
|
||||
if (block_a.hashables.source != params.ledger.genesis_account)
|
||||
{
|
||||
account = ledger.account (transaction, block_a.hashables.source);
|
||||
amount = ledger.amount (transaction, block_a.hash ());
|
||||
bool error_or_pruned (false);
|
||||
account = ledger.account_safe (transaction, block_a.hashables.source, error_or_pruned);
|
||||
amount = ledger.amount_safe (transaction, block_a.hash (), error_or_pruned);
|
||||
if (error_or_pruned)
|
||||
{
|
||||
type = "Receive (pruned)";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -554,8 +569,15 @@ public:
|
|||
void state_block (nano::state_block const & block_a)
|
||||
{
|
||||
auto balance (block_a.hashables.balance.number ());
|
||||
auto previous_balance (ledger.balance (transaction, block_a.hashables.previous));
|
||||
if (balance < previous_balance)
|
||||
bool error_or_pruned (false);
|
||||
auto previous_balance (ledger.balance_safe (transaction, block_a.hashables.previous, error_or_pruned));
|
||||
if (error_or_pruned)
|
||||
{
|
||||
type = "Unknown (pruned)";
|
||||
amount = 0;
|
||||
account = block_a.hashables.account;
|
||||
}
|
||||
else if (balance < previous_balance)
|
||||
{
|
||||
type = "Send";
|
||||
amount = previous_balance - balance;
|
||||
|
@ -576,7 +598,11 @@ public:
|
|||
else
|
||||
{
|
||||
type = "Receive";
|
||||
account = ledger.account (transaction, block_a.hashables.link.as_block_hash ());
|
||||
account = ledger.account_safe (transaction, block_a.hashables.link.as_block_hash (), error_or_pruned);
|
||||
if (error_or_pruned)
|
||||
{
|
||||
type = "Receive (pruned)";
|
||||
}
|
||||
}
|
||||
amount = balance - previous_balance;
|
||||
}
|
||||
|
@ -599,16 +625,18 @@ void nano_qt::history::refresh ()
|
|||
{
|
||||
QList<QStandardItem *> items;
|
||||
auto block (ledger.store.block_get (transaction, hash));
|
||||
debug_assert (block != nullptr);
|
||||
block->visit (visitor);
|
||||
items.push_back (new QStandardItem (QString (visitor.type.c_str ())));
|
||||
items.push_back (new QStandardItem (QString (visitor.account.to_account ().c_str ())));
|
||||
auto balanceItem = new QStandardItem (QString (wallet.format_balance (visitor.amount).c_str ()));
|
||||
balanceItem->setData (Qt::AlignRight, Qt::TextAlignmentRole);
|
||||
items.push_back (balanceItem);
|
||||
items.push_back (new QStandardItem (QString (hash.to_string ().c_str ())));
|
||||
hash = block->previous ();
|
||||
model->appendRow (items);
|
||||
if (block != nullptr)
|
||||
{
|
||||
block->visit (visitor);
|
||||
items.push_back (new QStandardItem (QString (visitor.type.c_str ())));
|
||||
items.push_back (new QStandardItem (QString (visitor.account.to_account ().c_str ())));
|
||||
auto balanceItem = new QStandardItem (QString (wallet.format_balance (visitor.amount).c_str ()));
|
||||
balanceItem->setData (Qt::AlignRight, Qt::TextAlignmentRole);
|
||||
items.push_back (balanceItem);
|
||||
items.push_back (new QStandardItem (QString (hash.to_string ().c_str ())));
|
||||
hash = block->previous ();
|
||||
model->appendRow (items);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -501,6 +501,78 @@ TEST (history, short_text)
|
|||
ASSERT_EQ (4, history.model->rowCount ());
|
||||
}
|
||||
|
||||
TEST (history, pruned_source)
|
||||
{
|
||||
if (nano::using_rocksdb_in_tests ())
|
||||
{
|
||||
// Don't test this in rocksdb mode
|
||||
return;
|
||||
}
|
||||
nano_qt::eventloop_processor processor;
|
||||
nano::keypair key;
|
||||
nano::system system (1);
|
||||
system.wallet (0)->insert_adhoc (key.prv);
|
||||
nano::account account;
|
||||
{
|
||||
auto transaction (system.nodes[0]->wallets.tx_begin_read ());
|
||||
account = system.account (transaction, 0);
|
||||
}
|
||||
auto wallet (std::make_shared<nano_qt::wallet> (*test_application, processor, *system.nodes[0], system.wallet (0), account));
|
||||
auto store = nano::make_store (system.nodes[0]->logger, nano::unique_path ());
|
||||
ASSERT_TRUE (!store->init_error ());
|
||||
nano::genesis genesis;
|
||||
nano::ledger ledger (*store, system.nodes[0]->stats);
|
||||
ledger.pruning = true;
|
||||
nano::block_hash next_pruning;
|
||||
// Basic pruning for legacy blocks. Previous block is pruned, source is pruned
|
||||
{
|
||||
auto transaction (store->tx_begin_write ());
|
||||
store->initialize (transaction, genesis, ledger.cache);
|
||||
auto latest (ledger.latest (transaction, nano::dev_genesis_key.pub));
|
||||
nano::send_block send1 (latest, nano::dev_genesis_key.pub, nano::genesis_amount - 100, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (latest));
|
||||
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send1).code);
|
||||
nano::send_block send2 (send1.hash (), key.pub, nano::genesis_amount - 200, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (send1.hash ()));
|
||||
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send2).code);
|
||||
nano::receive_block receive (send2.hash (), send1.hash (), nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (send2.hash ()));
|
||||
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive).code);
|
||||
nano::open_block open (send2.hash (), key.pub, key.pub, key.prv, key.pub, *system.work.generate (key.pub));
|
||||
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, open).code);
|
||||
ASSERT_EQ (1, ledger.pruning_action (transaction, send1.hash (), 2));
|
||||
next_pruning = send2.hash ();
|
||||
}
|
||||
nano_qt::history history1 (ledger, nano::dev_genesis_key.pub, *wallet);
|
||||
history1.refresh ();
|
||||
ASSERT_EQ (2, history1.model->rowCount ());
|
||||
nano_qt::history history2 (ledger, key.pub, *wallet);
|
||||
history2.refresh ();
|
||||
ASSERT_EQ (1, history2.model->rowCount ());
|
||||
// Additional legacy test
|
||||
{
|
||||
auto transaction (store->tx_begin_write ());
|
||||
ASSERT_EQ (1, ledger.pruning_action (transaction, next_pruning, 2));
|
||||
}
|
||||
history1.refresh ();
|
||||
ASSERT_EQ (1, history1.model->rowCount ());
|
||||
history2.refresh ();
|
||||
ASSERT_EQ (1, history2.model->rowCount ());
|
||||
// Pruning for state blocks. Previous block is pruned, source is pruned
|
||||
{
|
||||
auto transaction (store->tx_begin_write ());
|
||||
auto latest (ledger.latest (transaction, nano::dev_genesis_key.pub));
|
||||
nano::state_block send (nano::dev_genesis_key.pub, latest, nano::dev_genesis_key.pub, nano::genesis_amount - 200, key.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (latest));
|
||||
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send).code);
|
||||
auto latest_key (ledger.latest (transaction, key.pub));
|
||||
nano::state_block receive (key.pub, latest_key, key.pub, 200, send.hash (), key.prv, key.pub, *system.work.generate (latest_key));
|
||||
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive).code);
|
||||
ASSERT_EQ (1, ledger.pruning_action (transaction, latest, 2));
|
||||
ASSERT_EQ (1, ledger.pruning_action (transaction, latest_key, 2));
|
||||
}
|
||||
history1.refresh ();
|
||||
ASSERT_EQ (1, history1.model->rowCount ());
|
||||
history2.refresh ();
|
||||
ASSERT_EQ (1, history2.model->rowCount ());
|
||||
}
|
||||
|
||||
TEST (wallet, startup_work)
|
||||
{
|
||||
nano_qt::eventloop_processor processor;
|
||||
|
|
|
@ -1562,6 +1562,155 @@ TEST (rpc, history_count)
|
|||
ASSERT_EQ (1, history_node.size ());
|
||||
}
|
||||
|
||||
TEST (rpc, history_pruning)
|
||||
{
|
||||
nano::system system;
|
||||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.enable_voting = false; // Remove after allowing pruned voting
|
||||
nano::node_flags node_flags;
|
||||
node_flags.enable_pruning = true;
|
||||
auto node0 = add_ipc_enabled_node (system, node_config, node_flags);
|
||||
nano::genesis genesis;
|
||||
auto change (std::make_shared<nano::change_block> (genesis.hash (), nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *node0->work.generate (genesis.hash ())));
|
||||
node0->process_active (change);
|
||||
auto send (std::make_shared<nano::send_block> (change->hash (), nano::dev_genesis_key.pub, nano::genesis_amount - node0->config.receive_minimum.number (), nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *node0->work.generate (change->hash ())));
|
||||
node0->process_active (send);
|
||||
auto receive (std::make_shared<nano::receive_block> (send->hash (), send->hash (), nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *node0->work.generate (send->hash ())));
|
||||
node0->process_active (receive);
|
||||
auto usend (std::make_shared<nano::state_block> (nano::genesis_account, receive->hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, nano::genesis_account, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *node0->work_generate_blocking (receive->hash ())));
|
||||
auto ureceive (std::make_shared<nano::state_block> (nano::genesis_account, usend->hash (), nano::genesis_account, nano::genesis_amount, usend->hash (), nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *node0->work_generate_blocking (usend->hash ())));
|
||||
auto uchange (std::make_shared<nano::state_block> (nano::genesis_account, ureceive->hash (), nano::keypair ().pub, nano::genesis_amount, 0, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *node0->work_generate_blocking (ureceive->hash ())));
|
||||
node0->process_active (usend);
|
||||
node0->process_active (ureceive);
|
||||
node0->process_active (uchange);
|
||||
node0->block_processor.flush ();
|
||||
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
|
||||
// Confirm last block to prune previous
|
||||
{
|
||||
auto election = node0->active.election (change->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
}
|
||||
ASSERT_TIMELY (2s, node0->block_confirmed (change->hash ()) && node0->active.active (send->qualified_root ()));
|
||||
{
|
||||
auto election = node0->active.election (send->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
}
|
||||
ASSERT_TIMELY (2s, node0->block_confirmed (send->hash ()) && node0->active.active (receive->qualified_root ()));
|
||||
{
|
||||
auto election = node0->active.election (receive->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
}
|
||||
ASSERT_TIMELY (2s, node0->block_confirmed (receive->hash ()) && node0->active.active (usend->qualified_root ()));
|
||||
{
|
||||
auto election = node0->active.election (usend->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
}
|
||||
ASSERT_TIMELY (2s, node0->block_confirmed (usend->hash ()) && node0->active.active (ureceive->qualified_root ()));
|
||||
{
|
||||
auto election = node0->active.election (ureceive->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
}
|
||||
ASSERT_TIMELY (2s, node0->block_confirmed (ureceive->hash ()) && node0->active.active (uchange->qualified_root ()));
|
||||
{
|
||||
auto election = node0->active.election (uchange->qualified_root ());
|
||||
ASSERT_NE (nullptr, election);
|
||||
election->force_confirm ();
|
||||
}
|
||||
ASSERT_TIMELY (2s, node0->active.empty () && node0->block_confirmed (uchange->hash ()));
|
||||
ASSERT_TIMELY (2s, node0->ledger.cache.cemented_count == 7 && node0->confirmation_height_processor.current ().is_zero () && node0->confirmation_height_processor.awaiting_processing_size () == 0);
|
||||
// Pruning action
|
||||
{
|
||||
auto transaction (node0->store.tx_begin_write ());
|
||||
ASSERT_EQ (1, node0->ledger.pruning_action (transaction, change->hash (), 1));
|
||||
}
|
||||
nano::node_rpc_config node_rpc_config;
|
||||
nano::ipc::ipc_server ipc_server (*node0, node_rpc_config);
|
||||
nano::rpc_config rpc_config (nano::get_available_port (), true);
|
||||
rpc_config.rpc_process.ipc_port = node0->config.ipc_config.transport_tcp.port;
|
||||
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 ();
|
||||
boost::property_tree::ptree request;
|
||||
request.put ("action", "history");
|
||||
request.put ("hash", send->hash ().to_string ());
|
||||
request.put ("count", 100);
|
||||
test_response response (request, rpc.config.port, system.io_ctx);
|
||||
ASSERT_TIMELY (5s, response.status != 0);
|
||||
ASSERT_EQ (200, response.status);
|
||||
std::vector<std::tuple<std::string, std::string, std::string, std::string>> history_l;
|
||||
auto & history_node (response.json.get_child ("history"));
|
||||
for (auto i (history_node.begin ()), n (history_node.end ()); i != n; ++i)
|
||||
{
|
||||
history_l.push_back (std::make_tuple (i->second.get<std::string> ("type"), i->second.get<std::string> ("account", "-1"), i->second.get<std::string> ("amount", "-1"), i->second.get<std::string> ("hash")));
|
||||
boost::optional<std::string> amount (i->second.get_optional<std::string> ("amount"));
|
||||
ASSERT_FALSE (amount.is_initialized ()); // Cannot calculate amount
|
||||
}
|
||||
ASSERT_EQ (1, history_l.size ());
|
||||
ASSERT_EQ ("send", std::get<0> (history_l[0]));
|
||||
ASSERT_EQ (nano::dev_genesis_key.pub.to_account (), std::get<1> (history_l[0]));
|
||||
ASSERT_EQ ("-1", std::get<2> (history_l[0]));
|
||||
ASSERT_EQ (send->hash ().to_string (), std::get<3> (history_l[0]));
|
||||
// Pruning action
|
||||
{
|
||||
auto transaction (node0->store.tx_begin_write ());
|
||||
ASSERT_EQ (1, node0->ledger.pruning_action (transaction, send->hash (), 1));
|
||||
}
|
||||
boost::property_tree::ptree request2;
|
||||
request2.put ("action", "history");
|
||||
request2.put ("hash", receive->hash ().to_string ());
|
||||
request2.put ("count", 100);
|
||||
test_response response2 (request2, rpc.config.port, system.io_ctx);
|
||||
ASSERT_TIMELY (5s, response2.status != 0);
|
||||
ASSERT_EQ (200, response2.status);
|
||||
history_l.clear ();
|
||||
auto & history_node2 (response2.json.get_child ("history"));
|
||||
for (auto i (history_node2.begin ()), n (history_node2.end ()); i != n; ++i)
|
||||
{
|
||||
history_l.push_back (std::make_tuple (i->second.get<std::string> ("type"), i->second.get<std::string> ("account", "-1"), i->second.get<std::string> ("amount", "-1"), i->second.get<std::string> ("hash")));
|
||||
boost::optional<std::string> amount (i->second.get_optional<std::string> ("amount"));
|
||||
ASSERT_FALSE (amount.is_initialized ()); // Cannot calculate amount
|
||||
boost::optional<std::string> account (i->second.get_optional<std::string> ("account"));
|
||||
ASSERT_FALSE (account.is_initialized ()); // Cannot find source account
|
||||
}
|
||||
ASSERT_EQ (1, history_l.size ());
|
||||
ASSERT_EQ ("receive", std::get<0> (history_l[0]));
|
||||
ASSERT_EQ ("-1", std::get<1> (history_l[0]));
|
||||
ASSERT_EQ ("-1", std::get<2> (history_l[0]));
|
||||
ASSERT_EQ (receive->hash ().to_string (), std::get<3> (history_l[0]));
|
||||
// Pruning action
|
||||
{
|
||||
auto transaction (node0->store.tx_begin_write ());
|
||||
ASSERT_EQ (1, node0->ledger.pruning_action (transaction, receive->hash (), 1));
|
||||
}
|
||||
boost::property_tree::ptree request3;
|
||||
request3.put ("action", "history");
|
||||
request3.put ("hash", uchange->hash ().to_string ());
|
||||
request3.put ("count", 100);
|
||||
test_response response3 (request3, rpc.config.port, system.io_ctx);
|
||||
ASSERT_TIMELY (5s, response3.status != 0);
|
||||
ASSERT_EQ (200, response3.status);
|
||||
history_l.clear ();
|
||||
auto & history_node3 (response3.json.get_child ("history"));
|
||||
for (auto i (history_node3.begin ()), n (history_node3.end ()); i != n; ++i)
|
||||
{
|
||||
history_l.push_back (std::make_tuple (i->second.get<std::string> ("type"), i->second.get<std::string> ("account", "-1"), i->second.get<std::string> ("amount", "-1"), i->second.get<std::string> ("hash")));
|
||||
}
|
||||
ASSERT_EQ (2, history_l.size ());
|
||||
ASSERT_EQ ("receive", std::get<0> (history_l[0]));
|
||||
ASSERT_EQ (ureceive->hash ().to_string (), std::get<3> (history_l[0]));
|
||||
ASSERT_EQ (nano::dev_genesis_key.pub.to_account (), std::get<1> (history_l[0]));
|
||||
ASSERT_EQ (nano::Gxrb_ratio.convert_to<std::string> (), std::get<2> (history_l[0]));
|
||||
ASSERT_EQ ("unknown", std::get<0> (history_l[1]));
|
||||
ASSERT_EQ ("-1", std::get<1> (history_l[1]));
|
||||
ASSERT_EQ ("-1", std::get<2> (history_l[1]));
|
||||
ASSERT_EQ (usend->hash ().to_string (), std::get<3> (history_l[1]));
|
||||
}
|
||||
|
||||
TEST (rpc, process_block)
|
||||
{
|
||||
nano::system system;
|
||||
|
@ -3180,6 +3329,50 @@ TEST (rpc, block_count)
|
|||
}
|
||||
}
|
||||
|
||||
TEST (rpc, block_count_pruning)
|
||||
{
|
||||
nano::system system;
|
||||
auto & node0 = *system.add_node ();
|
||||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.enable_voting = false; // Remove after allowing pruned voting
|
||||
nano::node_flags node_flags;
|
||||
node_flags.enable_pruning = true;
|
||||
auto & node1 = *add_ipc_enabled_node (system, node_config, node_flags);
|
||||
auto latest (node1.latest (nano::dev_genesis_key.pub));
|
||||
auto send1 (std::make_shared<nano::send_block> (latest, nano::dev_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *node1.work_generate_blocking (latest)));
|
||||
node1.process_active (send1);
|
||||
auto receive1 (std::make_shared<nano::receive_block> (send1->hash (), send1->hash (), nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *node1.work_generate_blocking (send1->hash ())));
|
||||
node1.process_active (receive1);
|
||||
node1.block_processor.flush ();
|
||||
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
|
||||
ASSERT_TIMELY (5s, node1.ledger.cache.cemented_count == 3 && node1.confirmation_height_processor.current ().is_zero () && node1.confirmation_height_processor.awaiting_processing_size () == 0);
|
||||
// Pruning action
|
||||
{
|
||||
auto transaction (node1.store.tx_begin_write ());
|
||||
ASSERT_EQ (1, node1.ledger.pruning_action (transaction, send1->hash (), 1));
|
||||
}
|
||||
scoped_io_thread_name_change scoped_thread_name_io;
|
||||
nano::node_rpc_config node_rpc_config;
|
||||
nano::ipc::ipc_server ipc_server (node1, node_rpc_config);
|
||||
nano::rpc_config rpc_config (nano::get_available_port (), true);
|
||||
rpc_config.rpc_process.ipc_port = node1.config.ipc_config.transport_tcp.port;
|
||||
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 ();
|
||||
boost::property_tree::ptree request1;
|
||||
request1.put ("action", "block_count");
|
||||
{
|
||||
test_response response1 (request1, rpc.config.port, system.io_ctx);
|
||||
ASSERT_TIMELY (10s, response1.status != 0);
|
||||
ASSERT_EQ (200, response1.status);
|
||||
ASSERT_EQ ("3", response1.json.get<std::string> ("count"));
|
||||
ASSERT_EQ ("0", response1.json.get<std::string> ("unchecked"));
|
||||
ASSERT_EQ ("3", response1.json.get<std::string> ("cemented"));
|
||||
ASSERT_EQ ("2", response1.json.get<std::string> ("full"));
|
||||
ASSERT_EQ ("1", response1.json.get<std::string> ("pruned"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST (rpc, frontier_count)
|
||||
{
|
||||
nano::system system;
|
||||
|
@ -5059,6 +5252,65 @@ TEST (rpc, blocks_info_subtype)
|
|||
ASSERT_EQ (change_subtype, "change");
|
||||
}
|
||||
|
||||
TEST (rpc, block_info_pruning)
|
||||
{
|
||||
nano::system system;
|
||||
auto & node0 = *system.add_node ();
|
||||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.enable_voting = false; // Remove after allowing pruned voting
|
||||
nano::node_flags node_flags;
|
||||
node_flags.enable_pruning = true;
|
||||
auto & node1 = *add_ipc_enabled_node (system, node_config, node_flags);
|
||||
auto latest (node1.latest (nano::dev_genesis_key.pub));
|
||||
auto send1 (std::make_shared<nano::send_block> (latest, nano::dev_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *node1.work_generate_blocking (latest)));
|
||||
node1.process_active (send1);
|
||||
auto receive1 (std::make_shared<nano::receive_block> (send1->hash (), send1->hash (), nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *node1.work_generate_blocking (send1->hash ())));
|
||||
node1.process_active (receive1);
|
||||
node1.block_processor.flush ();
|
||||
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
|
||||
ASSERT_TIMELY (5s, node1.ledger.cache.cemented_count == 3 && node1.confirmation_height_processor.current ().is_zero () && node1.confirmation_height_processor.awaiting_processing_size () == 0);
|
||||
// Pruning action
|
||||
{
|
||||
auto transaction (node1.store.tx_begin_write ());
|
||||
ASSERT_EQ (1, node1.ledger.pruning_action (transaction, send1->hash (), 1));
|
||||
}
|
||||
scoped_io_thread_name_change scoped_thread_name_io;
|
||||
nano::node_rpc_config node_rpc_config;
|
||||
nano::ipc::ipc_server ipc_server (node1, node_rpc_config);
|
||||
nano::rpc_config rpc_config (nano::get_available_port (), true);
|
||||
rpc_config.rpc_process.ipc_port = node1.config.ipc_config.transport_tcp.port;
|
||||
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 ();
|
||||
// Pruned block
|
||||
boost::property_tree::ptree request;
|
||||
request.put ("action", "block_info");
|
||||
request.put ("hash", send1->hash ().to_string ());
|
||||
test_response response (request, rpc.config.port, system.io_ctx);
|
||||
ASSERT_TIMELY (5s, response.status != 0);
|
||||
ASSERT_EQ (200, response.status);
|
||||
ASSERT_EQ (std::error_code (nano::error_blocks::not_found).message (), response.json.get<std::string> ("error"));
|
||||
// Existing block with previous pruned
|
||||
boost::property_tree::ptree request2;
|
||||
request2.put ("action", "block_info");
|
||||
request2.put ("json_block", "true");
|
||||
request2.put ("hash", receive1->hash ().to_string ());
|
||||
test_response response2 (request2, rpc.config.port, system.io_ctx);
|
||||
ASSERT_TIMELY (5s, response2.status != 0);
|
||||
ASSERT_EQ (200, response2.status);
|
||||
std::string account_text (response2.json.get<std::string> ("block_account"));
|
||||
ASSERT_EQ (nano::dev_genesis_key.pub.to_account (), account_text);
|
||||
boost::optional<std::string> amount (response2.json.get_optional<std::string> ("amount"));
|
||||
ASSERT_FALSE (amount.is_initialized ()); // Cannot calculate amount
|
||||
bool json_error{ false };
|
||||
nano::receive_block receive_from_json (json_error, response2.json.get_child ("contents"));
|
||||
ASSERT_FALSE (json_error);
|
||||
ASSERT_EQ (receive1->full_hash (), receive_from_json.full_hash ());
|
||||
std::string balance_text (response2.json.get<std::string> ("balance"));
|
||||
ASSERT_EQ (nano::genesis_amount.convert_to<std::string> (), balance_text);
|
||||
ASSERT_TRUE (response2.json.get<bool> ("confirmed"));
|
||||
}
|
||||
|
||||
TEST (rpc, work_peers_all)
|
||||
{
|
||||
nano::system system;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue