Skip to content

Commit

Permalink
Ascending bootstrap dependency resolution (#4692)
Browse files Browse the repository at this point in the history
* Dependency walking

* Parallel database scan

* Stats

* Throttling & backoff

* Dependency account scanning

* Sync dependencies

* Track source when throttling

* Count tags

* Priorities backoff

Co-authored-by: gr0vity-dev <[email protected]>

* Timestamps

* Avoid reprocessing old blocks

Co-authored-by: gr0vity-dev <[email protected]>

* Max tags limit

* Handle `gap_previous`

Co-authored-by: gr0vity-dev <[email protected]>

* Check timestamp

* Tune initial priority

Co-authored-by: gr0vity-dev <[email protected]>

* Fix config

* Verify response

* Use filters

* Remove random sampling

Co-authored-by: gr0vity-dev <[email protected]>

* Backoff adjustments

* Insert genesis on start

Co-authored-by: gr0vity-dev <[email protected]>

* Fix timestamp check performance

Co-authored-by: gr0vity-dev <[email protected]>

* Adjust throttle size computation

* Config improvements

* Fix compilation

* Extend test timeout

---------

Co-authored-by: gr0vity-dev <[email protected]>
  • Loading branch information
2 people authored and clemahieu committed Aug 6, 2024
1 parent ec15680 commit 390b83f
Show file tree
Hide file tree
Showing 23 changed files with 949 additions and 387 deletions.
74 changes: 27 additions & 47 deletions nano/core_test/bootstrap_ascending.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ TEST (account_sets, construction)
nano::test::system system;
auto store = nano::make_store (system.logger, nano::unique_path (), nano::dev::constants);
ASSERT_FALSE (store->init_error ());
nano::bootstrap_ascending::account_sets sets{ system.stats };
nano::account_sets_config config;
nano::bootstrap_ascending::account_sets sets{ config, system.stats };
}

TEST (account_sets, empty_blocked)
Expand All @@ -40,7 +41,8 @@ TEST (account_sets, empty_blocked)
nano::account account{ 1 };
auto store = nano::make_store (system.logger, nano::unique_path (), nano::dev::constants);
ASSERT_FALSE (store->init_error ());
nano::bootstrap_ascending::account_sets sets{ system.stats };
nano::account_sets_config config;
nano::bootstrap_ascending::account_sets sets{ config, system.stats };
ASSERT_FALSE (sets.blocked (account));
}

Expand All @@ -51,7 +53,8 @@ TEST (account_sets, block)
nano::account account{ 1 };
auto store = nano::make_store (system.logger, nano::unique_path (), nano::dev::constants);
ASSERT_FALSE (store->init_error ());
nano::bootstrap_ascending::account_sets sets{ system.stats };
nano::account_sets_config config;
nano::bootstrap_ascending::account_sets sets{ config, system.stats };
sets.block (account, random_hash ());
ASSERT_TRUE (sets.blocked (account));
}
Expand All @@ -63,7 +66,8 @@ TEST (account_sets, unblock)
nano::account account{ 1 };
auto store = nano::make_store (system.logger, nano::unique_path (), nano::dev::constants);
ASSERT_FALSE (store->init_error ());
nano::bootstrap_ascending::account_sets sets{ system.stats };
nano::account_sets_config config;
nano::bootstrap_ascending::account_sets sets{ config, system.stats };
auto hash = random_hash ();
sets.block (account, hash);
sets.unblock (account, hash);
Expand All @@ -77,8 +81,9 @@ TEST (account_sets, priority_base)
nano::account account{ 1 };
auto store = nano::make_store (system.logger, nano::unique_path (), nano::dev::constants);
ASSERT_FALSE (store->init_error ());
nano::bootstrap_ascending::account_sets sets{ system.stats };
ASSERT_EQ (1.0f, sets.priority (account));
nano::account_sets_config config;
nano::bootstrap_ascending::account_sets sets{ config, system.stats };
ASSERT_EQ (0.0, sets.priority (account));
}

