From 340425d43b50b8e9c97288d908eef8683b986249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+fikumikudev@users.noreply.github.com> Date: Wed, 24 Aug 2022 19:00:28 +0200 Subject: [PATCH 1/3] Add test utility functions --- nano/node/active_transactions.cpp | 6 +++ nano/node/active_transactions.hpp | 4 ++ nano/test_common/testutil.cpp | 78 ++++++++++++++++++++++++++++--- nano/test_common/testutil.hpp | 40 ++++++++++++++++ 4 files changed, 122 insertions(+), 6 deletions(-) diff --git a/nano/node/active_transactions.cpp b/nano/node/active_transactions.cpp index 2ab73a870b..405fcc4fda 100644 --- a/nano/node/active_transactions.cpp +++ b/nano/node/active_transactions.cpp @@ -506,6 +506,12 @@ bool nano::active_transactions::active (nano::block const & block_a) return roots.get ().find (block_a.qualified_root ()) != roots.get ().end () && blocks.find (block_a.hash ()) != blocks.end (); } +bool nano::active_transactions::active (const nano::block_hash & hash) +{ + nano::lock_guard guard{ mutex }; + return blocks.find (hash) != blocks.end (); +} + std::shared_ptr nano::active_transactions::election (nano::qualified_root const & root_a) const { std::shared_ptr result; diff --git a/nano/node/active_transactions.hpp b/nano/node/active_transactions.hpp index 3321527085..16f2d1bcf2 100644 --- a/nano/node/active_transactions.hpp +++ b/nano/node/active_transactions.hpp @@ -151,6 +151,10 @@ class active_transactions final // Is the root of this block in the roots container bool active (nano::block const &); bool active (nano::qualified_root const &); + /* + * Is the block hash present in any active election + */ + bool active (nano::block_hash const &); std::shared_ptr election (nano::qualified_root const &) const; std::shared_ptr winner (nano::block_hash const &) const; // Returns a list of elections sorted by difficulty diff --git a/nano/test_common/testutil.cpp b/nano/test_common/testutil.cpp index 284a1b842d..adb31a7616 100644 --- a/nano/test_common/testutil.cpp +++ b/nano/test_common/testutil.cpp @@ -50,6 +50,15 @@ bool nano::test::process (nano::node & node, std::vector> blocks) +{ + for (auto & block : blocks) + { + node.process_active (block); + } + return true; +} + bool nano::test::confirm (nano::node & node, std::vector hashes) { // Finish processing all blocks @@ -79,9 +88,7 @@ bool nano::test::confirm (nano::node & node, std::vector hashe bool nano::test::confirm (nano::node & node, std::vector> blocks) { - std::vector hashes; - std::transform (blocks.begin (), blocks.end (), std::back_inserter (hashes), [] (auto & block) { return block->hash (); }); - return confirm (node, hashes); + return confirm (node, blocks_to_hashes (blocks)); } bool nano::test::confirmed (nano::node & node, std::vector hashes) @@ -98,9 +105,61 @@ bool nano::test::confirmed (nano::node & node, std::vector has bool nano::test::confirmed (nano::node & node, std::vector> blocks) { - std::vector hashes; - std::transform (blocks.begin (), blocks.end (), std::back_inserter (hashes), [] (auto & block) { return block->hash (); }); - return confirmed (node, hashes); + return confirmed (node, blocks_to_hashes (blocks)); +} + +bool nano::test::exist (nano::node & node, std::vector hashes) +{ + for (auto & hash : hashes) + { + if (!node.block (hash)) + { + return false; + } + } + return true; +} + +bool nano::test::exist (nano::node & node, std::vector> blocks) +{ + return exist (node, blocks_to_hashes (blocks)); +} + +bool nano::test::activate (nano::node & node, std::vector hashes) +{ + for (auto & hash : hashes) + { + auto disk_block = node.block (hash); + if (disk_block == nullptr) + { + // Block does not exist in the ledger yet + return false; + } + node.scheduler.manual (disk_block); + } + return true; +} + +bool nano::test::activate (nano::node & node, std::vector> blocks) +{ + return activate (node, blocks_to_hashes (blocks)); +} + +bool nano::test::active (nano::node & node, std::vector hashes) +{ + for (auto & hash : hashes) + { + if (!node.active.active (hash)) + { + return false; + } + } + return true; +} + +bool nano::test::active (nano::node & node, std::vector> blocks) +{ + return active (node, blocks_to_hashes (blocks)); } std::shared_ptr nano::test::make_vote (nano::keypair key, std::vector hashes, uint64_t timestamp, uint8_t duration) @@ -113,4 +172,11 @@ std::shared_ptr nano::test::make_vote (nano::keypair key, std::vecto std::vector hashes; std::transform (blocks.begin (), blocks.end (), std::back_inserter (hashes), [] (auto & block) { return block->hash (); }); return make_vote (key, hashes, timestamp, duration); +} + +std::vector nano::test::blocks_to_hashes (std::vector> blocks) +{ + std::vector hashes; + std::transform (blocks.begin (), blocks.end (), std::back_inserter (hashes), [] (auto & block) { return block->hash (); }); + return hashes; } \ No newline at end of file diff --git a/nano/test_common/testutil.hpp b/nano/test_common/testutil.hpp index baafd6df84..6fb4d89dc1 100644 --- a/nano/test_common/testutil.hpp +++ b/nano/test_common/testutil.hpp @@ -214,6 +214,12 @@ namespace test @return true if all blocks were successfully processed and inserted into ledger */ bool process (nano::node & node, std::vector> blocks); + /* + * Convenience function to process multiple blocks as if they were live blocks arriving from the network + * It is not guaranted that those blocks will be inserted into ledger (there might be forks, missing links etc) + * @return true if all blocks were successfully processed + */ + bool process_live (nano::node & node, std::vector> blocks); /* * Convenience function to confirm a list of blocks * The actual confirmation will happen asynchronously, check for that with `nano::test::confirmed (..)` function @@ -236,6 +242,36 @@ namespace test * @return true if all blocks are confirmed, false otherwise */ bool confirmed (nano::node & node, std::vector hashes); + /* + * Convenience function to check whether a list of hashes exists in node ledger. + * @return true if all blocks are fully processed and inserted in the ledger, false otherwise + */ + bool exist (nano::node & node, std::vector hashes); + /* + * Convenience function to check whether a list of blocks exists in node ledger. + * @return true if all blocks are fully processed and inserted in the ledger, false otherwise + */ + bool exist (nano::node & node, std::vector> blocks); + /* + * Convenience function to start elections for a list of hashes. Blocks are loaded from ledger. + * @return true if all blocks exist and were queued to election scheduler + */ + bool activate (nano::node & node, std::vector hashes); + /* + * Convenience function to start elections for a list of hashes. Blocks are loaded from ledger. + * @return true if all blocks exist and were queued to election scheduler + */ + bool activate (nano::node & node, std::vector> blocks); + /* + * Convenience function that checks whether all hashes from list have currently active elections + * @return true if all blocks have currently active elections, false othersie + */ + bool active (nano::node & node, std::vector hashes); + /* + * Convenience function that checks whether all hashes from list have currently active elections + * @return true if all blocks have currently active elections, false othersie + */ + bool active (nano::node & node, std::vector> blocks); /* * Convenience function to create a new vote from list of blocks */ @@ -244,5 +280,9 @@ namespace test * Convenience function to create a new vote from list of block hashes */ std::shared_ptr make_vote (nano::keypair key, std::vector hashes, uint64_t timestamp = 0, uint8_t duration = 0); + /* + * Converts list of blocks to list of hashes + */ + std::vector blocks_to_hashes (std::vector> blocks); } } \ No newline at end of file From 47c496f3618d92d2a83d8184d419a2d24bd91da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+fikumikudev@users.noreply.github.com> Date: Wed, 24 Aug 2022 19:00:54 +0200 Subject: [PATCH 2/3] Fix `epoch_conflict_confirm` test --- nano/core_test/node.cpp | 72 ++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/nano/core_test/node.cpp b/nano/core_test/node.cpp index 4ac92d9831..4550bd690e 100644 --- a/nano/core_test/node.cpp +++ b/nano/core_test/node.cpp @@ -2741,9 +2741,9 @@ TEST (node, epoch_conflict_confirm) nano::test::system system; nano::node_config node_config (nano::test::get_available_port (), system.logging); node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled; - auto node0 = system.add_node (node_config); + auto & node0 = *system.add_node (node_config); node_config.peering_port = nano::test::get_available_port (); - auto node1 = system.add_node (node_config); + auto & node1 = *system.add_node (node_config); nano::keypair key; nano::keypair epoch_signer (nano::dev::genesis_key); nano::state_block_builder builder; @@ -2788,44 +2788,44 @@ TEST (node, epoch_conflict_confirm) .previous (0) .representative (0) .balance (0) - .link (node0->ledger.epoch_link (nano::epoch::epoch_1)) + .link (node0.ledger.epoch_link (nano::epoch::epoch_1)) .sign (epoch_signer.prv, epoch_signer.pub) .work (*system.work.generate (open->hash ())) .build_shared (); - ASSERT_EQ (nano::process_result::progress, node1->process (*send).code); - ASSERT_EQ (nano::process_result::progress, node1->process (*send2).code); - ASSERT_EQ (nano::process_result::progress, node1->process (*open).code); - // Confirm block in node1 to allow generating votes - node1->block_confirm (open); - auto election (node1->active.election (open->qualified_root ())); - ASSERT_NE (nullptr, election); - election->force_confirm (); - ASSERT_TIMELY (3s, node1->block_confirmed (open->hash ())); - ASSERT_EQ (nano::process_result::progress, node0->process (*send).code); - ASSERT_EQ (nano::process_result::progress, node0->process (*send2).code); - ASSERT_EQ (nano::process_result::progress, node0->process (*open).code); - node0->process_active (change); - node0->process_active (epoch_open); - ASSERT_TIMELY (10s, node0->block (change->hash ()) && node0->block (epoch_open->hash ()) && node1->block (change->hash ()) && node1->block (epoch_open->hash ())); - // Confirm blocks in node1 to allow generating votes - nano::test::blocks_confirm (*node1, { change, epoch_open }, true /* forced */); - ASSERT_TIMELY (3s, node1->block_confirmed (change->hash ()) && node1->block_confirmed (epoch_open->hash ())); - // Start elections for node0 - nano::test::blocks_confirm (*node0, { change, epoch_open }); - ASSERT_EQ (2, node0->active.size ()); - { - nano::lock_guard lock (node0->active.mutex); - ASSERT_TRUE (node0->active.blocks.find (change->hash ()) != node0->active.blocks.end ()); - ASSERT_TRUE (node0->active.blocks.find (epoch_open->hash ()) != node0->active.blocks.end ()); - } + + // Process initial blocks on node1 + ASSERT_TRUE (nano::test::process (node1, { send, send2, open })); + + // Confirm open block in node1 to allow generating votes + ASSERT_TRUE (nano::test::confirm (node1, { open })); + ASSERT_TIMELY (5s, nano::test::confirmed (node1, { open })); + + // Process initial blocks on node0 + ASSERT_TRUE (nano::test::process (node0, { send, send2, open })); + + // Process conflicting blocks on node 0 as blocks coming from live network + ASSERT_TRUE (nano::test::process_live (node0, { change, epoch_open })); + + // Ensure blocks were propagated to both nodes + ASSERT_TIMELY (5s, nano::test::exist (node0, { change, epoch_open })); + ASSERT_TIMELY (5s, nano::test::exist (node1, { change, epoch_open })); + + // Confirm initial blocks in node1 to allow generating votes later + ASSERT_TRUE (nano::test::confirm (node1, { change, epoch_open, send2 })); + ASSERT_TIMELY (5s, nano::test::confirmed (node1, { change, epoch_open, send2 })); + + // Start elections for node0 for conflicting change and epoch_open blocks (those two blocks have the same root) + ASSERT_TRUE (nano::test::activate (node0, { change, epoch_open })); + ASSERT_TIMELY (5s, nano::test::active (node0, { change, epoch_open })); + + // Make node1 a representative system.wallet (1)->insert_adhoc (nano::dev::genesis_key.prv); - ASSERT_TIMELY (5s, node0->active.election (change->qualified_root ()) == nullptr); - ASSERT_TIMELY (5s, node0->active.empty ()); - { - auto transaction (node0->store.tx_begin_read ()); - ASSERT_TRUE (node0->ledger.store.block.exists (transaction, change->hash ())); - ASSERT_TRUE (node0->ledger.store.block.exists (transaction, epoch_open->hash ())); - } + + // Ensure the elections for conflicting blocks have completed + ASSERT_TIMELY (5s, nano::test::active (node0, { change, epoch_open })); + + // Ensure both conflicting blocks were successfully processed and confirmed + ASSERT_TIMELY (5s, nano::test::confirmed (node0, { change, epoch_open })); } // Test disabled because it's failing intermittently. From c0929bcf1af7c41836ce1eec6fb6d8a3630ffdaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+fikumikudev@users.noreply.github.com> Date: Mon, 29 Aug 2022 11:58:12 +0200 Subject: [PATCH 3/3] Renaming --- nano/core_test/node.cpp | 4 ++-- nano/test_common/testutil.cpp | 6 +++--- nano/test_common/testutil.hpp | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/nano/core_test/node.cpp b/nano/core_test/node.cpp index 4550bd690e..fe4b81bd79 100644 --- a/nano/core_test/node.cpp +++ b/nano/core_test/node.cpp @@ -2807,8 +2807,8 @@ TEST (node, epoch_conflict_confirm) ASSERT_TRUE (nano::test::process_live (node0, { change, epoch_open })); // Ensure blocks were propagated to both nodes - ASSERT_TIMELY (5s, nano::test::exist (node0, { change, epoch_open })); - ASSERT_TIMELY (5s, nano::test::exist (node1, { change, epoch_open })); + ASSERT_TIMELY (5s, nano::test::exists (node0, { change, epoch_open })); + ASSERT_TIMELY (5s, nano::test::exists (node1, { change, epoch_open })); // Confirm initial blocks in node1 to allow generating votes later ASSERT_TRUE (nano::test::confirm (node1, { change, epoch_open, send2 })); diff --git a/nano/test_common/testutil.cpp b/nano/test_common/testutil.cpp index adb31a7616..5718ee15cc 100644 --- a/nano/test_common/testutil.cpp +++ b/nano/test_common/testutil.cpp @@ -108,7 +108,7 @@ bool nano::test::confirmed (nano::node & node, std::vector hashes) +bool nano::test::exists (nano::node & node, std::vector hashes) { for (auto & hash : hashes) { @@ -120,9 +120,9 @@ bool nano::test::exist (nano::node & node, std::vector hashes) return true; } -bool nano::test::exist (nano::node & node, std::vector> blocks) +bool nano::test::exists (nano::node & node, std::vector> blocks) { - return exist (node, blocks_to_hashes (blocks)); + return exists (node, blocks_to_hashes (blocks)); } bool nano::test::activate (nano::node & node, std::vector hashes) diff --git a/nano/test_common/testutil.hpp b/nano/test_common/testutil.hpp index 6fb4d89dc1..c48462b1ef 100644 --- a/nano/test_common/testutil.hpp +++ b/nano/test_common/testutil.hpp @@ -246,12 +246,12 @@ namespace test * Convenience function to check whether a list of hashes exists in node ledger. * @return true if all blocks are fully processed and inserted in the ledger, false otherwise */ - bool exist (nano::node & node, std::vector hashes); + bool exists (nano::node & node, std::vector hashes); /* * Convenience function to check whether a list of blocks exists in node ledger. * @return true if all blocks are fully processed and inserted in the ledger, false otherwise */ - bool exist (nano::node & node, std::vector> blocks); + bool exists (nano::node & node, std::vector> blocks); /* * Convenience function to start elections for a list of hashes. Blocks are loaded from ledger. * @return true if all blocks exist and were queued to election scheduler