Skip to content

Commit

Permalink
Fix conflicts.add_two unit test (#4361)
Browse files Browse the repository at this point in the history
* Add debugging convenience function nano::test::print_all_account_info

to print the basic info of all accounts in the ledger.
It is intended to be used from unit tests.

* Introduce nano::test::setup_new_account()

To make it easier to write unit tests

* Fix unit test conflicts.add_two
  • Loading branch information
dsiganos authored Jan 17, 2024
1 parent 978020e commit 4889d3c
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 92 deletions.
110 changes: 31 additions & 79 deletions nano/core_test/conflicts.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@

#include <nano/node/election.hpp>
#include <nano/node/scheduler/component.hpp>
#include <nano/node/scheduler/priority.hpp>
#include <nano/test_common/chains.hpp>
#include <nano/test_common/system.hpp>
#include <nano/test_common/testutil.hpp>

Expand Down Expand Up @@ -89,91 +91,41 @@ TEST (conflicts, add_two)
{
nano::test::system system{};
auto const & node = system.add_node ();
nano::keypair key1, key2, key3;
auto gk = nano::dev::genesis_key;

system.wallet (0)->insert_adhoc (nano::dev::genesis_key.prv);

// define a functor that sends from given account to given destination,
// optionally force-confirming the send blocks *and* receiving on the destination account;
// the functor returns a pair of the send and receive blocks created or nullptrs if something failed
//
auto const do_send = [&node, &system] (auto const & previous, auto const & from, auto const & to, bool forceConfirm = true)
-> std::pair<std::optional<std::shared_ptr<nano::block>>, std::optional<std::shared_ptr<nano::block>>> {
auto const send = nano::send_block_builder{}.make_block ().previous (previous).destination (to.pub).balance (0).sign (from.prv, from.pub).work (*system.work.generate (previous)).build_shared ();

if (nano::process_result::progress != node->process (*send).code)
{
return std::make_pair (std::nullopt, std::nullopt);
}

if (!forceConfirm)
{
return std::make_pair (std::move (send), std::nullopt);
}

auto const is_confirmed = [&node] (auto const & hash) {
return node->block_confirmed (hash);
};

node->process_confirmed (nano::election_status{ send });
auto const is_send_not_confirmed = system.poll_until_true (5s, std::bind (is_confirmed, send->hash ()));
if (is_send_not_confirmed)
{
return std::make_pair (std::nullopt, std::nullopt);
}

auto const receive = nano::open_block_builder{}.make_block ().account (to.pub).source (send->hash ()).representative (to.pub).sign (to.prv, to.pub).work (*system.work.generate (to.pub)).build_shared ();

if (nano::process_result::progress != node->process (*receive).code)
{
return std::make_pair (std::nullopt, std::nullopt);
}

node->process_confirmed (nano::election_status{ receive });
auto const is_receive_not_confirmed = system.poll_until_true (5s, std::bind (is_confirmed, receive->hash ()));
if (is_receive_not_confirmed)
{
return std::make_pair (std::move (send), std::nullopt);
}

return std::make_pair (std::move (send), std::move (receive));
};

// send from genesis to account1 and receive it on account1
//
nano::keypair account1{};
auto const [send1, receive1] = do_send (nano::dev::genesis->hash (), nano::dev::genesis_key, account1);
ASSERT_TRUE (send1.has_value () && receive1.has_value ());
// both blocks having been fully confirmed, we expect 1 (genesis) + 2 (send/receive) = 3 cemented blocks
//
ASSERT_EQ (3, node->ledger.cache.cemented_count);

nano::keypair account2{};
auto const [send2, receive2] = do_send ((*send1)->hash (), nano::dev::genesis_key, account2);
ASSERT_TRUE (send2.has_value () && receive2.has_value ());
// create 2 new accounts, that receive 1 raw each, all blocks are force confirmed
auto [send1, open1] = nano::test::setup_new_account (system, *node, 1, gk, key1, gk.pub, true);
auto [send2, open2] = nano::test::setup_new_account (system, *node, 1, gk, key2, gk.pub, true);
ASSERT_EQ (5, node->ledger.cache.cemented_count);

// send from account1 to account3 but do not receive it on account3 and do not force-confirm the send block
//
nano::keypair account3{};
auto const [send3, dummy1] = do_send ((*receive1)->hash (), account1, account3, false);
ASSERT_TRUE (send3.has_value ());
// expect the number of cemented blocks not to have changed since the last operation
//
ASSERT_EQ (5, node->ledger.cache.cemented_count);
// send 1 raw to account key3 from key1
auto send_a = nano::state_block_builder ()
.account (key1.pub)
.previous (open1->hash ())
.representative (nano::dev::genesis_key.pub)
.balance (0)
.link (key3.pub)
.sign (key1.prv, key1.pub)
.work (*system.work.generate (open1->hash ()))
.build_shared ();

auto const [send4, dummy2] = do_send ((*receive2)->hash (), account2, account3, false);
ASSERT_TRUE (send4.has_value ());
ASSERT_EQ (5, node->ledger.cache.cemented_count);
// send 1 raw to account key3 from key2
auto send_b = nano::state_block_builder ()
.account (key2.pub)
.previous (open2->hash ())
.representative (nano::dev::genesis_key.pub)
.balance (0)
.link (key3.pub)
.sign (key2.prv, key2.pub)
.work (*system.work.generate (open2->hash ()))
.build_shared ();

// activate elections for the previous two send blocks (to account3) that we did not forcefully confirm
//
node->scheduler.priority.activate (account3.pub, node->store.tx_begin_read ());
ASSERT_TIMELY (5s, node->active.election ((*send3)->qualified_root ()) != nullptr);
ASSERT_TIMELY (5s, node->active.election ((*send4)->qualified_root ()) != nullptr);

// wait 3s before asserting just to make sure there would be enough time
// for the Active Elections Container to evict both elections in case they would wrongfully get confirmed
//
ASSERT_TRUE (nano::test::process (*node, { send_a, send_b }));
ASSERT_TRUE (nano::test::start_elections (system, *node, { send_a, send_b }));
ASSERT_TRUE (node->active.election (send_a->qualified_root ()));
ASSERT_TRUE (node->active.election (send_b->qualified_root ()));
ASSERT_TIMELY_EQ (5s, node->active.size (), 2);
}

Expand Down
29 changes: 16 additions & 13 deletions nano/test_common/chains.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,39 +148,42 @@ nano::block_list_t nano::test::setup_independent_blocks (nano::test::system & sy
return blocks;
}

nano::keypair nano::test::setup_rep (nano::test::system & system, nano::node & node, nano::uint128_t const amount, nano::keypair source)
std::pair<std::shared_ptr<nano::block>, std::shared_ptr<nano::block>> nano::test::setup_new_account (nano::test::system & system, nano::node & node, nano::uint128_t const amount, nano::keypair source, nano::keypair dest, nano::account dest_rep, bool force_confirm)
{
auto latest = node.latest (source.pub);
auto balance = node.balance (source.pub);

nano::keypair key;
nano::block_builder builder;

auto send = builder
auto send = nano::block_builder ()
.state ()
.account (source.pub)
.previous (latest)
.representative (source.pub)
.balance (balance - amount)
.link (key.pub)
.link (dest.pub)
.sign (source.prv, source.pub)
.work (*system.work.generate (latest))
.build_shared ();

auto open = builder
auto open = nano::block_builder ()
.state ()
.account (key.pub)
.account (dest.pub)
.previous (0)
.representative (key.pub)
.representative (dest_rep)
.balance (amount)
.link (send->hash ())
.sign (key.prv, key.pub)
.work (*system.work.generate (key.pub))
.sign (dest.prv, dest.pub)
.work (*system.work.generate (dest.pub))
.build_shared ();

EXPECT_TRUE (nano::test::process (node, { send, open }));
EXPECT_TRUE (nano::test::start_elections (system, node, { send, open }, true));
EXPECT_TRUE (nano::test::start_elections (system, node, { send, open }, force_confirm));
EXPECT_TIMELY (5s, nano::test::confirmed (node, { send, open }));
return std::make_pair (send, open);
}

return key;
nano::keypair nano::test::setup_rep (nano::test::system & system, nano::node & node, nano::uint128_t const amount, nano::keypair source)
{
nano::keypair destkey;
nano::test::setup_new_account (system, node, amount, source, destkey, destkey.pub, true);
return destkey;
}
12 changes: 12 additions & 0 deletions nano/test_common/chains.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ std::vector<std::pair<nano::account, nano::block_list_t>> setup_chains (nano::te
*/
nano::block_list_t setup_independent_blocks (nano::test::system & system, nano::node & node, int count, nano::keypair source = nano::dev::genesis_key);

/**
* \brief Create a pair of send/receive blocks to implement the transfer of "amount" raw from "source" to the unopened account "dest".
* \param system
* \param node
* \param amount the amount of raw to transfer
* \param source the source account
* \param dest the destination account
* \param dest_rep the rep that the dest account should have
* \param force_confirm force confirm the blocks
*/
std::pair<std::shared_ptr<nano::block>, std::shared_ptr<nano::block>> setup_new_account (nano::test::system & system, nano::node & node, nano::uint128_t const amount, nano::keypair source, nano::keypair dest, nano::account dest_rep, bool force_confirm);

/**
* Sends `amount` raw from `source` account chain into a newly created account and sets that account as its own representative
* @return created representative
Expand Down
21 changes: 21 additions & 0 deletions nano/test_common/testutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,24 @@ bool nano::test::start_elections (nano::test::system & system_a, nano::node & no
{
return nano::test::start_elections (system_a, node_a, blocks_to_hashes (blocks_a), forced_a);
}

void nano::test::print_all_account_info (nano::node & node)
{
auto const tx = node.ledger.store.tx_begin_read ();
auto const end = node.ledger.store.account.end ();
for (auto i = node.ledger.store.account.begin (tx); i != end; ++i)
{
nano::account acc = i->first;
nano::account_info acc_info = i->second;
nano::confirmation_height_info height_info;
std::cout << "Account: " << acc.to_account () << std::endl;
std::cout << " Unconfirmed Balance: " << acc_info.balance.to_string_dec () << std::endl;
std::cout << " Confirmed Balance: " << node.ledger.account_balance (tx, acc, true) << std::endl;
std::cout << " Block Count: " << acc_info.block_count << std::endl;
if (!node.ledger.store.confirmation_height.get (tx, acc, height_info))
{
std::cout << " Conf. Height: " << height_info.height << std::endl;
std::cout << " Conf. Frontier: " << height_info.frontier.to_string () << std::endl;
}
}
}
7 changes: 7 additions & 0 deletions nano/test_common/testutil.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -416,5 +416,12 @@ namespace test
* NOTE: Each election is given 5 seconds to complete, if it does not complete in 5 seconds, it will return an error.
*/
[[nodiscard]] bool start_elections (nano::test::system &, nano::node &, std::vector<std::shared_ptr<nano::block>> const &, bool const forced_a = false);

/**
* \brief Debugging function to print all accounts in a ledger. Intented to be used to debug unit tests.
* \param ledger
*/
void print_all_account_info (nano::node & node);

}
}

0 comments on commit 4889d3c

Please sign in to comment.