Fix conflicts.add_two unit test (#4361)

* 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
This commit is contained in:
Dimitrios Siganos 2024-01-17 14:01:46 +07:00 committed by GitHub
commit 4889d3cf91
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 88 additions and 93 deletions

View file

@ -1,6 +1,8 @@
#include <nano/node/election.hpp> #include <nano/node/election.hpp>
#include <nano/node/scheduler/component.hpp> #include <nano/node/scheduler/component.hpp>
#include <nano/node/scheduler/priority.hpp> #include <nano/node/scheduler/priority.hpp>
#include <nano/test_common/chains.hpp>
#include <nano/test_common/system.hpp> #include <nano/test_common/system.hpp>
#include <nano/test_common/testutil.hpp> #include <nano/test_common/testutil.hpp>
@ -89,91 +91,41 @@ TEST (conflicts, add_two)
{ {
nano::test::system system{}; nano::test::system system{};
auto const & node = system.add_node (); 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); // 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);
// define a functor that sends from given account to given destination, auto [send2, open2] = nano::test::setup_new_account (system, *node, 1, gk, key2, gk.pub, true);
// 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 ());
ASSERT_EQ (5, node->ledger.cache.cemented_count); 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 // send 1 raw to account key3 from key1
// auto send_a = nano::state_block_builder ()
nano::keypair account3{}; .account (key1.pub)
auto const [send3, dummy1] = do_send ((*receive1)->hash (), account1, account3, false); .previous (open1->hash ())
ASSERT_TRUE (send3.has_value ()); .representative (nano::dev::genesis_key.pub)
// expect the number of cemented blocks not to have changed since the last operation .balance (0)
// .link (key3.pub)
ASSERT_EQ (5, node->ledger.cache.cemented_count); .sign (key1.prv, key1.pub)
.work (*system.work.generate (open1->hash ()))
.build_shared ();
auto const [send4, dummy2] = do_send ((*receive2)->hash (), account2, account3, false); // send 1 raw to account key3 from key2
ASSERT_TRUE (send4.has_value ()); auto send_b = nano::state_block_builder ()
ASSERT_EQ (5, node->ledger.cache.cemented_count); .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 // activate elections for the previous two send blocks (to account3) that we did not forcefully confirm
// ASSERT_TRUE (nano::test::process (*node, { send_a, send_b }));
node->scheduler.priority.activate (account3.pub, node->store.tx_begin_read ()); ASSERT_TRUE (nano::test::start_elections (system, *node, { send_a, send_b }));
ASSERT_TIMELY (5s, node->active.election ((*send3)->qualified_root ()) != nullptr); ASSERT_TRUE (node->active.election (send_a->qualified_root ()));
ASSERT_TIMELY (5s, node->active.election ((*send4)->qualified_root ()) != nullptr); ASSERT_TRUE (node->active.election (send_b->qualified_root ()));
// 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_TIMELY_EQ (5s, node->active.size (), 2); ASSERT_TIMELY_EQ (5s, node->active.size (), 2);
} }

View file

@ -148,39 +148,42 @@ nano::block_list_t nano::test::setup_independent_blocks (nano::test::system & sy
return blocks; 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 latest = node.latest (source.pub);
auto balance = node.balance (source.pub); auto balance = node.balance (source.pub);
nano::keypair key; auto send = nano::block_builder ()
nano::block_builder builder;
auto send = builder
.state () .state ()
.account (source.pub) .account (source.pub)
.previous (latest) .previous (latest)
.representative (source.pub) .representative (source.pub)
.balance (balance - amount) .balance (balance - amount)
.link (key.pub) .link (dest.pub)
.sign (source.prv, source.pub) .sign (source.prv, source.pub)
.work (*system.work.generate (latest)) .work (*system.work.generate (latest))
.build_shared (); .build_shared ();
auto open = builder auto open = nano::block_builder ()
.state () .state ()
.account (key.pub) .account (dest.pub)
.previous (0) .previous (0)
.representative (key.pub) .representative (dest_rep)
.balance (amount) .balance (amount)
.link (send->hash ()) .link (send->hash ())
.sign (key.prv, key.pub) .sign (dest.prv, dest.pub)
.work (*system.work.generate (key.pub)) .work (*system.work.generate (dest.pub))
.build_shared (); .build_shared ();
EXPECT_TRUE (nano::test::process (node, { send, open })); 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 })); 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;
} }

View file

@ -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); 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 * Sends `amount` raw from `source` account chain into a newly created account and sets that account as its own representative
* @return created representative * @return created representative

View file

@ -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); 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;
}
}
}

View file

@ -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. * 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); [[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);
} }
} }