Skip to content

Commit

Permalink
Merge pull request #4312 from pwojcikdev/hinted-fixing-2-develop
Browse files Browse the repository at this point in the history
Hinted scheduler improvements
  • Loading branch information
pwojcikdev committed Oct 17, 2023
2 parents 5bc61a2 + 91ffaf2 commit 5cd0355
Show file tree
Hide file tree
Showing 26 changed files with 664 additions and 568 deletions.
57 changes: 31 additions & 26 deletions nano/core_test/active_transactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ TEST (active_transactions, inactive_votes_cache)
.build_shared ();
auto vote (std::make_shared<nano::vote> (nano::dev::genesis_key.pub, nano::dev::genesis_key.prv, nano::vote::timestamp_max, nano::vote::duration_max, std::vector<nano::block_hash> (1, send->hash ())));
node.vote_processor.vote (vote, std::make_shared<nano::transport::inproc::channel> (node, node));
ASSERT_TIMELY (5s, node.inactive_vote_cache.cache_size () == 1);
ASSERT_TIMELY (5s, node.vote_cache.size () == 1);
node.process_active (send);
node.block_processor.flush ();
ASSERT_TIMELY (5s, node.ledger.block_confirmed (node.store.tx_begin_read (), send->hash ()));
Expand All @@ -264,7 +264,7 @@ TEST (active_transactions, inactive_votes_cache_non_final)
// Non-final vote
auto vote = std::make_shared<nano::vote> (nano::dev::genesis_key.pub, nano::dev::genesis_key.prv, 0, 0, std::vector<nano::block_hash> (1, send->hash ()));
node.vote_processor.vote (vote, std::make_shared<nano::transport::inproc::channel> (node, node));
ASSERT_TIMELY (5s, node.inactive_vote_cache.cache_size () == 1);
ASSERT_TIMELY (5s, node.vote_cache.size () == 1);

node.process_active (send);
std::shared_ptr<nano::election> election;
Expand Down Expand Up @@ -301,7 +301,7 @@ TEST (active_transactions, inactive_votes_cache_fork)

auto const vote = std::make_shared<nano::vote> (nano::dev::genesis_key.pub, nano::dev::genesis_key.prv, nano::vote::timestamp_max, nano::vote::duration_max, std::vector<nano::block_hash> (1, send1->hash ()));
node.vote_processor.vote (vote, std::make_shared<nano::transport::inproc::channel> (node, node));
ASSERT_TIMELY (5s, node.inactive_vote_cache.cache_size () == 1);
ASSERT_TIMELY (5s, node.vote_cache.size () == 1);

node.process_active (send2);

Expand Down Expand Up @@ -356,10 +356,10 @@ TEST (active_transactions, inactive_votes_cache_existing_vote)
ASSERT_EQ (nano::vote::timestamp_min * 1, last_vote1.timestamp);
// Attempt to change vote with inactive_votes_cache
nano::unique_lock<nano::mutex> active_lock (node.active.mutex);
node.inactive_vote_cache.vote (send->hash (), vote1);
auto cache = node.inactive_vote_cache.find (send->hash ());
node.vote_cache.vote (send->hash (), vote1);
auto cache = node.vote_cache.find (send->hash ());
ASSERT_TRUE (cache);
ASSERT_EQ (1, cache->voters.size ());
ASSERT_EQ (1, cache->voters ().size ());
cache->fill (election);
// Check that election data is not changed
ASSERT_EQ (2, election->votes ().size ());
Expand Down Expand Up @@ -416,9 +416,9 @@ TEST (active_transactions, inactive_votes_cache_multiple_votes)
auto vote2 (std::make_shared<nano::vote> (nano::dev::genesis_key.pub, nano::dev::genesis_key.prv, 0, 0, std::vector<nano::block_hash> (1, send1->hash ())));
node.vote_processor.vote (vote2, std::make_shared<nano::transport::inproc::channel> (node, node));

