Skip to content

Commit

Permalink
Fix unit test rpc history pruning (#4089)
Browse files Browse the repository at this point in the history
* standardise assert timelys to be 5 seconds

* Bugfix: Stop depending on block processor flush and use nano::test::confirm()

* Simplify the rest of the test case

* Add fixme comment to nano::test::confirm()
  • Loading branch information
dsiganos authored Jan 30, 2023
1 parent 7e9f6e8 commit 471a0a3
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 95 deletions.
168 changes: 74 additions & 94 deletions nano/rpc_test/rpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1358,15 +1358,21 @@ TEST (rpc, history_pruning)
nano::node_flags node_flags;
node_flags.enable_pruning = true;
auto node0 = add_ipc_enabled_node (system, node_config, node_flags);
std::vector<std::shared_ptr<nano::block>> blocks;

nano::block_builder builder;

// noop change block
auto change = builder
.change ()
.previous (nano::dev::genesis->hash ())
.representative (nano::dev::genesis_key.pub)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*node0->work.generate (nano::dev::genesis->hash ()))
.build_shared ();
node0->process_active (change);
blocks.push_back (change);

// legacy send to itself
auto send = builder
.send ()
.previous (change->hash ())
Expand All @@ -1375,15 +1381,19 @@ TEST (rpc, history_pruning)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*node0->work.generate (change->hash ()))
.build_shared ();
node0->process_active (send);
blocks.push_back (send);

// legacy receive the legacy self send
auto receive = builder
.receive ()
.previous (send->hash ())
.source (send->hash ())
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*node0->work.generate (send->hash ()))
.build_shared ();
node0->process_active (receive);
blocks.push_back (receive);

// non legacy self send
auto usend = builder
.state ()
.account (nano::dev::genesis->account ())
Expand All @@ -1394,6 +1404,9 @@ TEST (rpc, history_pruning)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*node0->work_generate_blocking (receive->hash ()))
.build_shared ();
blocks.push_back (usend);

// non legacy receive of the non legacy self send
auto ureceive = builder
.state ()
.account (nano::dev::genesis->account ())
Expand All @@ -1404,6 +1417,9 @@ TEST (rpc, history_pruning)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*node0->work_generate_blocking (usend->hash ()))
.build_shared ();
blocks.push_back (ureceive);

// change genesis to a random rep
auto uchange = builder
.state ()
.account (nano::dev::genesis->account ())
Expand All @@ -1414,127 +1430,91 @@ TEST (rpc, history_pruning)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*node0->work_generate_blocking (ureceive->hash ()))
.build_shared ();
node0->process_active (usend);
node0->process_active (ureceive);
node0->process_active (uchange);
node0->block_processor.flush ();
blocks.push_back (uchange);

nano::test::process_live (*node0, blocks);
ASSERT_TIMELY (5s, nano::test::exists (*node0, blocks));
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

// WORKAROUND: this is called repeatedly inside an assert timely because nano::test::confirm()
// uses block_processor.flush internally which can fail to flush
ASSERT_TIMELY (5s, nano::test::confirm (*node0, blocks));

ASSERT_TIMELY (5s, node0->block_confirmed (uchange->hash ()));
nano::confirmation_height_info confirmation_height_info;
node0->store.confirmation_height.get (node0->store.tx_begin_read (), nano::dev::genesis_key.pub, confirmation_height_info);
ASSERT_EQ (7, confirmation_height_info.height);

// Prune block "change"
{
auto transaction (node0->store.tx_begin_write ());
ASSERT_EQ (1, node0->ledger.pruning_action (transaction, change->hash (), 1));
}