TEST (account_sets, priority_blocked)
Expand All @@ -88,9 +93,10 @@ TEST (account_sets, priority_blocked)
nano::account account{ 1 };
auto store = nano::make_store (system.logger, nano::unique_path (), nano::dev::constants);
ASSERT_FALSE (store->init_error ());
nano::bootstrap_ascending::account_sets sets{ system.stats };
nano::account_sets_config config;
nano::bootstrap_ascending::account_sets sets{ config, system.stats };
sets.block (account, random_hash ());
ASSERT_EQ (0.0f, sets.priority (account));
ASSERT_EQ (0.0, sets.priority (account));
}

// When account is unblocked, check that it retains it former priority
Expand All @@ -101,15 +107,16 @@ TEST (account_sets, priority_unblock_keep)
nano::account account{ 1 };
auto store = nano::make_store (system.logger, nano::unique_path (), nano::dev::constants);
ASSERT_FALSE (store->init_error ());
nano::bootstrap_ascending::account_sets sets{ system.stats };
nano::account_sets_config config;
nano::bootstrap_ascending::account_sets sets{ config, system.stats };
sets.priority_up (account);
sets.priority_up (account);
ASSERT_EQ (sets.priority (account), nano::bootstrap_ascending::account_sets::priority_initial * nano::bootstrap_ascending::account_sets::priority_increase);
ASSERT_EQ (sets.priority (account), nano::bootstrap_ascending::account_sets::priority_initial + nano::bootstrap_ascending::account_sets::priority_increase);
auto hash = random_hash ();
sets.block (account, hash);
ASSERT_EQ (0.0f, sets.priority (account));
ASSERT_EQ (0.0, sets.priority (account));
sets.unblock (account, hash);
ASSERT_EQ (sets.priority (account), nano::bootstrap_ascending::account_sets::priority_initial * nano::bootstrap_ascending::account_sets::priority_increase);
ASSERT_EQ (sets.priority (account), nano::bootstrap_ascending::account_sets::priority_initial + nano::bootstrap_ascending::account_sets::priority_increase);
}

TEST (account_sets, priority_up_down)
Expand All @@ -119,24 +126,25 @@ TEST (account_sets, priority_up_down)
nano::account account{ 1 };
auto store = nano::make_store (system.logger, nano::unique_path (), nano::dev::constants);
ASSERT_FALSE (store->init_error ());
nano::bootstrap_ascending::account_sets sets{ system.stats };
nano::account_sets_config config;
nano::bootstrap_ascending::account_sets sets{ config, system.stats };
sets.priority_up (account);
ASSERT_EQ (sets.priority (account), nano::bootstrap_ascending::account_sets::priority_initial);
sets.priority_down (account);
ASSERT_EQ (sets.priority (account), nano::bootstrap_ascending::account_sets::priority_initial - nano::bootstrap_ascending::account_sets::priority_decrease);
ASSERT_EQ (sets.priority (account), nano::bootstrap_ascending::account_sets::priority_initial / nano::bootstrap_ascending::account_sets::priority_divide);
}

// Check that priority downward saturates to 1.0f
TEST (account_sets, priority_down_sat)
{
nano::test::system system;

nano::account account{ 1 };
auto store = nano::make_store (system.logger, nano::unique_path (), nano::dev::constants);
ASSERT_FALSE (store->init_error ());
nano::bootstrap_ascending::account_sets sets{ system.stats };
nano::account_sets_config config;
nano::bootstrap_ascending::account_sets sets{ config, system.stats };
sets.priority_down (account);
ASSERT_EQ (1.0f, sets.priority (account));
ASSERT_EQ (0.0, sets.priority (account));
}

// Ensure priority value is bounded
Expand All @@ -147,7 +155,8 @@ TEST (account_sets, saturate_priority)
nano::account account{ 1 };
auto store = nano::make_store (system.logger, nano::unique_path (), nano::dev::constants);
ASSERT_FALSE (store->init_error ());
nano::bootstrap_ascending::account_sets sets{ system.stats };
nano::account_sets_config config;
nano::bootstrap_ascending::account_sets sets{ config, system.stats };
for (int n = 0; n < 1000; ++n)
{
sets.priority_up (account);
Expand Down Expand Up @@ -257,32 +266,3 @@ TEST (bootstrap_ascending, trace_base)
// std::cerr << "node1: " << node1.network.endpoint () << std::endl;
ASSERT_TIMELY (10s, node1.block (receive1->hash ()) != nullptr);
}

TEST (bootstrap_ascending, config_serialization)
{
nano::bootstrap_ascending_config config1;
config1.requests_limit = 0x101;
config1.database_requests_limit = 0x102;
config1.pull_count = 0x103;
config1.request_timeout = 0x104ms;
config1.throttle_coefficient = 0x105;
config1.throttle_wait = 0x106ms;
config1.block_wait_count = 0x107;
nano::tomlconfig toml1;
ASSERT_FALSE (config1.serialize (toml1));
std::stringstream stream1;
toml1.write (stream1);
auto string = stream1.str ();
std::stringstream stream2{ string };
nano::tomlconfig toml2;
toml2.read (stream2);
nano::bootstrap_ascending_config config2;
ASSERT_FALSE (config2.deserialize (toml2));
ASSERT_EQ (config1.requests_limit, config2.requests_limit);
ASSERT_EQ (config1.database_requests_limit, config2.database_requests_limit);
ASSERT_EQ (config1.pull_count, config2.pull_count);
ASSERT_EQ (config1.request_timeout, config2.request_timeout);
ASSERT_EQ (config1.throttle_coefficient, config2.throttle_coefficient);
ASSERT_EQ (config1.throttle_wait, config2.throttle_wait);
ASSERT_EQ (config1.block_wait_count, config2.block_wait_count);
}
2 changes: 1 addition & 1 deletion nano/core_test/bootstrap_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class responses_helper final
/**
* Checks if both lists contain the same blocks, with `blocks_b` skipped by `skip` elements
*/
bool compare_blocks (std::vector<std::shared_ptr<nano::block>> blocks_a, std::vector<std::shared_ptr<nano::block>> blocks_b, int skip = 0)
bool compare_blocks (auto const & blocks_a, auto const & blocks_b, int skip = 0)
{
debug_assert (blocks_b.size () >= blocks_a.size () + skip);

Expand Down
2 changes: 1 addition & 1 deletion nano/core_test/rep_crawler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ TEST (rep_crawler, two_reps_one_node)
system.wallet (0)->insert_adhoc (nano::dev::genesis_key.prv);
system.wallet (0)->insert_adhoc (second_rep.prv);

ASSERT_TIMELY_EQ (5s, node2.rep_crawler.representative_count (), 2);
ASSERT_TIMELY_EQ (15s, node2.rep_crawler.representative_count (), 2);
auto reps = node2.rep_crawler.representatives ();
ASSERT_EQ (2, reps.size ());

Expand Down
40 changes: 39 additions & 1 deletion nano/core_test/toml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ TEST (toml, daemon_config_deserialize_defaults)
std::stringstream ss;
ss << R"toml(
[node]
[node.bootstrap_ascending]
[node.bootstrap_server]
[node.block_processor]
[node.diagnostics.txn_tracking]
[node.httpcallback]
Expand All @@ -128,7 +130,6 @@ TEST (toml, daemon_config_deserialize_defaults)
[node.websocket]
[node.lmdb]
[node.rocksdb]
[node.bootstrap_server]
[opencl]
[rpc]
[rpc.child_process]
Expand Down Expand Up @@ -265,6 +266,18 @@ TEST (toml, daemon_config_deserialize_defaults)
ASSERT_EQ (conf.node.vote_processor.threads, defaults.node.vote_processor.threads);
ASSERT_EQ (conf.node.vote_processor.batch_size, defaults.node.vote_processor.batch_size);

ASSERT_EQ (conf.node.bootstrap_ascending.enable, defaults.node.bootstrap_ascending.enable);
ASSERT_EQ (conf.node.bootstrap_ascending.enable_database_scan, defaults.node.bootstrap_ascending.enable_database_scan);
ASSERT_EQ (conf.node.bootstrap_ascending.enable_dependency_walker, defaults.node.bootstrap_ascending.enable_dependency_walker);
ASSERT_EQ (conf.node.bootstrap_ascending.requests_limit, defaults.node.bootstrap_ascending.requests_limit);
ASSERT_EQ (conf.node.bootstrap_ascending.database_rate_limit, defaults.node.bootstrap_ascending.database_rate_limit);
ASSERT_EQ (conf.node.bootstrap_ascending.pull_count, defaults.node.bootstrap_ascending.pull_count);
ASSERT_EQ (conf.node.bootstrap_ascending.request_timeout, defaults.node.bootstrap_ascending.request_timeout);
ASSERT_EQ (conf.node.bootstrap_ascending.throttle_coefficient, defaults.node.bootstrap_ascending.throttle_coefficient);
ASSERT_EQ (conf.node.bootstrap_ascending.throttle_wait, defaults.node.bootstrap_ascending.throttle_wait);
ASSERT_EQ (conf.node.bootstrap_ascending.block_wait_count, defaults.node.bootstrap_ascending.block_wait_count);
ASSERT_EQ (conf.node.bootstrap_ascending.max_requests, defaults.node.bootstrap_ascending.max_requests);

ASSERT_EQ (conf.node.bootstrap_server.max_queue, defaults.node.bootstrap_server.max_queue);
ASSERT_EQ (conf.node.bootstrap_server.threads, defaults.node.bootstrap_server.threads);
ASSERT_EQ (conf.node.bootstrap_server.batch_size, defaults.node.bootstrap_server.batch_size);
Expand Down Expand Up @@ -576,6 +589,19 @@ TEST (toml, daemon_config_deserialize_no_defaults)
threads = 999
batch_size = 999
[node.bootstrap_ascending]
enable = false
enable_database_scan = false
enable_dependency_walker = false
requests_limit = 999
database_rate_limit = 999
pull_count = 999
request_timeout = 999
throttle_coefficient = 999
throttle_wait = 999
block_wait_count = 999
max_requests = 999
[node.bootstrap_server]
max_queue = 999
threads = 999
Expand Down Expand Up @@ -740,6 +766,18 @@ TEST (toml, daemon_config_deserialize_no_defaults)
ASSERT_NE (conf.node.vote_processor.threads, defaults.node.vote_processor.threads);
ASSERT_NE (conf.node.vote_processor.batch_size, defaults.node.vote_processor.batch_size);

ASSERT_NE (conf.node.bootstrap_ascending.enable, defaults.node.bootstrap_ascending.enable);
ASSERT_NE (conf.node.bootstrap_ascending.enable_database_scan, defaults.node.bootstrap_ascending.enable_database_scan);
ASSERT_NE (conf.node.bootstrap_ascending.enable_dependency_walker, defaults.node.bootstrap_ascending.enable_dependency_walker);
ASSERT_NE (conf.node.bootstrap_ascending.requests_limit, defaults.node.bootstrap_ascending.requests_limit);
ASSERT_NE (conf.node.bootstrap_ascending.database_rate_limit, defaults.node.bootstrap_ascending.database_rate_limit);
ASSERT_NE (conf.node.bootstrap_ascending.pull_count, defaults.node.bootstrap_ascending.pull_count);
ASSERT_NE (conf.node.bootstrap_ascending.request_timeout, defaults.node.bootstrap_ascending.request_timeout);
ASSERT_NE (conf.node.bootstrap_ascending.throttle_coefficient, defaults.node.bootstrap_ascending.throttle_coefficient);
ASSERT_NE (conf.node.bootstrap_ascending.throttle_wait, defaults.node.bootstrap_ascending.throttle_wait);
ASSERT_NE (conf.node.bootstrap_ascending.block_wait_count, defaults.node.bootstrap_ascending.block_wait_count);
ASSERT_NE (conf.node.bootstrap_ascending.max_requests, defaults.node.bootstrap_ascending.max_requests);

ASSERT_NE (conf.node.bootstrap_server.max_queue, defaults.node.bootstrap_server.max_queue);
ASSERT_NE (conf.node.bootstrap_server.threads, defaults.node.bootstrap_server.threads);
ASSERT_NE (conf.node.bootstrap_server.batch_size, defaults.node.bootstrap_server.batch_size);
Expand Down
39 changes: 33 additions & 6 deletions nano/lib/stats_enums.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ enum class type
blockprocessor_source,
blockprocessor_result,
blockprocessor_overfill,
bootstrap_ascending,
bootstrap_ascending_accounts,
bootstrap_ascending_verify,
bootstrap_ascending_process,
bootstrap_ascending_request,
bootstrap_ascending_reply,
bootstrap_ascending_next,
bootstrap_server,
bootstrap_server_request,
bootstrap_server_overfill,
Expand Down Expand Up @@ -87,9 +94,6 @@ enum class type
message_processor_overfill,
message_processor_type,

bootstrap_ascending,
bootstrap_ascending_accounts,

_last // Must be the last enum
};