ASSERT_TIMELY (5s, node.inactive_vote_cache.find (send1->hash ()));
ASSERT_TIMELY (5s, node.inactive_vote_cache.find (send1->hash ())->voters.size () == 2);
ASSERT_EQ (1, node.inactive_vote_cache.cache_size ());
ASSERT_TIMELY (5s, node.vote_cache.find (send1->hash ()));
ASSERT_TIMELY (5s, node.vote_cache.find (send1->hash ())->voters ().size () == 2);
ASSERT_EQ (1, node.vote_cache.size ());
node.scheduler.priority.activate (nano::dev::genesis_key.pub, node.store.tx_begin_read ());
std::shared_ptr<nano::election> election;
ASSERT_TIMELY (5s, election = node.active.election (send1->qualified_root ()));
Expand All @@ -438,7 +438,7 @@ TEST (active_transactions, inactive_votes_cache_election_start)
nano::send_block_builder send_block_builder;
nano::state_block_builder state_block_builder;
// Enough weight to trigger election hinting but not enough to confirm block on its own
auto amount = ((node.online_reps.trended () / 100) * node.config.election_hint_weight_percent) / 2 + 1000 * nano::Gxrb_ratio;
auto amount = ((node.online_reps.trended () / 100) * node.config.hinted_scheduler.hinting_threshold_percent) / 2 + 1000 * nano::Gxrb_ratio;
auto send1 = send_block_builder.make_block ()
.previous (latest)
.destination (key1.pub)
Expand Down Expand Up @@ -493,28 +493,33 @@ TEST (active_transactions, inactive_votes_cache_election_start)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*system.work.generate (send3->hash ()))
.build_shared ();

// Inactive votes
std::vector<nano::block_hash> hashes{ open1->hash (), open2->hash (), send4->hash () };
auto vote1 (std::make_shared<nano::vote> (key1.pub, key1.prv, 0, 0, hashes));
auto vote1 = nano::test::make_vote (key1, { open1, open2, send4 });
node.vote_processor.vote (vote1, std::make_shared<nano::transport::inproc::channel> (node, node));
ASSERT_TIMELY (5s, node.inactive_vote_cache.cache_size () == 3);
ASSERT_TIMELY (5s, node.vote_cache.size () == 3);
ASSERT_TRUE (node.active.empty ());
ASSERT_EQ (1, node.ledger.cache.cemented_count);

// 2 votes are required to start election (dev network)
auto vote2 (std::make_shared<nano::vote> (key2.pub, key2.prv, 0, 0, hashes));
auto vote2 = nano::test::make_vote (key2, { open1, open2, send4 });
node.vote_processor.vote (vote2, std::make_shared<nano::transport::inproc::channel> (node, node));
// Only open1 & open2 blocks elections should start (send4 is missing previous block in ledger)
ASSERT_TIMELY (5s, 2 == node.active.size ());
// Only election for send1 should start, other blocks are missing dependencies and don't have enough final weight
ASSERT_TIMELY_EQ (5s, 1, node.active.size ());
ASSERT_TRUE (node.active.active (send1->hash ()));

// Confirm elections with weight quorum
auto vote0 (std::make_shared<nano::vote> (nano::dev::genesis_key.pub, nano::dev::genesis_key.prv, nano::vote::timestamp_max, nano::vote::duration_max, hashes)); // Final vote for confirmation
auto vote0 = nano::test::make_final_vote (nano::dev::genesis_key, { open1, open2, send4 });
node.vote_processor.vote (vote0, std::make_shared<nano::transport::inproc::channel> (node, node));
ASSERT_TIMELY (5s, node.active.empty ());
ASSERT_TIMELY_EQ (5s, 0, node.active.size ());
ASSERT_TIMELY (5s, 5 == node.ledger.cache.cemented_count);
ASSERT_TRUE (nano::test::confirmed (node, { send1, send2, open1, open2 }));

// A late block arrival also checks the inactive votes cache
ASSERT_TRUE (node.active.empty ());
auto send4_cache (node.inactive_vote_cache.find (send4->hash ()));
auto send4_cache (node.vote_cache.find (send4->hash ()));
ASSERT_TRUE (send4_cache);
ASSERT_EQ (3, send4_cache->voters.size ());
ASSERT_EQ (3, send4_cache->voters ().size ());
node.process_active (send3);
// An election is started for send6 but does not
ASSERT_FALSE (node.block_confirmed_or_being_confirmed (send3->hash ()));
Expand Down Expand Up @@ -960,8 +965,8 @@ TEST (active_transactions, fork_replacement_tally)
node1.vote_processor.vote (vote, std::make_shared<nano::transport::inproc::channel> (node1, node1));
node1.vote_processor.flush ();
// ensure vote arrives before the block
ASSERT_TIMELY (5s, node1.inactive_vote_cache.find (send_last->hash ()));
ASSERT_TIMELY (5s, 1 == node1.inactive_vote_cache.find (send_last->hash ())->size ());
ASSERT_TIMELY (5s, node1.vote_cache.find (send_last->hash ()));
ASSERT_TIMELY (5s, 1 == node1.vote_cache.find (send_last->hash ())->size ());
node1.network.publish_filter.clear ();
node2.network.flood_block (send_last);
ASSERT_TIMELY (5s, node1.stats.count (nano::stat::type::message, nano::stat::detail::publish, nano::stat::dir::in) > 1);
Expand Down Expand Up @@ -1427,7 +1432,7 @@ TEST (active_transactions, limit_vote_hinted_elections)