auto const rpc_ctx = add_rpc (system, node0);
boost::property_tree::ptree request;
request.put ("action", "history");
request.put ("hash", send->hash ().to_string ());
request.put ("count", 100);
auto response (wait_response (system, rpc_ctx, request));
std::vector<std::tuple<std::string, std::string, std::string, std::string>> history_l;
auto & history_node (response.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 response = wait_response (system, rpc_ctx, request);
auto history_node = response.get_child ("history");
ASSERT_EQ (history_node.size (), 1);
auto entry = (*history_node.begin ()).second;
ASSERT_EQ ("send", entry.get<std::string> ("type"));
ASSERT_EQ (nano::dev::genesis_key.pub.to_account (), entry.get<std::string> ("account", "N/A"));
ASSERT_EQ ("N/A", entry.get<std::string> ("amount", "N/A"));
ASSERT_EQ (send->hash ().to_string (), entry.get<std::string> ("hash"));

// Prune block "send"
{
rpc_ctx.io_scope->reset ();
auto transaction (node0->store.tx_begin_write ());
ASSERT_EQ (1, node0->ledger.pruning_action (transaction, send->hash (), 1));
rpc_ctx.io_scope->renew ();
}

boost::property_tree::ptree request2;
request2.put ("action", "history");
request2.put ("hash", receive->hash ().to_string ());
request2.put ("count", 100);
auto response2 (wait_response (system, rpc_ctx, request2));
history_l.clear ();
auto & history_node2 (response2.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
response = wait_response (system, rpc_ctx, request2);
history_node = response.get_child ("history");
ASSERT_EQ (history_node.size (), 1);
entry = (*history_node.begin ()).second;
ASSERT_EQ ("receive", entry.get<std::string> ("type"));
ASSERT_EQ ("N/A", entry.get<std::string> ("account", "N/A"));
ASSERT_EQ ("N/A", entry.get<std::string> ("amount", "N/A"));
ASSERT_EQ (receive->hash ().to_string (), entry.get<std::string> ("hash"));

// Prune block "receive"
{
rpc_ctx.io_scope->reset ();
auto transaction (node0->store.tx_begin_write ());
ASSERT_EQ (1, node0->ledger.pruning_action (transaction, receive->hash (), 1));
rpc_ctx.io_scope->renew ();
}

boost::property_tree::ptree request3;
request3.put ("action", "history");
request3.put ("hash", uchange->hash ().to_string ());
request3.put ("count", 100);
auto response3 (wait_response (system, rpc_ctx, request3));
history_l.clear ();
auto & history_node3 (response3.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]));
response = wait_response (system, rpc_ctx, request3);
history_node = response.get_child ("history");
ASSERT_EQ (history_node.size (), 2);

// first array element
entry = (*history_node.begin ()).second;
ASSERT_EQ ("receive", entry.get<std::string> ("type"));
ASSERT_EQ (ureceive->hash ().to_string (), entry.get<std::string> ("hash"));
ASSERT_EQ (nano::dev::genesis_key.pub.to_account (), entry.get<std::string> ("account", "N/A"));
ASSERT_EQ (nano::Gxrb_ratio.convert_to<std::string> (), entry.get<std::string> ("amount", "N/A"));

// second array element
entry = (*(++history_node.begin ())).second;
ASSERT_EQ ("unknown", entry.get<std::string> ("type"));
ASSERT_EQ ("N/A", entry.get<std::string> ("account", "N/A"));
ASSERT_EQ ("N/A", entry.get<std::string> ("amount", "N/A"));
ASSERT_EQ (usend->hash ().to_string (), entry.get<std::string> ("hash"));
}

TEST (rpc, process_block)
Expand Down
2 changes: 1 addition & 1 deletion nano/test_common/testutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ bool nano::test::process_live (nano::node & node, std::vector<std::shared_ptr<na

bool nano::test::confirm (nano::node & node, std::vector<nano::block_hash> hashes)
{
// Finish processing all blocks
// Finish processing all blocks - FIXME: block processor flush is broken and should be removed
node.block_processor.flush ();
for (auto & hash : hashes)
{
Expand Down

0 comments on commit 471a0a3

Please sign in to comment.