Expand Down Expand Up @@ -129,6 +133,7 @@ enum class detail
unconfirmed,
cemented,
cooldown,
empty,

// processing queue
queue,
Expand Down Expand Up @@ -421,27 +426,44 @@ enum class detail
track,
timeout,
nothing_new,
account_info_empty,
loop_database,
loop_dependencies,
duplicate_request,
invalid_response_type,
timestamp_reset,

// bootstrap ascending accounts
prioritize,
prioritize_failed,
block,
unblock,
unblock_failed,
dependency_update,
dependency_update_failed,

next_none,
next_priority,
next_database,
next_none,
next_blocking,
next_dependency,

blocking_insert,
blocking_erase_overflow,
priority_insert,
priority_erase_threshold,
priority_erase_block,
priority_erase_by_threshold,
priority_erase_by_blocking,
priority_erase_overflow,
deprioritize,
deprioritize_failed,
sync_dependencies,

request_blocks,
request_account_info,

// active
started_hinted,
started_optimistic,
// rep_crawler
channel_dead,
query_target_failed,
Expand Down Expand Up @@ -489,6 +511,11 @@ enum class detail
activate_success,
cancel_lowest,

// query_type
blocks_by_hash,
blocks_by_account,
account_info_by_hash,

_last // Must be the last enum
};

Expand Down
2 changes: 1 addition & 1 deletion nano/lib/tomlconfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ class tomlconfig : public nano::configbase
template <typename Duration>
tomlconfig & get_duration (std::string const & key, Duration & target)
{
uint64_t value;
uint64_t value = target.count ();
get (key, value);
target = Duration{ value };
return *this;
Expand Down
13 changes: 9 additions & 4 deletions nano/node/blockprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
* block_processor::context
*/

nano::block_processor::context::context (std::shared_ptr<nano::block> block, nano::block_source source_a) :
nano::block_processor::context::context (std::shared_ptr<nano::block> block, nano::block_source source_a, callback_t callback_a) :
block{ std::move (block) },
source{ source_a }
source{ source_a },
callback{ std::move (callback_a) }
{
debug_assert (source != nano::block_source::unknown);
}
Expand Down Expand Up @@ -121,7 +122,7 @@ std::size_t nano::block_processor::size (nano::block_source source) const
return queue.size ({ source });
}

bool nano::block_processor::add (std::shared_ptr<nano::block> const & block, block_source const source, std::shared_ptr<nano::transport::channel> const & channel)
bool nano::block_processor::add (std::shared_ptr<nano::block> const & block, block_source const source, std::shared_ptr<nano::transport::channel> const & channel, std::function<void (nano::block_status)> callback)
{
if (node.network_params.work.validate_entry (*block)) // true => error
{
Expand All @@ -135,7 +136,7 @@ bool nano::block_processor::add (std::shared_ptr<nano::block> const & block, blo
to_string (source),
channel ? channel->to_string () : "<unknown>"); // TODO: Lazy eval

return add_impl (context{ block, source }, channel);
return add_impl (context{ block, source, std::move (callback) }, channel);
}

std::optional<nano::block_status> nano::block_processor::add_blocking (std::shared_ptr<nano::block> const & block, block_source const source)
Expand Down Expand Up @@ -247,6 +248,10 @@ void nano::block_processor::run ()
// Set results for futures when not holding the lock
for (auto & [result, context] : processed)
{
if (context.callback)
{
context.callback (result);
}
context.set_result (result);
}

Expand Down
Loading

0 comments on commit 390b83f

Please sign in to comment.