Remove bootstrap restarting code (#3149)
* This removes bootstrap restarting code as it is ineffective and can cause unnecessary restarting of the bootstrap process. * bulk.genesis_pruning test improvements * Fix TSAN warning in test active_transactions.confirm_frontier * Remove now unused variables and options Co-authored-by: Sergey Kroshnin <sergiysw@gmail.com>
This commit is contained in:
parent
8cc5f39fd8
commit
9112636c22
10 changed files with 15 additions and 399 deletions
|
@ -88,17 +88,21 @@ TEST (active_transactions, confirm_frontier)
|
|||
}
|
||||
|
||||
nano::genesis genesis;
|
||||
auto send = nano::send_block_builder ()
|
||||
nano::state_block_builder builder;
|
||||
auto send = builder
|
||||
.account (nano::dev_genesis_key.pub)
|
||||
.previous (genesis.hash ())
|
||||
.destination (nano::public_key ())
|
||||
.representative (nano::dev_genesis_key.pub)
|
||||
.balance (nano::genesis_amount - 100)
|
||||
.link (nano::public_key ())
|
||||
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
|
||||
.work (*system.work.generate (genesis.hash ()))
|
||||
.build_shared ();
|
||||
auto send_copy = builder.make_block ().from (*send).build_shared ();
|
||||
ASSERT_EQ (nano::process_result::progress, node1.process (*send).code);
|
||||
node1.confirmation_height_processor.add (send);
|
||||
ASSERT_TIMELY (5s, node1.ledger.block_confirmed (node1.store.tx_begin_read (), send->hash ()));
|
||||
ASSERT_EQ (nano::process_result::progress, node2.process (*send).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node2.process (*send_copy).code);
|
||||
ASSERT_TIMELY (5s, !node2.active.empty ());
|
||||
// Save election to check request count afterwards
|
||||
auto election2 = node2.active.election (send->qualified_root ());
|
||||
|
|
|
@ -354,157 +354,6 @@ TEST (bootstrap_processor, DISABLED_pull_requeue_network_error)
|
|||
ASSERT_EQ (0, node1->stats.count (nano::stat::type::bootstrap, nano::stat::detail::bulk_pull_failed_account, nano::stat::dir::in)); // Requeue is not increasing failed attempts
|
||||
}
|
||||
|
||||
TEST (bootstrap_processor, frontiers_unconfirmed)
|
||||
{
|
||||
nano::system system;
|
||||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
|
||||
node_config.tcp_io_timeout = std::chrono::seconds (2);
|
||||
nano::node_flags node_flags;
|
||||
node_flags.disable_bootstrap_bulk_pull_server = true;
|
||||
node_flags.disable_bootstrap_bulk_push_client = true;
|
||||
node_flags.disable_legacy_bootstrap = true;
|
||||
node_flags.disable_lazy_bootstrap = true;
|
||||
node_flags.disable_wallet_bootstrap = true;
|
||||
node_flags.disable_rep_crawler = true;
|
||||
auto node1 = system.add_node (node_config, node_flags);
|
||||
nano::genesis genesis;
|
||||
nano::keypair key1, key2;
|
||||
// Generating invalid chain
|
||||
auto send1 (std::make_shared<nano::state_block> (nano::dev_genesis_key.pub, genesis.hash (), nano::dev_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, key1.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (genesis.hash ())));
|
||||
ASSERT_EQ (nano::process_result::progress, node1->process (*send1).code);
|
||||
auto send2 (std::make_shared<nano::state_block> (nano::dev_genesis_key.pub, send1->hash (), nano::dev_genesis_key.pub, nano::genesis_amount - 2 * nano::Gxrb_ratio, key2.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (send1->hash ())));
|
||||
ASSERT_EQ (nano::process_result::progress, node1->process (*send2).code);
|
||||
auto open1 (std::make_shared<nano::state_block> (key1.pub, 0, key1.pub, nano::Gxrb_ratio, send1->hash (), key1.prv, key1.pub, *system.work.generate (key1.pub)));
|
||||
ASSERT_EQ (nano::process_result::progress, node1->process (*open1).code);
|
||||
auto open2 (std::make_shared<nano::state_block> (key2.pub, 0, key2.pub, nano::Gxrb_ratio, send2->hash (), key2.prv, key2.pub, *system.work.generate (key2.pub)));
|
||||
ASSERT_EQ (nano::process_result::progress, node1->process (*open2).code);
|
||||
|
||||
node_config.peering_port = nano::get_available_port ();
|
||||
node_flags.disable_bootstrap_bulk_pull_server = false;
|
||||
node_flags.disable_rep_crawler = false;
|
||||
auto node2 = system.add_node (node_config, node_flags);
|
||||
// Generating valid chain
|
||||
auto send3 (std::make_shared<nano::state_block> (nano::dev_genesis_key.pub, genesis.hash (), nano::dev_genesis_key.pub, nano::genesis_amount - nano::xrb_ratio, key1.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (genesis.hash ())));
|
||||
ASSERT_EQ (nano::process_result::progress, node2->process (*send3).code);
|
||||
auto open3 (std::make_shared<nano::state_block> (key1.pub, 0, key1.pub, nano::xrb_ratio, send3->hash (), key1.prv, key1.pub, *system.work.generate (key1.pub)));
|
||||
ASSERT_EQ (nano::process_result::progress, node2->process (*open3).code);
|
||||
system.wallet (1)->insert_adhoc (nano::dev_genesis_key.prv);
|
||||
|
||||
// Ensure node2 can generate votes
|
||||
node2->block_confirm (send3);
|
||||
ASSERT_TIMELY (10s, node2->ledger.cache.cemented_count == 3 && node2->confirmation_height_processor.current ().is_zero ());
|
||||
|
||||
// Test node to restart bootstrap
|
||||
node_config.peering_port = nano::get_available_port ();
|
||||
node_flags.disable_legacy_bootstrap = false;
|
||||
auto node3 = system.add_node (node_config, node_flags);
|
||||
ASSERT_TIMELY (5s, node3->rep_crawler.representative_count () != 0);
|
||||
//Add single excluded peers record (2 records are required to drop peer)
|
||||
node3->network.excluded_peers.add (nano::transport::map_endpoint_to_tcp (node1->network.endpoint ()), 0);
|
||||
ASSERT_FALSE (node3->network.excluded_peers.check (nano::transport::map_endpoint_to_tcp (node1->network.endpoint ())));
|
||||
node3->bootstrap_initiator.bootstrap (node1->network.endpoint (), false);
|
||||
ASSERT_TIMELY (15s, !node3->bootstrap_initiator.in_progress ());
|
||||
ASSERT_FALSE (node3->ledger.block_exists (send1->hash ()));
|
||||
ASSERT_FALSE (node3->ledger.block_exists (open1->hash ()));
|
||||
ASSERT_EQ (1, node3->stats.count (nano::stat::type::bootstrap, nano::stat::detail::frontier_confirmation_failed, nano::stat::dir::in)); // failed request from node1
|
||||
ASSERT_FALSE (node3->network.excluded_peers.check (nano::transport::map_endpoint_to_tcp (node1->network.endpoint ()))); // Banning from bootstrap is disabled
|
||||
}
|
||||
|
||||
TEST (bootstrap_processor, frontiers_confirmed)
|
||||
{
|
||||
nano::system system;
|
||||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
|
||||
node_config.tcp_io_timeout = std::chrono::seconds (2);
|
||||
nano::node_flags node_flags;
|
||||
node_flags.disable_bootstrap_bulk_pull_server = true;
|
||||
node_flags.disable_bootstrap_bulk_push_client = true;
|
||||
node_flags.disable_legacy_bootstrap = true;
|
||||
node_flags.disable_lazy_bootstrap = true;
|
||||
node_flags.disable_wallet_bootstrap = true;
|
||||
node_flags.disable_rep_crawler = true;
|
||||
auto node1 = system.add_node (node_config, node_flags);
|
||||
nano::genesis genesis;
|
||||
nano::keypair key1, key2;
|
||||
// Generating valid chain
|
||||
auto send1 (std::make_shared<nano::state_block> (nano::dev_genesis_key.pub, genesis.hash (), nano::dev_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, key1.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (genesis.hash ())));
|
||||
ASSERT_EQ (nano::process_result::progress, node1->process (*send1).code);
|
||||
auto send2 (std::make_shared<nano::state_block> (nano::dev_genesis_key.pub, send1->hash (), nano::dev_genesis_key.pub, nano::genesis_amount - 2 * nano::Gxrb_ratio, key2.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (send1->hash ())));
|
||||
ASSERT_EQ (nano::process_result::progress, node1->process (*send2).code);
|
||||
auto open1 (std::make_shared<nano::state_block> (key1.pub, 0, key1.pub, nano::Gxrb_ratio, send1->hash (), key1.prv, key1.pub, *system.work.generate (key1.pub)));
|
||||
ASSERT_EQ (nano::process_result::progress, node1->process (*open1).code);
|
||||
auto open2 (std::make_shared<nano::state_block> (key2.pub, 0, key2.pub, nano::Gxrb_ratio, send2->hash (), key2.prv, key2.pub, *system.work.generate (key2.pub)));
|
||||
ASSERT_EQ (nano::process_result::progress, node1->process (*open2).code);
|
||||
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
|
||||
|
||||
// Confirm all blocks so node1 is free to generate votes
|
||||
node1->block_confirm (send1);
|
||||
ASSERT_TIMELY (10s, node1->ledger.cache.cemented_count == 5 && node1->confirmation_height_processor.current ().is_zero ());
|
||||
|
||||
// Test node to bootstrap
|
||||
node_config.peering_port = nano::get_available_port ();
|
||||
node_flags.disable_legacy_bootstrap = false;
|
||||
node_flags.disable_rep_crawler = false;
|
||||
auto node2 = system.add_node (node_config, node_flags);
|
||||
ASSERT_TIMELY (5s, node2->rep_crawler.representative_count () != 0);
|
||||
node2->bootstrap_initiator.bootstrap (node1->network.endpoint (), false);
|
||||
ASSERT_TIMELY (10s, node2->bootstrap_initiator.current_attempt () == nullptr || node2->bootstrap_initiator.current_attempt ()->frontiers_confirmed);
|
||||
ASSERT_EQ (1, node2->stats.count (nano::stat::type::bootstrap, nano::stat::detail::frontier_confirmation_successful, nano::stat::dir::in)); // Successful request from node1
|
||||
ASSERT_EQ (0, node2->stats.count (nano::stat::type::bootstrap, nano::stat::detail::frontier_confirmation_failed, nano::stat::dir::in));
|
||||
}
|
||||
|
||||
TEST (bootstrap_processor, frontiers_unconfirmed_threshold)
|
||||
{
|
||||
nano::system system;
|
||||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
|
||||
node_config.tcp_io_timeout = std::chrono::seconds (2);
|
||||
node_config.bootstrap_fraction_numerator = 4;
|
||||
nano::node_flags node_flags;
|
||||
node_flags.disable_bootstrap_bulk_pull_server = true;
|
||||
node_flags.disable_bootstrap_bulk_push_client = true;
|
||||
node_flags.disable_legacy_bootstrap = true;
|
||||
node_flags.disable_lazy_bootstrap = true;
|
||||
node_flags.disable_wallet_bootstrap = true;
|
||||
node_flags.disable_rep_crawler = true;
|
||||
auto node1 = system.add_node (node_config, node_flags);
|
||||
nano::genesis genesis;
|
||||
nano::keypair key1, key2;
|
||||
// Generating invalid chain
|
||||
auto threshold (node1->gap_cache.bootstrap_threshold () + 1);
|
||||
ASSERT_LT (threshold, node1->online_reps.delta ());
|
||||
auto send1 (std::make_shared<nano::state_block> (nano::dev_genesis_key.pub, genesis.hash (), nano::dev_genesis_key.pub, nano::genesis_amount - threshold, key1.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (genesis.hash ())));
|
||||
ASSERT_EQ (nano::process_result::progress, node1->process (*send1).code);
|
||||
auto send2 (std::make_shared<nano::state_block> (nano::dev_genesis_key.pub, send1->hash (), nano::dev_genesis_key.pub, nano::genesis_amount - threshold - nano::Gxrb_ratio, key2.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (send1->hash ())));
|
||||
ASSERT_EQ (nano::process_result::progress, node1->process (*send2).code);
|
||||
auto open1 (std::make_shared<nano::state_block> (key1.pub, 0, key1.pub, threshold, send1->hash (), key1.prv, key1.pub, *system.work.generate (key1.pub)));
|
||||
ASSERT_EQ (nano::process_result::progress, node1->process (*open1).code);
|
||||
auto open2 (std::make_shared<nano::state_block> (key2.pub, 0, key2.pub, nano::Gxrb_ratio, send2->hash (), key2.prv, key2.pub, *system.work.generate (key2.pub)));
|
||||
ASSERT_EQ (nano::process_result::progress, node1->process (*open2).code);
|
||||
system.wallet (0)->insert_adhoc (key1.prv); // Small representative
|
||||
|
||||
// Test node with large representative
|
||||
node_config.peering_port = nano::get_available_port ();
|
||||
auto node2 = system.add_node (node_config, node_flags);
|
||||
system.wallet (1)->insert_adhoc (nano::dev_genesis_key.prv);
|
||||
|
||||
// Test node to bootstrap
|
||||
node_config.peering_port = nano::get_available_port ();
|
||||
node_flags.disable_legacy_bootstrap = false;
|
||||
node_flags.disable_rep_crawler = false;
|
||||
auto node3 = system.add_node (node_config, node_flags);
|
||||
ASSERT_EQ (nano::process_result::progress, node3->process (*send1).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node3->process (*open1).code); // Change known representative weight
|
||||
ASSERT_TIMELY (5s, node3->rep_crawler.representative_count () == 2);
|
||||
node3->bootstrap_initiator.bootstrap (node1->network.endpoint (), false);
|
||||
ASSERT_TIMELY (15s, node3->stats.count (nano::stat::type::bootstrap, nano::stat::detail::frontier_confirmation_failed, nano::stat::dir::in) == 1);
|
||||
ASSERT_FALSE (node3->ledger.block_exists (send2->hash ()));
|
||||
ASSERT_FALSE (node3->ledger.block_exists (open2->hash ()));
|
||||
ASSERT_EQ (1, node3->stats.count (nano::stat::type::bootstrap, nano::stat::detail::frontier_confirmation_failed, nano::stat::dir::in)); // failed confirmation
|
||||
ASSERT_EQ (0, node3->stats.count (nano::stat::type::bootstrap, nano::stat::detail::frontier_confirmation_successful, nano::stat::dir::in));
|
||||
}
|
||||
|
||||
TEST (bootstrap_processor, push_diamond)
|
||||
{
|
||||
nano::system system;
|
||||
|
@ -1494,8 +1343,7 @@ TEST (bulk, genesis_pruning)
|
|||
// Bootstrap with missing blocks for node2
|
||||
node2->bootstrap_initiator.bootstrap (node1->network.endpoint (), false);
|
||||
node2->network.merge_peer (node1->network.endpoint ());
|
||||
// 2 bootstraps including test bootstrap & restart after frontier confirmation failure
|
||||
ASSERT_TIMELY (25s, node2->stats.count (nano::stat::type::bootstrap, nano::stat::detail::initiate, nano::stat::dir::out) >= 2 && !node2->bootstrap_initiator.in_progress ());
|
||||
ASSERT_TIMELY (25s, node2->stats.count (nano::stat::type::bootstrap, nano::stat::detail::initiate, nano::stat::dir::out) >= 1 && !node2->bootstrap_initiator.in_progress ());
|
||||
// node2 still missing blocks
|
||||
ASSERT_EQ (1, node2->ledger.cache.block_count);
|
||||
{
|
||||
|
@ -1509,7 +1357,6 @@ TEST (bulk, genesis_pruning)
|
|||
ASSERT_EQ (3, node2->ledger.cache.block_count);
|
||||
// New bootstrap
|
||||
ASSERT_TIMELY (5s, node2->bootstrap_initiator.connections->connections_count == 0);
|
||||
node2->network.excluded_peers.remove (nano::transport::map_endpoint_to_tcp (node1->network.endpoint ()));
|
||||
node2->bootstrap_initiator.bootstrap (node1->network.endpoint (), false);
|
||||
ASSERT_TIMELY (10s, node2->latest (nano::dev_genesis_key.pub) == node1->latest (nano::dev_genesis_key.pub));
|
||||
ASSERT_EQ (node2->latest (nano::dev_genesis_key.pub), node1->latest (nano::dev_genesis_key.pub));
|
||||
|
|
|
@ -49,7 +49,7 @@ void nano::bootstrap_initiator::bootstrap (bool force, std::string id_a, uint32_
|
|||
}
|
||||
}
|
||||
|
||||
void nano::bootstrap_initiator::bootstrap (nano::endpoint const & endpoint_a, bool add_to_peers, bool frontiers_confirmed, std::string id_a)
|
||||
void nano::bootstrap_initiator::bootstrap (nano::endpoint const & endpoint_a, bool add_to_peers, std::string id_a)
|
||||
{
|
||||
if (add_to_peers)
|
||||
{
|
||||
|
@ -70,15 +70,10 @@ void nano::bootstrap_initiator::bootstrap (nano::endpoint const & endpoint_a, bo
|
|||
auto legacy_attempt (std::make_shared<nano::bootstrap_attempt_legacy> (node.shared (), attempts.incremental++, id_a, std::numeric_limits<uint32_t>::max ()));
|
||||
attempts_list.push_back (legacy_attempt);
|
||||
attempts.add (legacy_attempt);
|
||||
if (frontiers_confirmed)
|
||||
{
|
||||
node.network.excluded_peers.remove (nano::transport::map_endpoint_to_tcp (endpoint_a));
|
||||
}
|
||||
if (!node.network.excluded_peers.check (nano::transport::map_endpoint_to_tcp (endpoint_a)))
|
||||
{
|
||||
connections->add_connection (endpoint_a);
|
||||
}
|
||||
legacy_attempt->frontiers_confirmed = frontiers_confirmed;
|
||||
}
|
||||
condition.notify_all ();
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ class bootstrap_initiator final
|
|||
public:
|
||||
explicit bootstrap_initiator (nano::node &);
|
||||
~bootstrap_initiator ();
|
||||
void bootstrap (nano::endpoint const &, bool add_to_peers = true, bool frontiers_confirmed = false, std::string id_a = "");
|
||||
void bootstrap (nano::endpoint const &, bool add_to_peers = true, std::string id_a = "");
|
||||
void bootstrap (bool force = false, std::string id_a = "", uint32_t const frontiers_age_a = std::numeric_limits<uint32_t>::max ());
|
||||
void bootstrap_lazy (nano::hash_or_account const &, bool force = false, bool confirmed = true, std::string id_a = "");
|
||||
void bootstrap_wallet (std::deque<nano::account> &);
|
||||
|
@ -127,9 +127,6 @@ public:
|
|||
static constexpr double bootstrap_minimum_frontier_blocks_per_sec = 1000.0;
|
||||
static constexpr double bootstrap_minimum_termination_time_sec = 30.0;
|
||||
static constexpr unsigned bootstrap_max_new_connections = 32;
|
||||
static constexpr size_t bootstrap_max_confirm_frontiers = 70;
|
||||
static constexpr double required_frontier_confirmation_ratio = 0.8;
|
||||
static constexpr unsigned frontier_confirmation_blocks_limit = 128 * 1024;
|
||||
static constexpr unsigned requeued_pulls_limit = 256;
|
||||
static constexpr unsigned requeued_pulls_limit_dev = 1;
|
||||
static constexpr unsigned requeued_pulls_processed_blocks_factor = 4096;
|
||||
|
|
|
@ -12,9 +12,6 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
constexpr size_t nano::bootstrap_limits::bootstrap_max_confirm_frontiers;
|
||||
constexpr double nano::bootstrap_limits::required_frontier_confirmation_ratio;
|
||||
constexpr unsigned nano::bootstrap_limits::frontier_confirmation_blocks_limit;
|
||||
constexpr unsigned nano::bootstrap_limits::requeued_pulls_limit;
|
||||
constexpr unsigned nano::bootstrap_limits::requeued_pulls_limit_dev;
|
||||
|
||||
|
@ -116,11 +113,6 @@ std::string nano::bootstrap_attempt::mode_text ()
|
|||
return mode_text;
|
||||
}
|
||||
|
||||
void nano::bootstrap_attempt::restart_condition ()
|
||||
{
|
||||
debug_assert (mode == nano::bootstrap_mode::legacy);
|
||||
}
|
||||
|
||||
void nano::bootstrap_attempt::add_frontier (nano::pull_info const &)
|
||||
{
|
||||
debug_assert (mode == nano::bootstrap_mode::legacy);
|
||||
|
@ -137,11 +129,6 @@ bool nano::bootstrap_attempt::request_bulk_push_target (std::pair<nano::block_ha
|
|||
return true;
|
||||
}
|
||||
|
||||
void nano::bootstrap_attempt::add_recent_pull (nano::block_hash const &)
|
||||
{
|
||||
debug_assert (mode == nano::bootstrap_mode::legacy);
|
||||
}
|
||||
|
||||
bool nano::bootstrap_attempt::process_block (std::shared_ptr<nano::block> const & block_a, nano::account const & known_account_a, uint64_t pull_blocks, nano::bulk_pull::count_t max_blocks, bool block_expected, unsigned retry_limit)
|
||||
{
|
||||
nano::unchecked_info info (block_a, known_account_a, 0, nano::signature_verification::unknown);
|
||||
|
|
|
@ -23,11 +23,9 @@ public:
|
|||
void pull_finished ();
|
||||
bool should_log ();
|
||||
std::string mode_text ();
|
||||
virtual void restart_condition ();
|
||||
virtual void add_frontier (nano::pull_info const &);
|
||||
virtual void add_bulk_push_target (nano::block_hash const &, nano::block_hash const &);
|
||||
virtual bool request_bulk_push_target (std::pair<nano::block_hash, nano::block_hash> &);
|
||||
virtual void add_recent_pull (nano::block_hash const &);
|
||||
virtual void lazy_start (nano::hash_or_account const &, bool confirmed = true);
|
||||
virtual void lazy_add (nano::pull_info const &);
|
||||
virtual void lazy_requeue (nano::block_hash const &, nano::block_hash const &, bool);
|
||||
|
@ -51,7 +49,6 @@ public:
|
|||
std::string id;
|
||||
std::chrono::steady_clock::time_point attempt_start{ std::chrono::steady_clock::now () };
|
||||
std::atomic<bool> frontiers_received{ false };
|
||||
std::atomic<bool> frontiers_confirmed{ false };
|
||||
nano::bootstrap_mode mode;
|
||||
nano::mutex mutex;
|
||||
nano::condition_variable condition;
|
||||
|
|
|
@ -356,10 +356,6 @@ void nano::bootstrap_connections::request_pull (nano::unique_lock<nano::mutex> &
|
|||
}
|
||||
if (attempt_l != nullptr)
|
||||
{
|
||||
if (attempt_l->mode == nano::bootstrap_mode::legacy)
|
||||
{
|
||||
attempt_l->add_recent_pull (pull.head);
|
||||
}
|
||||
// The bulk_pull_client destructor attempt to requeue_pull which can cause a deadlock if this is the last reference
|
||||
// Dispatch request in an external thread in case it needs to be destroyed
|
||||
node.background ([connection_l, attempt_l, pull]() {
|
||||
|
@ -388,11 +384,7 @@ void nano::bootstrap_connections::requeue_pull (nano::pull_info const & pull_a,
|
|||
if (attempt_l != nullptr)
|
||||
{
|
||||
++attempt_l->requeued_pulls;
|
||||
if (attempt_l->mode == nano::bootstrap_mode::legacy)
|
||||
{
|
||||
attempt_l->restart_condition ();
|
||||
}
|
||||
else if (attempt_l->mode == nano::bootstrap_mode::lazy)
|
||||
if (attempt_l->mode == nano::bootstrap_mode::lazy)
|
||||
{
|
||||
pull.count = attempt_l->lazy_batch_size ();
|
||||
}
|
||||
|
|
|
@ -115,196 +115,6 @@ bool nano::bootstrap_attempt_legacy::request_bulk_push_target (std::pair<nano::b
|
|||
return empty;
|
||||
}
|
||||
|
||||
void nano::bootstrap_attempt_legacy::add_recent_pull (nano::block_hash const & head_a)
|
||||
{
|
||||
nano::lock_guard<nano::mutex> lock (mutex);
|
||||
recent_pulls_head.push_back (head_a);
|
||||
if (recent_pulls_head.size () > nano::bootstrap_limits::bootstrap_max_confirm_frontiers)
|
||||
{
|
||||
recent_pulls_head.pop_front ();
|
||||
}
|
||||
}
|
||||
|
||||
void nano::bootstrap_attempt_legacy::restart_condition ()
|
||||
{
|
||||
/* Conditions to start frontiers confirmation:
|
||||
- not completed frontiers confirmation
|
||||
- more than 256 pull retries usually indicating issues with requested pulls
|
||||
- or 128k processed blocks indicating large bootstrap */
|
||||
if (!frontiers_confirmation_pending && !frontiers_confirmed && (requeued_pulls > (!node->network_params.network.is_dev_network () ? nano::bootstrap_limits::requeued_pulls_limit : nano::bootstrap_limits::requeued_pulls_limit_dev) || total_blocks > nano::bootstrap_limits::frontier_confirmation_blocks_limit))
|
||||
{
|
||||
frontiers_confirmation_pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
void nano::bootstrap_attempt_legacy::attempt_restart_check (nano::unique_lock<nano::mutex> & lock_a)
|
||||
{
|
||||
if (frontiers_confirmation_pending)
|
||||
{
|
||||
auto confirmed (confirm_frontiers (lock_a));
|
||||
debug_assert (lock_a.owns_lock ());
|
||||
if (!confirmed)
|
||||
{
|
||||
node->stats.inc (nano::stat::type::bootstrap, nano::stat::detail::frontier_confirmation_failed, nano::stat::dir::in);
|
||||
node->logger.try_log (boost::str (boost::format ("Frontier confirmation failed for peer %1% after %2% seconds bootstrap attempt") % endpoint_frontier_request % std::chrono::duration_cast<std::chrono::seconds> (std::chrono::steady_clock::now () - attempt_start).count ()));
|
||||
lock_a.unlock ();
|
||||
stop ();
|
||||
lock_a.lock ();
|
||||
// Start new bootstrap connection
|
||||
auto node_l (node->shared ());
|
||||
auto this_l (shared_from_this ());
|
||||
auto duration (std::chrono::duration_cast<std::chrono::seconds> (std::chrono::steady_clock::now () - attempt_start).count ());
|
||||
auto frontiers_age_l (frontiers_age != std::numeric_limits<uint32_t>::max () ? frontiers_age + duration : frontiers_age);
|
||||
node->background ([node_l, this_l, frontiers_age_l]() {
|
||||
node_l->bootstrap_initiator.remove_attempt (this_l);
|
||||
auto id_l (this_l->id);
|
||||
// Delay after removing current attempt
|
||||
node_l->workers.add_timed_task (std::chrono::steady_clock::now () + std::chrono::milliseconds (50), [node_l, id_l, frontiers_age_l]() {
|
||||
node_l->bootstrap_initiator.bootstrap (true, id_l, frontiers_age_l);
|
||||
});
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
node->stats.inc (nano::stat::type::bootstrap, nano::stat::detail::frontier_confirmation_successful, nano::stat::dir::in);
|
||||
}
|
||||
frontiers_confirmed = confirmed;
|
||||
frontiers_confirmation_pending = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool nano::bootstrap_attempt_legacy::confirm_frontiers (nano::unique_lock<nano::mutex> & lock_a)
|
||||
{
|
||||
bool confirmed (false);
|
||||
debug_assert (!frontiers_confirmed);
|
||||
condition.wait (lock_a, [& stopped = stopped] { return !stopped; });
|
||||
auto this_l (shared_from_this ());
|
||||
std::vector<nano::block_hash> frontiers;
|
||||
lock_a.unlock ();
|
||||
nano::unique_lock<nano::mutex> pulls_lock (node->bootstrap_initiator.connections->mutex);
|
||||
for (auto i (node->bootstrap_initiator.connections->pulls.begin ()), end (node->bootstrap_initiator.connections->pulls.end ()); i != end && frontiers.size () != nano::bootstrap_limits::bootstrap_max_confirm_frontiers; ++i)
|
||||
{
|
||||
if (!i->head.is_zero () && i->bootstrap_id == incremental_id && std::find (frontiers.begin (), frontiers.end (), i->head) == frontiers.end ())
|
||||
{
|
||||
frontiers.push_back (i->head);
|
||||
}
|
||||
}
|
||||
pulls_lock.unlock ();
|
||||
lock_a.lock ();
|
||||
for (auto i (recent_pulls_head.begin ()), end (recent_pulls_head.end ()); i != end && frontiers.size () != nano::bootstrap_limits::bootstrap_max_confirm_frontiers; ++i)
|
||||
{
|
||||
if (!i->is_zero () && std::find (frontiers.begin (), frontiers.end (), *i) == frontiers.end ())
|
||||
{
|
||||
frontiers.push_back (*i);
|
||||
}
|
||||
}
|
||||
lock_a.unlock ();
|
||||
auto frontiers_count (frontiers.size ());
|
||||
if (frontiers_count > 0)
|
||||
{
|
||||
const size_t reps_limit = 20;
|
||||
auto representatives (node->rep_crawler.representatives ());
|
||||
auto reps_weight (node->rep_crawler.total_weight ());
|
||||
auto representatives_copy (representatives);
|
||||
nano::uint128_t total_weight (0);
|
||||
// Select random peers from bottom 50% of principal representatives
|
||||
if (representatives.size () > 1)
|
||||
{
|
||||
std::reverse (representatives.begin (), representatives.end ());
|
||||
representatives.resize (representatives.size () / 2);
|
||||
for (auto i = static_cast<CryptoPP::word32> (representatives.size () - 1); i > 0; --i)
|
||||
{
|
||||
auto k = nano::random_pool::generate_word32 (0, i);
|
||||
std::swap (representatives[i], representatives[k]);
|
||||
}
|
||||
if (representatives.size () > reps_limit)
|
||||
{
|
||||
representatives.resize (reps_limit);
|
||||
}
|
||||
}
|
||||
for (auto const & rep : representatives)
|
||||
{
|
||||
total_weight += rep.weight.number ();
|
||||
}
|
||||
// Select peers with total 25% of reps stake from top 50% of principal representatives
|
||||
representatives_copy.resize (representatives_copy.size () / 2);
|
||||
while (total_weight < reps_weight / 4) // 25%
|
||||
{
|
||||
auto k = nano::random_pool::generate_word32 (0, static_cast<CryptoPP::word32> (representatives_copy.size () - 1));
|
||||
auto rep (representatives_copy[k]);
|
||||
if (std::find (representatives.begin (), representatives.end (), rep) == representatives.end ())
|
||||
{
|
||||
representatives.push_back (rep);
|
||||
total_weight += rep.weight.number ();
|
||||
}
|
||||
}
|
||||
// Start requests
|
||||
for (auto i (0), max_requests (20); i <= max_requests && !confirmed && !stopped; ++i)
|
||||
{
|
||||
std::unordered_map<std::shared_ptr<nano::transport::channel>, std::deque<std::pair<nano::block_hash, nano::root>>> batched_confirm_req_bundle;
|
||||
std::deque<std::pair<nano::block_hash, nano::root>> request;
|
||||
// Find confirmed frontiers (tally > 12.5% of reps stake, 60% of requestsed reps responded
|
||||
for (auto ii (frontiers.begin ()); ii != frontiers.end ();)
|
||||
{
|
||||
if (node->ledger.block_or_pruned_exists (*ii))
|
||||
{
|
||||
ii = frontiers.erase (ii);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto existing (node->active.find_inactive_votes_cache (*ii));
|
||||
nano::uint128_t tally;
|
||||
for (auto & [voter, timestamp] : existing.voters)
|
||||
{
|
||||
tally += node->ledger.weight (voter);
|
||||
}
|
||||
if (existing.status.confirmed || (tally > reps_weight / 8 && existing.voters.size () >= representatives.size () * 0.6)) // 12.5% of weight, 60% of reps
|
||||
{
|
||||
ii = frontiers.erase (ii);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto const & rep : representatives)
|
||||
{
|
||||
if (std::find_if (existing.voters.begin (), existing.voters.end (), [&rep](auto const & item_a) { return item_a.first == rep.account; }) == existing.voters.end ())
|
||||
{
|
||||
release_assert (!ii->is_zero ());
|
||||
auto rep_request (batched_confirm_req_bundle.find (rep.channel));
|
||||
if (rep_request == batched_confirm_req_bundle.end ())
|
||||
{
|
||||
std::deque<std::pair<nano::block_hash, nano::root>> insert_root_hash = { std::make_pair (*ii, *ii) };
|
||||
batched_confirm_req_bundle.emplace (rep.channel, insert_root_hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
rep_request->second.emplace_back (*ii, *ii);
|
||||
}
|
||||
}
|
||||
}
|
||||
++ii;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto confirmed_count (frontiers_count - frontiers.size ());
|
||||
if (confirmed_count >= frontiers_count * nano::bootstrap_limits::required_frontier_confirmation_ratio) // 80% of frontiers confirmed
|
||||
{
|
||||
confirmed = true;
|
||||
}
|
||||
else if (i < max_requests)
|
||||
{
|
||||
node->network.broadcast_confirm_req_batched_many (batched_confirm_req_bundle);
|
||||
std::this_thread::sleep_for (std::chrono::milliseconds (!node->network_params.network.is_dev_network () ? 500 : 25));
|
||||
}
|
||||
}
|
||||
if (!confirmed)
|
||||
{
|
||||
node->logger.always_log (boost::str (boost::format ("Failed to confirm frontiers for bootstrap attempt. %1% of %2% frontiers were not confirmed") % frontiers.size () % frontiers_count));
|
||||
}
|
||||
}
|
||||
lock_a.lock ();
|
||||
return confirmed;
|
||||
}
|
||||
|
||||
bool nano::bootstrap_attempt_legacy::request_frontier (nano::unique_lock<nano::mutex> & lock_a, bool first_attempt)
|
||||
{
|
||||
auto result (true);
|
||||
|
@ -371,10 +181,8 @@ bool nano::bootstrap_attempt_legacy::request_frontier (nano::unique_lock<nano::m
|
|||
void nano::bootstrap_attempt_legacy::run_start (nano::unique_lock<nano::mutex> & lock_a)
|
||||
{
|
||||
frontiers_received = false;
|
||||
frontiers_confirmed = false;
|
||||
total_blocks = 0;
|
||||
requeued_pulls = 0;
|
||||
recent_pulls_head.clear ();
|
||||
auto frontier_failure (true);
|
||||
uint64_t frontier_attempts (0);
|
||||
while (!stopped && frontier_failure)
|
||||
|
@ -397,9 +205,7 @@ void nano::bootstrap_attempt_legacy::run ()
|
|||
while (still_pulling ())
|
||||
{
|
||||
// clang-format off
|
||||
condition.wait (lock, [&stopped = stopped, &pulling = pulling, &frontiers_confirmation_pending = frontiers_confirmation_pending] { return stopped || pulling == 0 || frontiers_confirmation_pending; });
|
||||
// clang-format on
|
||||
attempt_restart_check (lock);
|
||||
condition.wait (lock, [&stopped = stopped, &pulling = pulling] { return stopped || pulling == 0; });
|
||||
}
|
||||
// Flushing may resolve forks which can add more pulls
|
||||
node->logger.try_log ("Flushing unchecked blocks");
|
||||
|
@ -430,6 +236,4 @@ void nano::bootstrap_attempt_legacy::get_information (boost::property_tree::ptre
|
|||
nano::lock_guard<nano::mutex> lock (mutex);
|
||||
tree_a.put ("frontier_pulls", std::to_string (frontier_pulls.size ()));
|
||||
tree_a.put ("frontiers_received", static_cast<bool> (frontiers_received));
|
||||
tree_a.put ("frontiers_confirmed", static_cast<bool> (frontiers_confirmed));
|
||||
tree_a.put ("frontiers_confirmation_pending", static_cast<bool> (frontiers_confirmation_pending));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,20 +25,14 @@ public:
|
|||
void add_frontier (nano::pull_info const &) override;
|
||||
void add_bulk_push_target (nano::block_hash const &, nano::block_hash const &) override;
|
||||
bool request_bulk_push_target (std::pair<nano::block_hash, nano::block_hash> &) override;
|
||||
void add_recent_pull (nano::block_hash const &) override;
|
||||
void run_start (nano::unique_lock<nano::mutex> &);
|
||||
void restart_condition () override;
|
||||
void attempt_restart_check (nano::unique_lock<nano::mutex> &);
|
||||
bool confirm_frontiers (nano::unique_lock<nano::mutex> &);
|
||||
void get_information (boost::property_tree::ptree &) override;
|
||||
nano::tcp_endpoint endpoint_frontier_request;
|
||||
std::weak_ptr<nano::frontier_req_client> frontiers;
|
||||
std::weak_ptr<nano::bulk_push_client> push;
|
||||
std::deque<nano::pull_info> frontier_pulls;
|
||||
std::deque<nano::block_hash> recent_pulls_head;
|
||||
std::vector<std::pair<nano::block_hash, nano::block_hash>> bulk_push_targets;
|
||||
std::atomic<unsigned> account_count{ 0 };
|
||||
std::atomic<bool> frontiers_confirmation_pending{ false };
|
||||
uint32_t frontiers_age;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1688,7 +1688,6 @@ void nano::json_handler::bootstrap ()
|
|||
{
|
||||
std::string address_text = request.get<std::string> ("address");
|
||||
std::string port_text = request.get<std::string> ("port");
|
||||
const bool bypass_frontier_confirmation = request.get<bool> ("bypass_frontier_confirmation", false);
|
||||
boost::system::error_code address_ec;
|
||||
auto address (boost::asio::ip::make_address_v6 (address_text, address_ec));
|
||||
if (!address_ec)
|
||||
|
@ -1699,7 +1698,7 @@ void nano::json_handler::bootstrap ()
|
|||
if (!node.flags.disable_legacy_bootstrap)
|
||||
{
|
||||
std::string bootstrap_id (request.get<std::string> ("id", ""));
|
||||
node.bootstrap_initiator.bootstrap (nano::endpoint (address, port), true, bypass_frontier_confirmation, bootstrap_id);
|
||||
node.bootstrap_initiator.bootstrap (nano::endpoint (address, port), true, bootstrap_id);
|
||||
response_l.put ("success", "");
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue