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