Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix epoch_conflict_confirm test #3906

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 36 additions & 36 deletions nano/core_test/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<nano::mutex> 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::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 }));
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.
Expand Down
6 changes: 6 additions & 0 deletions nano/node/active_transactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,12 @@ bool nano::active_transactions::active (nano::block const & block_a)
return roots.get<tag_root> ().find (block_a.qualified_root ()) != roots.get<tag_root> ().end () && blocks.find (block_a.hash ()) != blocks.end ();
}

bool nano::active_transactions::active (const nano::block_hash & hash)
{
nano::lock_guard<nano::mutex> guard{ mutex };
return blocks.find (hash) != blocks.end ();
}

std::shared_ptr<nano::election> nano::active_transactions::election (nano::qualified_root const & root_a) const
{
std::shared_ptr<nano::election> result;
Expand Down
4 changes: 4 additions & 0 deletions nano/node/active_transactions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<nano::election> election (nano::qualified_root const &) const;
std::shared_ptr<nano::block> winner (nano::block_hash const &) const;
// Returns a list of elections sorted by difficulty
Expand Down
78 changes: 72 additions & 6 deletions nano/test_common/testutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ bool nano::test::process (nano::node & node, std::vector<std::shared_ptr<nano::b
return true;
}

bool nano::test::process_live (nano::node & node, std::vector<std::shared_ptr<nano::block>> blocks)
{
for (auto & block : blocks)
{
node.process_active (block);
}
return true;
}

bool nano::test::confirm (nano::node & node, std::vector<nano::block_hash> hashes)
{
// Finish processing all blocks
Expand Down Expand Up @@ -79,9 +88,7 @@ bool nano::test::confirm (nano::node & node, std::vector<nano::block_hash> hashe

bool nano::test::confirm (nano::node & node, std::vector<std::shared_ptr<nano::block>> blocks)
{
std::vector<nano::block_hash> 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<nano::block_hash> hashes)
Expand All @@ -98,9 +105,61 @@ bool nano::test::confirmed (nano::node & node, std::vector<nano::block_hash> has

bool nano::test::confirmed (nano::node & node, std::vector<std::shared_ptr<nano::block>> blocks)
{
std::vector<nano::block_hash> 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::exists (nano::node & node, std::vector<nano::block_hash> hashes)
{
for (auto & hash : hashes)
{
if (!node.block (hash))
{
return false;
}
}
return true;
}

bool nano::test::exists (nano::node & node, std::vector<std::shared_ptr<nano::block>> blocks)
{
return exists (node, blocks_to_hashes (blocks));
}

bool nano::test::activate (nano::node & node, std::vector<nano::block_hash> 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<std::shared_ptr<nano::block>> blocks)
{
return activate (node, blocks_to_hashes (blocks));
}

bool nano::test::active (nano::node & node, std::vector<nano::block_hash> hashes)
{
for (auto & hash : hashes)
{
if (!node.active.active (hash))
{
return false;
}
}
return true;
}

bool nano::test::active (nano::node & node, std::vector<std::shared_ptr<nano::block>> blocks)
{
return active (node, blocks_to_hashes (blocks));
}

std::shared_ptr<nano::vote> nano::test::make_vote (nano::keypair key, std::vector<nano::block_hash> hashes, uint64_t timestamp, uint8_t duration)
Expand All @@ -113,4 +172,11 @@ std::shared_ptr<nano::vote> nano::test::make_vote (nano::keypair key, std::vecto
std::vector<nano::block_hash> 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::block_hash> nano::test::blocks_to_hashes (std::vector<std::shared_ptr<nano::block>> blocks)
{
std::vector<nano::block_hash> hashes;
std::transform (blocks.begin (), blocks.end (), std::back_inserter (hashes), [] (auto & block) { return block->hash (); });
return hashes;
}
40 changes: 40 additions & 0 deletions nano/test_common/testutil.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::shared_ptr<nano::block>> 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<std::shared_ptr<nano::block>> blocks);
/*
* Convenience function to confirm a list of blocks
* The actual confirmation will happen asynchronously, check for that with `nano::test::confirmed (..)` function
Expand All @@ -236,6 +242,36 @@ namespace test
* @return true if all blocks are confirmed, false otherwise
*/
bool confirmed (nano::node & node, std::vector<nano::block_hash> 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 exists (nano::node & node, std::vector<nano::block_hash> 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 exists (nano::node & node, std::vector<std::shared_ptr<nano::block>> 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<nano::block_hash> 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<std::shared_ptr<nano::block>> 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<nano::block_hash> 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<std::shared_ptr<nano::block>> blocks);
/*
* Convenience function to create a new vote from list of blocks
*/
Expand All @@ -244,5 +280,9 @@ namespace test
* Convenience function to create a new vote from list of block hashes
*/
std::shared_ptr<nano::vote> make_vote (nano::keypair key, std::vector<nano::block_hash> hashes, uint64_t timestamp = 0, uint8_t duration = 0);
/*
* Converts list of blocks to list of hashes
*/
std::vector<nano::block_hash> blocks_to_hashes (std::vector<std::shared_ptr<nano::block>> blocks);
}
}