Skip to content

Commit

Permalink
Bucket tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pwojcikdev committed Jul 10, 2024
1 parent 45649e9 commit 22f057b
Show file tree
Hide file tree
Showing 4 changed files with 248 additions and 41 deletions.
56 changes: 27 additions & 29 deletions nano/core_test/active_elections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1294,35 +1294,33 @@ TEST (active_elections, list_active)
TEST (active_elections, vacancy)
{
std::atomic<bool> updated = false;
{
nano::test::system system;
nano::node_config config = system.default_config ();
config.active_elections.size = 1;
auto & node = *system.add_node (config);
nano::state_block_builder builder;
auto send = builder.make_block ()
.account (nano::dev::genesis_key.pub)
.previous (nano::dev::genesis->hash ())
.representative (nano::dev::genesis_key.pub)
.link (nano::dev::genesis_key.pub)
.balance (nano::dev::constants.genesis_amount - nano::Gxrb_ratio)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*system.work.generate (nano::dev::genesis->hash ()))
.build ();
node.active.vacancy_update = [&updated] () { updated = true; };
ASSERT_EQ (nano::block_status::progress, node.process (send));
ASSERT_EQ (1, node.active.vacancy (nano::election_behavior::priority));
ASSERT_EQ (0, node.active.size ());
auto election1 = nano::test::start_election (system, node, send->hash ());
ASSERT_TIMELY (1s, updated);
updated = false;
ASSERT_EQ (0, node.active.vacancy (nano::election_behavior::priority));
ASSERT_EQ (1, node.active.size ());
election1->force_confirm ();
ASSERT_TIMELY (1s, updated);
ASSERT_EQ (1, node.active.vacancy (nano::election_behavior::priority));
ASSERT_EQ (0, node.active.size ());
}
nano::test::system system;
nano::node_config config = system.default_config ();
config.active_elections.size = 1;
auto & node = *system.add_node (config);
nano::state_block_builder builder;
auto send = builder.make_block ()
.account (nano::dev::genesis_key.pub)
.previous (nano::dev::genesis->hash ())
.representative (nano::dev::genesis_key.pub)
.link (nano::dev::genesis_key.pub)
.balance (nano::dev::constants.genesis_amount - nano::Gxrb_ratio)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*system.work.generate (nano::dev::genesis->hash ()))
.build ();
node.active.vacancy_update = [&updated] () { updated = true; };
ASSERT_EQ (nano::block_status::progress, node.process (send));
ASSERT_EQ (1, node.active.vacancy (nano::election_behavior::priority));
ASSERT_EQ (0, node.active.size ());
auto election1 = nano::test::start_election (system, node, send->hash ());
ASSERT_TIMELY (1s, updated);
updated = false;
ASSERT_EQ (0, node.active.vacancy (nano::election_behavior::priority));
ASSERT_EQ (1, node.active.size ());
election1->force_confirm ();
ASSERT_TIMELY (1s, updated);
ASSERT_EQ (1, node.active.vacancy (nano::election_behavior::priority));
ASSERT_EQ (0, node.active.size ());
}