// Setup representatives
// Enough weight to trigger election hinting but not enough to confirm block on its own
const auto amount = ((node.online_reps.trended () / 100) * node.config.election_hint_weight_percent) + 1000 * nano::Gxrb_ratio;
const auto amount = ((node.online_reps.trended () / 100) * node.config.hinted_scheduler.hinting_threshold_percent) + 1000 * nano::Gxrb_ratio;
nano::keypair rep1 = nano::test::setup_rep (system, node, amount / 2);
nano::keypair rep2 = nano::test::setup_rep (system, node, amount / 2);

Expand All @@ -1444,7 +1449,7 @@ TEST (active_transactions, limit_vote_hinted_elections)
auto vote1 = nano::test::make_vote (rep1, { open0, open1 });
node.vote_processor.vote (vote1, nano::test::fake_channel (node));
// Ensure new inactive vote cache entries were created
ASSERT_TIMELY (5s, node.inactive_vote_cache.cache_size () == 2);
ASSERT_TIMELY (5s, node.vote_cache.size () == 2);
// And no elections are getting started yet
ASSERT_ALWAYS (1s, node.active.empty ());
// And nothing got confirmed yet
Expand Down Expand Up @@ -1517,7 +1522,7 @@ TEST (active_transactions, allow_limited_overflow)
{
// Non-final vote, so it stays in the AEC without getting confirmed
auto vote = nano::test::make_vote (nano::dev::genesis_key, { block });
node.inactive_vote_cache.vote (block->hash (), vote);
node.vote_cache.vote (block->hash (), vote);
}

// Ensure active elections overfill AEC only up to normal + hinted limit
Expand Down Expand Up @@ -1555,7 +1560,7 @@ TEST (active_transactions, allow_limited_overflow_adapt)
{
// Non-final vote, so it stays in the AEC without getting confirmed
auto vote = nano::test::make_vote (nano::dev::genesis_key, { block });
node.inactive_vote_cache.vote (block->hash (), vote);
node.vote_cache.vote (block->hash (), vote);
}

// Ensure hinted election amount is bounded by hinted limit
Expand Down
56 changes: 23 additions & 33 deletions nano/core_test/toml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ TEST (toml, daemon_config_deserialize_defaults)
ASSERT_EQ (conf.node.secondary_work_peers, defaults.node.secondary_work_peers);
ASSERT_EQ (conf.node.online_weight_minimum, defaults.node.online_weight_minimum);
ASSERT_EQ (conf.node.rep_crawler_weight_minimum, defaults.node.rep_crawler_weight_minimum);
ASSERT_EQ (conf.node.election_hint_weight_percent, defaults.node.election_hint_weight_percent);
ASSERT_EQ (conf.node.password_fanout, defaults.node.password_fanout);
ASSERT_EQ (conf.node.peering_port, defaults.node.peering_port);
ASSERT_EQ (conf.node.pow_sleep_interval, defaults.node.pow_sleep_interval);
Expand Down Expand Up @@ -272,6 +271,13 @@ TEST (toml, daemon_config_deserialize_defaults)
ASSERT_EQ (conf.node.optimistic_scheduler.enabled, defaults.node.optimistic_scheduler.enabled);
ASSERT_EQ (conf.node.optimistic_scheduler.gap_threshold, defaults.node.optimistic_scheduler.gap_threshold);
ASSERT_EQ (conf.node.optimistic_scheduler.max_size, defaults.node.optimistic_scheduler.max_size);

ASSERT_EQ (conf.node.hinted_scheduler.hinting_threshold_percent, defaults.node.hinted_scheduler.hinting_threshold_percent);
ASSERT_EQ (conf.node.hinted_scheduler.check_interval.count (), defaults.node.hinted_scheduler.check_interval.count ());
ASSERT_EQ (conf.node.hinted_scheduler.block_cooldown.count (), defaults.node.hinted_scheduler.block_cooldown.count ());