/*
Expand Down
213 changes: 202 additions & 11 deletions nano/core_test/election_scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,121 @@

using namespace std::chrono_literals;

namespace
{
nano::keypair & keyzero ()
{
static nano::keypair result;
return result;
}
nano::keypair & key0 ()
{
static nano::keypair result;
return result;
}
nano::keypair & key1 ()
{
static nano::keypair result;
return result;
}
nano::keypair & key2 ()
{
static nano::keypair result;
return result;
}
nano::keypair & key3 ()
{
static nano::keypair result;
return result;
}
std::shared_ptr<nano::state_block> & blockzero ()
{
nano::block_builder builder;
static auto result = builder
.state ()
.account (keyzero ().pub)
.previous (0)
.representative (keyzero ().pub)
.balance (0)
.link (0)
.sign (keyzero ().prv, keyzero ().pub)
.work (0)
.build ();
return result;
}
std::shared_ptr<nano::state_block> & block0 ()
{
nano::block_builder builder;
static auto result = builder
.state ()
.account (key0 ().pub)
.previous (0)
.representative (key0 ().pub)
.balance (nano::Gxrb_ratio)
.link (0)
.sign (key0 ().prv, key0 ().pub)
.work (0)
.build ();
return result;
}
std::shared_ptr<nano::state_block> & block1 ()
{
nano::block_builder builder;
static auto result = builder
.state ()
.account (key1 ().pub)
.previous (0)
.representative (key1 ().pub)
.balance (nano::Mxrb_ratio)
.link (0)
.sign (key1 ().prv, key1 ().pub)
.work (0)
.build ();
return result;
}
std::shared_ptr<nano::state_block> & block2 ()
{
nano::block_builder builder;
static auto result = builder
.state ()
.account (key2 ().pub)
.previous (0)
.representative (key2 ().pub)
.balance (nano::Gxrb_ratio)
.link (0)
.sign (key2 ().prv, key2 ().pub)
.work (0)
.build ();
return result;
}
std::shared_ptr<nano::state_block> & block3 ()
{
nano::block_builder builder;
static auto result = builder
.state ()
.account (key3 ().pub)
.previous (0)
.representative (key3 ().pub)
.balance (nano::Mxrb_ratio)
.link (0)
.sign (key3 ().prv, key3 ().pub)
.work (0)
.build ();
return result;
}
}

TEST (election_scheduler, construction)
{
nano::test::system system{ 1 };
nano::test::system system;
auto & node = *system.add_node ();
}

TEST (election_scheduler, activate_one_timely)
{
nano::test::system system{ 1 };
nano::test::system system;
auto & node = *system.add_node ();

nano::state_block_builder builder;
auto send1 = builder.make_block ()
.account (nano::dev::genesis_key.pub)
Expand All @@ -31,14 +138,16 @@ TEST (election_scheduler, activate_one_timely)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*system.work.generate (nano::dev::genesis->hash ()))
.build ();
system.nodes[0]->ledger.process (system.nodes[0]->ledger.tx_begin_write (), send1);
system.nodes[0]->scheduler.priority.activate (system.nodes[0]->ledger.tx_begin_read (), nano::dev::genesis_key.pub);
ASSERT_TIMELY (5s, system.nodes[0]->active.election (send1->qualified_root ()));
node.ledger.process (node.ledger.tx_begin_write (), send1);
node.scheduler.priority.activate (node.ledger.tx_begin_read (), nano::dev::genesis_key.pub);
ASSERT_TIMELY (5s, node.active.election (send1->qualified_root ()));
}

TEST (election_scheduler, activate_one_flush)
{
nano::test::system system{ 1 };
nano::test::system system;
auto & node = *system.add_node ();

nano::state_block_builder builder;
auto send1 = builder.make_block ()
.account (nano::dev::genesis_key.pub)
Expand All @@ -49,9 +158,9 @@ TEST (election_scheduler, activate_one_flush)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*system.work.generate (nano::dev::genesis->hash ()))
.build ();
system.nodes[0]->ledger.process (system.nodes[0]->ledger.tx_begin_write (), send1);
system.nodes[0]->scheduler.priority.activate (system.nodes[0]->ledger.tx_begin_read (), nano::dev::genesis_key.pub);
ASSERT_TIMELY (5s, system.nodes[0]->active.election (send1->qualified_root ()));
node.ledger.process (node.ledger.tx_begin_write (), send1);
node.scheduler.priority.activate (node.ledger.tx_begin_read (), nano::dev::genesis_key.pub);
ASSERT_TIMELY (5s, node.active.election (send1->qualified_root ()));
}

/**
Expand All @@ -71,13 +180,13 @@ TEST (election_scheduler, activate_one_flush)
*/
TEST (election_scheduler, no_vacancy)
{
nano::test::system system{};
nano::test::system system;

nano::node_config config = system.default_config ();
config.active_elections.size = 1;
config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;

auto & node = *system.add_node (config);

nano::state_block_builder builder{};
nano::keypair key{};

Expand Down Expand Up @@ -146,3 +255,85 @@ TEST (election_scheduler, no_vacancy)
ASSERT_TIMELY (5s, node.active.election (block2->qualified_root ()) != nullptr);
ASSERT_TRUE (node.scheduler.priority.empty ());
}

TEST (election_scheduler_bucket, construction)
{
nano::test::system system;
auto & node = *system.add_node ();

nano::scheduler::priority_bucket_config bucket_config;
nano::scheduler::bucket bucket{ nano::Gxrb_ratio, bucket_config, node.active, node.stats };
ASSERT_EQ (nano::Gxrb_ratio, bucket.minimum_balance);
ASSERT_TRUE (bucket.empty ());
ASSERT_EQ (0, bucket.size ());
}

TEST (election_scheduler_bucket, insert_one)
{
nano::test::system system;
auto & node = *system.add_node ();

nano::scheduler::priority_bucket_config bucket_config;
nano::scheduler::bucket bucket{ 0, bucket_config, node.active, node.stats };
ASSERT_TRUE (bucket.push (1000, block0 ()));
ASSERT_FALSE (bucket.empty ());
ASSERT_EQ (1, bucket.size ());
auto blocks = bucket.blocks ();
ASSERT_EQ (1, blocks.size ());
ASSERT_EQ (block0 (), blocks.front ());
}

TEST (election_scheduler_bucket, insert_duplicate)
{
nano::test::system system;
auto & node = *system.add_node ();

nano::scheduler::priority_bucket_config bucket_config;
nano::scheduler::bucket bucket{ 0, bucket_config, node.active, node.stats };
ASSERT_TRUE (bucket.push (1000, block0 ()));
ASSERT_FALSE (bucket.push (1000, block0 ()));
}

TEST (election_scheduler_bucket, insert_many)
{
nano::test::system system;
auto & node = *system.add_node ();

nano::scheduler::priority_bucket_config bucket_config;
nano::scheduler::bucket bucket{ 0, bucket_config, node.active, node.stats };
ASSERT_TRUE (bucket.push (2000, block0 ()));
ASSERT_TRUE (bucket.push (1001, block1 ()));
ASSERT_TRUE (bucket.push (1000, block2 ()));
ASSERT_TRUE (bucket.push (900, block3 ()));
ASSERT_FALSE (bucket.empty ());
ASSERT_EQ (4, bucket.size ());
auto blocks = bucket.blocks ();
ASSERT_EQ (4, blocks.size ());
// Ensure correct order
ASSERT_EQ (blocks[0], block3 ());
ASSERT_EQ (blocks[1], block2 ());
ASSERT_EQ (blocks[2], block1 ());
ASSERT_EQ (blocks[3], block0 ());
}

TEST (election_scheduler_bucket, max_blocks)
{
nano::test::system system;
auto & node = *system.add_node ();

nano::scheduler::priority_bucket_config bucket_config{
.max_blocks = 2
};
nano::scheduler::bucket bucket{ 0, bucket_config, node.active, node.stats };
ASSERT_TRUE (bucket.push (2000, block0 ()));
ASSERT_TRUE (bucket.push (900, block1 ()));
ASSERT_FALSE (bucket.push (3000, block2 ()));
ASSERT_TRUE (bucket.push (1001, block3 ())); // Evicts 2000
ASSERT_TRUE (bucket.push (1000, block0 ())); // Evicts 1001
ASSERT_EQ (2, bucket.size ());
auto blocks = bucket.blocks ();
ASSERT_EQ (2, blocks.size ());
// Ensure correct order
ASSERT_EQ (blocks[0], block1 ());
ASSERT_EQ (blocks[1], block0 ());
}
12 changes: 12 additions & 0 deletions nano/node/scheduler/bucket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,18 @@ void nano::scheduler::bucket::cancel_lowest_election ()
}
}

std::deque<std::shared_ptr<nano::block>> nano::scheduler::bucket::blocks () const
{
nano::lock_guard<nano::mutex> lock{ mutex };

std::deque<std::shared_ptr<nano::block>> result;
for (auto const & item : queue)
{
result.push_back (item.block);
}
return result;
}

void nano::scheduler::bucket::dump () const
{
for (auto const & item : queue)
Expand Down
8 changes: 7 additions & 1 deletion nano/node/scheduler/bucket.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <nano/node/fwd.hpp>
#include <nano/secure/common.hpp>

#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
Expand All @@ -10,6 +11,7 @@

#include <cstddef>
#include <cstdint>
#include <deque>
#include <memory>
#include <set>

Expand Down Expand Up @@ -41,7 +43,9 @@ class priority_bucket_config final
std::size_t max_elections{ 150 };
};

/** A class which holds an ordered set of blocks to be scheduled, ordered by their block arrival time
/**
* A class which holds an ordered set of blocks to be scheduled, ordered by their block arrival time
* TODO: This combines both block ordering and election management, which makes the class harder to test. The functionality should be split.
*/
class bucket final
{
Expand All @@ -63,6 +67,8 @@ class bucket final
size_t size () const;
size_t election_count () const;
bool empty () const;
std::deque<std::shared_ptr<nano::block>> blocks () const;

void dump () const;

private:
Expand Down

0 comments on commit 22f057b

Please sign in to comment.