ASSERT_EQ (conf.node.vote_cache.max_size, defaults.node.vote_cache.max_size);
ASSERT_EQ (conf.node.vote_cache.max_voters, defaults.node.vote_cache.max_voters);
}

TEST (toml, optional_child)
Expand Down Expand Up @@ -425,7 +431,6 @@ TEST (toml, daemon_config_deserialize_no_defaults)
background_threads = 999
online_weight_minimum = "999"
rep_crawler_weight_minimum = "999"
election_hint_weight_percent = 19
password_fanout = 999
peering_port = 999
pow_sleep_interval= 999
Expand Down Expand Up @@ -534,6 +539,11 @@ TEST (toml, daemon_config_deserialize_no_defaults)
gap_threshold = 999
max_size = 999
[node.hinted_scheduler]
hinting_threshold = 99
check_interval = 999
block_cooldown = 999
[node.rocksdb]
enable = true
memory_multiplier = 3
Expand All @@ -544,6 +554,10 @@ TEST (toml, daemon_config_deserialize_no_defaults)
max_pruning_age = 999
max_pruning_depth = 999
[node.vote_cache]
max_size = 999
max_voters = 999
[opencl]
device = 999
enable = true
Expand Down Expand Up @@ -606,7 +620,6 @@ TEST (toml, daemon_config_deserialize_no_defaults)
ASSERT_NE (conf.node.max_pruning_depth, defaults.node.max_pruning_depth);
ASSERT_NE (conf.node.online_weight_minimum, defaults.node.online_weight_minimum);
ASSERT_NE (conf.node.rep_crawler_weight_minimum, defaults.node.rep_crawler_weight_minimum);
ASSERT_NE (conf.node.election_hint_weight_percent, defaults.node.election_hint_weight_percent);
ASSERT_NE (conf.node.password_fanout, defaults.node.password_fanout);
ASSERT_NE (conf.node.peering_port, defaults.node.peering_port);
ASSERT_NE (conf.node.pow_sleep_interval, defaults.node.pow_sleep_interval);
Expand Down Expand Up @@ -703,6 +716,13 @@ TEST (toml, daemon_config_deserialize_no_defaults)
ASSERT_NE (conf.node.optimistic_scheduler.enabled, defaults.node.optimistic_scheduler.enabled);
ASSERT_NE (conf.node.optimistic_scheduler.gap_threshold, defaults.node.optimistic_scheduler.gap_threshold);
ASSERT_NE (conf.node.optimistic_scheduler.max_size, defaults.node.optimistic_scheduler.max_size);

ASSERT_NE (conf.node.hinted_scheduler.hinting_threshold_percent, defaults.node.hinted_scheduler.hinting_threshold_percent);
ASSERT_NE (conf.node.hinted_scheduler.check_interval.count (), defaults.node.hinted_scheduler.check_interval.count ());
ASSERT_NE (conf.node.hinted_scheduler.block_cooldown.count (), defaults.node.hinted_scheduler.block_cooldown.count ());

ASSERT_NE (conf.node.vote_cache.max_size, defaults.node.vote_cache.max_size);
ASSERT_NE (conf.node.vote_cache.max_voters, defaults.node.vote_cache.max_voters);
}

/** There should be no required values **/
Expand Down Expand Up @@ -835,36 +855,6 @@ TEST (toml, daemon_config_deserialize_errors)
ASSERT_EQ (conf.node.frontiers_confirmation, nano::frontiers_confirmation_mode::invalid);
}

{
std::stringstream ss;
ss << R"toml(
[node]
election_hint_weight_percent = 4
)toml";

nano::tomlconfig toml;
toml.read (ss);
nano::daemon_config conf;
conf.deserialize_toml (toml);

ASSERT_EQ (toml.get_error ().get_message (), "election_hint_weight_percent must be a number between 5 and 50");
}

{
std::stringstream ss;
ss << R"toml(
[node]
election_hint_weight_percent = 51
)toml";

nano::tomlconfig toml;
toml.read (ss);
nano::daemon_config conf;
conf.deserialize_toml (toml);

ASSERT_EQ (toml.get_error ().get_message (), "election_hint_weight_percent must be a number between 5 and 50");
}

{
std::stringstream ss;
ss << R"toml(
Expand Down
Loading

0 comments on commit 5cd0355

Please sign in to comment.