Creating confirmation_solicitor class. This class manages taking unconfirmed elections and creating confirmation_req bundles to the needed representatives.
This commit is contained in:
		
					parent
					
						
							
								b60233a1fd
							
						
					
				
			
			
				commit
				
					
						41b3f5e327
					
				
			
		
					 5 changed files with 127 additions and 172 deletions
				
			
		| 
						 | 
				
			
			@ -43,6 +43,8 @@ add_library (node
 | 
			
		|||
	common.cpp
 | 
			
		||||
	confirmation_height_processor.hpp
 | 
			
		||||
	confirmation_height_processor.cpp
 | 
			
		||||
	confirmation_solicitor.cpp
 | 
			
		||||
	confirmation_solicitor.hpp
 | 
			
		||||
	daemonconfig.hpp
 | 
			
		||||
	daemonconfig.cpp
 | 
			
		||||
	distributed_work.hpp
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,7 @@ election_time_to_live (node.network_params.network.is_test_network () ? 0s : 10s
 | 
			
		|||
multipliers_cb (20, 1.),
 | 
			
		||||
trended_active_difficulty (node.network_params.network.publish_threshold),
 | 
			
		||||
next_frontier_check (steady_clock::now ()),
 | 
			
		||||
solicitor (node_a),
 | 
			
		||||
thread ([this]() {
 | 
			
		||||
	nano::thread_role::set (nano::thread_role::name::request_loop);
 | 
			
		||||
	request_loop ();
 | 
			
		||||
| 
						 | 
				
			
			@ -202,109 +203,11 @@ void nano::active_transactions::election_escalate (std::shared_ptr<nano::electio
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::active_transactions::election_broadcast (std::shared_ptr<nano::election> & election_l, nano::transaction const & transaction_l, std::deque<std::shared_ptr<nano::block>> & blocks_bundle_l, std::unordered_set<nano::qualified_root> & inactive_l, nano::qualified_root & root_l)
 | 
			
		||||
{
 | 
			
		||||
	if (node.ledger.could_fit (transaction_l, *election_l->status.winner))
 | 
			
		||||
	{
 | 
			
		||||
		// Broadcast current winner
 | 
			
		||||
		if (blocks_bundle_l.size () < max_block_broadcasts)
 | 
			
		||||
		{
 | 
			
		||||
			blocks_bundle_l.push_back (election_l->status.winner);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (election_l->confirmation_request_count != 0)
 | 
			
		||||
	{
 | 
			
		||||
		election_l->stop ();
 | 
			
		||||
		inactive_l.insert (root_l);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nano::active_transactions::election_request_confirm (std::shared_ptr<nano::election> & election_l, std::vector<nano::representative> const & representatives_l, size_t const & roots_size_l,
 | 
			
		||||
std::deque<std::pair<std::shared_ptr<nano::block>, std::shared_ptr<std::vector<std::shared_ptr<nano::transport::channel>>>>> & single_confirm_req_bundle_l,
 | 
			
		||||
std::unordered_map<std::shared_ptr<nano::transport::channel>, std::deque<std::pair<nano::block_hash, nano::root>>> & batched_confirm_req_bundle_l)
 | 
			
		||||
{
 | 
			
		||||
	bool inserted_into_any_bundle{ false };
 | 
			
		||||
	std::vector<std::shared_ptr<nano::transport::channel>> rep_channels_missing_vote_l;
 | 
			
		||||
	// Add all rep endpoints that haven't already voted
 | 
			
		||||
	for (const auto & rep : representatives_l)
 | 
			
		||||
	{
 | 
			
		||||
		if (election_l->last_votes.find (rep.account) == election_l->last_votes.end ())
 | 
			
		||||
		{
 | 
			
		||||
			rep_channels_missing_vote_l.push_back (rep.channel);
 | 
			
		||||
 | 
			
		||||
			if (node.config.logging.vote_logging () && election_l->confirmation_request_count > 0)
 | 
			
		||||
			{
 | 
			
		||||
				node.logger.try_log ("Representative did not respond to confirm_req, retrying: ", rep.account.to_account ());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// Unique channels as there can be multiple reps per channel
 | 
			
		||||
	rep_channels_missing_vote_l.erase (std::unique (rep_channels_missing_vote_l.begin (), rep_channels_missing_vote_l.end ()), rep_channels_missing_vote_l.end ());
 | 
			
		||||
	bool low_reps_weight (rep_channels_missing_vote_l.empty () || node.rep_crawler.total_weight () < node.config.online_weight_minimum.number ());
 | 
			
		||||
	if (low_reps_weight && roots_size_l <= 5 && !node.network_params.network.is_test_network ())
 | 
			
		||||
	{
 | 
			
		||||
		// Spam mode
 | 
			
		||||
		auto deque_l (node.network.udp_channels.random_set (100));
 | 
			
		||||
		auto vec (std::make_shared<std::vector<std::shared_ptr<nano::transport::channel>>> ());
 | 
			
		||||
		for (auto i : deque_l)
 | 
			
		||||
		{
 | 
			
		||||
			vec->push_back (i);
 | 
			
		||||
		}
 | 
			
		||||
		single_confirm_req_bundle_l.push_back (std::make_pair (election_l->status.winner, vec));
 | 
			
		||||
		inserted_into_any_bundle = true;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		auto single_confirm_req_channels_l (std::make_shared<std::vector<std::shared_ptr<nano::transport::channel>>> ());
 | 
			
		||||
		for (auto & rep : rep_channels_missing_vote_l)
 | 
			
		||||
		{
 | 
			
		||||
			if (rep->get_network_version () >= node.network_params.protocol.tcp_realtime_protocol_version_min)
 | 
			
		||||
			{
 | 
			
		||||
				// Send batch request to peers supporting confirm_req by hash + root
 | 
			
		||||
				auto rep_request_l (batched_confirm_req_bundle_l.find (rep));
 | 
			
		||||
				auto block_l (election_l->status.winner);
 | 
			
		||||
				auto root_hash_l (std::make_pair (block_l->hash (), block_l->root ()));
 | 
			
		||||
				if (rep_request_l == batched_confirm_req_bundle_l.end ())
 | 
			
		||||
				{
 | 
			
		||||
					// Maximum number of representatives
 | 
			
		||||
					if (batched_confirm_req_bundle_l.size () < max_confirm_representatives)
 | 
			
		||||
					{
 | 
			
		||||
						std::deque<std::pair<nano::block_hash, nano::root>> insert_root_hash = { root_hash_l };
 | 
			
		||||
						batched_confirm_req_bundle_l.insert (std::make_pair (rep, insert_root_hash));
 | 
			
		||||
						inserted_into_any_bundle = true;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				// Maximum number of hashes
 | 
			
		||||
				else if (rep_request_l->second.size () < max_confirm_req_batches * nano::network::confirm_req_hashes_max)
 | 
			
		||||
				{
 | 
			
		||||
					rep_request_l->second.push_back (root_hash_l);
 | 
			
		||||
					inserted_into_any_bundle = true;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				single_confirm_req_channels_l->push_back (rep);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// broadcast_confirm_req_base modifies reps, so we clone it once to avoid aliasing
 | 
			
		||||
		if (single_confirm_req_bundle_l.size () < max_confirm_req && !single_confirm_req_channels_l->empty ())
 | 
			
		||||
		{
 | 
			
		||||
			single_confirm_req_bundle_l.push_back (std::make_pair (election_l->status.winner, single_confirm_req_channels_l));
 | 
			
		||||
			inserted_into_any_bundle = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return inserted_into_any_bundle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::active_transactions::request_confirm (nano::unique_lock<std::mutex> & lock_a)
 | 
			
		||||
{
 | 
			
		||||
	assert (!mutex.try_lock ());
 | 
			
		||||
	auto transaction_l (node.store.tx_begin_read ());
 | 
			
		||||
	std::unordered_set<nano::qualified_root> inactive_l;
 | 
			
		||||
	std::deque<std::shared_ptr<nano::block>> blocks_bundle_l;
 | 
			
		||||
	std::unordered_map<std::shared_ptr<nano::transport::channel>, std::deque<std::pair<nano::block_hash, nano::root>>> batched_confirm_req_bundle_l;
 | 
			
		||||
	std::deque<std::pair<std::shared_ptr<nano::block>, std::shared_ptr<std::vector<std::shared_ptr<nano::transport::channel>>>>> single_confirm_req_bundle_l;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Confirm frontiers when there aren't many confirmations already pending and node finished initial bootstrap
 | 
			
		||||
	 * In auto mode start confirm only if node contains almost principal representative (half of required for principal weight)
 | 
			
		||||
| 
						 | 
				
			
			@ -330,7 +233,6 @@ void nano::active_transactions::request_confirm (nano::unique_lock<std::mutex> &
 | 
			
		|||
	// The lowest PoW difficulty elections have a maximum time to live if they are beyond the soft threshold size for the container
 | 
			
		||||
	auto election_ttl_cutoff_l (std::chrono::steady_clock::now () - election_time_to_live);
 | 
			
		||||
 | 
			
		||||
	auto const representatives_l (node.rep_crawler.representatives (std::numeric_limits<size_t>::max ()));
 | 
			
		||||
	auto roots_size_l (roots.size ());
 | 
			
		||||
	auto & sorted_roots_l = roots.get<tag_difficulty> ();
 | 
			
		||||
	size_t count_l{ 0 };
 | 
			
		||||
| 
						 | 
				
			
			@ -344,12 +246,17 @@ void nano::active_transactions::request_confirm (nano::unique_lock<std::mutex> &
 | 
			
		|||
	 * Elections extending the soft config.active_elections_size limit are flushed after a certain time-to-live cutoff
 | 
			
		||||
	 * Flushed elections are later re-activated via frontier confirmation
 | 
			
		||||
	 */
 | 
			
		||||
	solicitor.prepare ();
 | 
			
		||||
	for (auto i = sorted_roots_l.begin (), n = sorted_roots_l.end (); i != n; ++i, ++count_l)
 | 
			
		||||
	{
 | 
			
		||||
		auto election_l (i->election);
 | 
			
		||||
		auto root_l (i->root);
 | 
			
		||||
		if (election_l->confirmed || (election_l->confirmation_request_count != 0 && !node.ledger.could_fit (transaction_l, *election_l->status.winner)))
 | 
			
		||||
		{
 | 
			
		||||
			election_l->stop ();
 | 
			
		||||
		}
 | 
			
		||||
		// Erase finished elections
 | 
			
		||||
		if ((election_l->confirmed || election_l->stopped))
 | 
			
		||||
		if ((election_l->stopped))
 | 
			
		||||
		{
 | 
			
		||||
			inactive_l.insert (root_l);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -363,74 +270,16 @@ void nano::active_transactions::request_confirm (nano::unique_lock<std::mutex> &
 | 
			
		|||
		// Broadcast and request confirmation
 | 
			
		||||
		else if (election_l->skip_delay || election_l->election_start < cutoff_l)
 | 
			
		||||
		{
 | 
			
		||||
			bool increment_counter_l{ true };
 | 
			
		||||
			solicitor.add (election_l);
 | 
			
		||||
			// Escalate long election after a certain time and number of requests performed
 | 
			
		||||
			if (election_l->confirmation_request_count > 4 && election_l->election_start < long_election_cutoff_l)
 | 
			
		||||
			{
 | 
			
		||||
				election_escalate (election_l, transaction_l, roots_size_l);
 | 
			
		||||
			}
 | 
			
		||||
			// Block broadcasting
 | 
			
		||||
			if (election_l->confirmation_request_count % 8 == 1)
 | 
			
		||||
			{
 | 
			
		||||
				election_broadcast (election_l, transaction_l, blocks_bundle_l, inactive_l, root_l);
 | 
			
		||||
			}
 | 
			
		||||
			// Confirmation requesting
 | 
			
		||||
			if (election_l->confirmation_request_count % 4 == 0)
 | 
			
		||||
			{
 | 
			
		||||
				// If failed to insert into any of the bundles (capped), don't increment the counter so that the same root is sent for confirmation in the next loop
 | 
			
		||||
				if (!election_request_confirm (election_l, representatives_l, roots_size_l, single_confirm_req_bundle_l, batched_confirm_req_bundle_l))
 | 
			
		||||
				{
 | 
			
		||||
					increment_counter_l = false;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (increment_counter_l || node.network_params.network.is_test_network ())
 | 
			
		||||
			{
 | 
			
		||||
				++election_l->confirmation_request_count;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	ongoing_broadcasts = !blocks_bundle_l.empty () + !batched_confirm_req_bundle_l.empty () + !single_confirm_req_bundle_l.empty ();
 | 
			
		||||
	lock_a.unlock ();
 | 
			
		||||
 | 
			
		||||
	// Rebroadcast unconfirmed blocks
 | 
			
		||||
	if (!blocks_bundle_l.empty ())
 | 
			
		||||
	{
 | 
			
		||||
		node.network.flood_block_many (
 | 
			
		||||
		std::move (blocks_bundle_l), [this]() {
 | 
			
		||||
			{
 | 
			
		||||
				nano::lock_guard<std::mutex> guard_l (this->mutex);
 | 
			
		||||
				--this->ongoing_broadcasts;
 | 
			
		||||
			}
 | 
			
		||||
			this->condition.notify_all ();
 | 
			
		||||
		},
 | 
			
		||||
		10); // 10ms/block * 30blocks = 300ms < 500ms
 | 
			
		||||
	}
 | 
			
		||||
	// Batch confirmation request
 | 
			
		||||
	if (!batched_confirm_req_bundle_l.empty ())
 | 
			
		||||
	{
 | 
			
		||||
		node.network.broadcast_confirm_req_batched_many (
 | 
			
		||||
		batched_confirm_req_bundle_l, [this]() {
 | 
			
		||||
			{
 | 
			
		||||
				nano::lock_guard<std::mutex> guard_l (this->mutex);
 | 
			
		||||
				--this->ongoing_broadcasts;
 | 
			
		||||
			}
 | 
			
		||||
			this->condition.notify_all ();
 | 
			
		||||
		},
 | 
			
		||||
		15); // 15ms/batch * 20batches = 300ms < 500ms
 | 
			
		||||
	}
 | 
			
		||||
	// Single confirmation requests
 | 
			
		||||
	if (!single_confirm_req_bundle_l.empty ())
 | 
			
		||||
	{
 | 
			
		||||
		node.network.broadcast_confirm_req_many (
 | 
			
		||||
		single_confirm_req_bundle_l, [this]() {
 | 
			
		||||
			{
 | 
			
		||||
				nano::lock_guard<std::mutex> guard_l (this->mutex);
 | 
			
		||||
				--this->ongoing_broadcasts;
 | 
			
		||||
			}
 | 
			
		||||
			this->condition.notify_all ();
 | 
			
		||||
		},
 | 
			
		||||
		30); // 30~60ms/req * 5 reqs = 150~300ms < 500ms
 | 
			
		||||
	}
 | 
			
		||||
	solicitor.flush ();
 | 
			
		||||
	lock_a.lock ();
 | 
			
		||||
	// Erase inactive elections
 | 
			
		||||
	for (auto i (inactive_l.begin ()), n (inactive_l.end ()); i != n; ++i)
 | 
			
		||||
| 
						 | 
				
			
			@ -467,10 +316,6 @@ void nano::active_transactions::request_loop ()
 | 
			
		|||
		request_confirm (lock);
 | 
			
		||||
 | 
			
		||||
		// Sleep until all broadcasts are done, plus the remaining loop time
 | 
			
		||||
		while (!stopped && ongoing_broadcasts)
 | 
			
		||||
		{
 | 
			
		||||
			condition.wait (lock);
 | 
			
		||||
		}
 | 
			
		||||
		if (!stopped)
 | 
			
		||||
		{
 | 
			
		||||
			// clang-format off
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <nano/lib/numbers.hpp>
 | 
			
		||||
#include <nano/node/confirmation_solicitor.hpp>
 | 
			
		||||
#include <nano/node/election.hpp>
 | 
			
		||||
#include <nano/node/gap_cache.hpp>
 | 
			
		||||
#include <nano/node/repcrawler.hpp>
 | 
			
		||||
| 
						 | 
				
			
			@ -121,10 +122,7 @@ public:
 | 
			
		|||
	std::chrono::milliseconds const election_request_delay;
 | 
			
		||||
	// Maximum time an election can be kept active if it is extending the container
 | 
			
		||||
	std::chrono::seconds const election_time_to_live;
 | 
			
		||||
	static size_t constexpr max_block_broadcasts = 30;
 | 
			
		||||
	static size_t constexpr max_confirm_representatives = 30;
 | 
			
		||||
	static size_t constexpr max_confirm_req_batches = 20;
 | 
			
		||||
	static size_t constexpr max_confirm_req = 5;
 | 
			
		||||
	boost::circular_buffer<double> multipliers_cb;
 | 
			
		||||
	uint64_t trended_active_difficulty;
 | 
			
		||||
	size_t priority_cementable_frontiers_size ();
 | 
			
		||||
| 
						 | 
				
			
			@ -145,17 +143,12 @@ private:
 | 
			
		|||
	void request_loop ();
 | 
			
		||||
	void search_frontiers (nano::transaction const &);
 | 
			
		||||
	void election_escalate (std::shared_ptr<nano::election> &, nano::transaction const &, size_t const &);
 | 
			
		||||
	void election_broadcast (std::shared_ptr<nano::election> &, nano::transaction const &, std::deque<std::shared_ptr<nano::block>> &, std::unordered_set<nano::qualified_root> &, nano::qualified_root &);
 | 
			
		||||
	bool election_request_confirm (std::shared_ptr<nano::election> &, std::vector<nano::representative> const &, size_t const &,
 | 
			
		||||
	std::deque<std::pair<std::shared_ptr<nano::block>, std::shared_ptr<std::vector<std::shared_ptr<nano::transport::channel>>>>> & single_confirm_req_bundle_l,
 | 
			
		||||
	std::unordered_map<std::shared_ptr<nano::transport::channel>, std::deque<std::pair<nano::block_hash, nano::root>>> & batched_confirm_req_bundle_l);
 | 
			
		||||
	void request_confirm (nano::unique_lock<std::mutex> &);
 | 
			
		||||
	nano::account next_frontier_account{ 0 };
 | 
			
		||||
	std::chrono::steady_clock::time_point next_frontier_check{ std::chrono::steady_clock::now () };
 | 
			
		||||
	nano::condition_variable condition;
 | 
			
		||||
	bool started{ false };
 | 
			
		||||
	std::atomic<bool> stopped{ false };
 | 
			
		||||
	unsigned ongoing_broadcasts{ 0 };
 | 
			
		||||
	// clang-format off
 | 
			
		||||
	boost::multi_index_container<nano::qualified_root,
 | 
			
		||||
	mi::indexed_by<
 | 
			
		||||
| 
						 | 
				
			
			@ -189,6 +182,7 @@ private:
 | 
			
		|||
		mi::hashed_unique<mi::tag<tag_root>,
 | 
			
		||||
			mi::member<nano::election_timepoint, nano::qualified_root, &nano::election_timepoint::root>>>>
 | 
			
		||||
	dropped_elections_cache;
 | 
			
		||||
	nano::confirmation_solicitor solicitor;
 | 
			
		||||
	// clang-format on
 | 
			
		||||
	static size_t constexpr dropped_elections_cache_max{ 32 * 1024 };
 | 
			
		||||
	boost::thread thread;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										63
									
								
								nano/node/confirmation_solicitor.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								nano/node/confirmation_solicitor.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
#include <nano/node/confirmation_solicitor.hpp>
 | 
			
		||||
 | 
			
		||||
#include <nano/node/election.hpp>
 | 
			
		||||
#include <nano/node/node.hpp>
 | 
			
		||||
 | 
			
		||||
nano::confirmation_solicitor::confirmation_solicitor (nano::node & node_a) :
 | 
			
		||||
node (node_a)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::confirmation_solicitor::prepare ()
 | 
			
		||||
{
 | 
			
		||||
	assert (!prepared);
 | 
			
		||||
	requests.clear ();
 | 
			
		||||
	rebroadcasted = 0;
 | 
			
		||||
	representatives = node.rep_crawler.representatives ();
 | 
			
		||||
	prepared = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::confirmation_solicitor::add (std::shared_ptr<nano::election> election_a)
 | 
			
		||||
{
 | 
			
		||||
	assert (prepared);
 | 
			
		||||
	if (election_a->confirmation_request_count % 8 == 1 && rebroadcasted++ < max_block_broadcasts)
 | 
			
		||||
	{
 | 
			
		||||
		node.network.flood_block (election_a->status.winner);
 | 
			
		||||
	}
 | 
			
		||||
	for (auto const & rep : representatives)
 | 
			
		||||
	{
 | 
			
		||||
		if (election_a->last_votes.find (rep.account) == election_a->last_votes.end ())
 | 
			
		||||
		{
 | 
			
		||||
			requests.insert ({ rep.channel, election_a });
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	++election_a->confirmation_request_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::confirmation_solicitor::flush ()
 | 
			
		||||
{
 | 
			
		||||
	assert (prepared);
 | 
			
		||||
	size_t batch_count = 0;
 | 
			
		||||
	size_t single_count = 0;
 | 
			
		||||
	for (auto i = requests.begin (), n (requests.end ()); i != n;)
 | 
			
		||||
	{
 | 
			
		||||
		if (batch_count++ < max_confirm_req_batches && i->channel->get_network_version () >= node.network_params.protocol.tcp_realtime_protocol_version_min)
 | 
			
		||||
		{
 | 
			
		||||
			auto channel = i->channel;
 | 
			
		||||
			std::vector<std::pair<nano::block_hash, nano::root>> roots_hashes_l;
 | 
			
		||||
			while (i != n && i->channel == channel && roots_hashes_l.size () < nano::network::confirm_req_hashes_max)
 | 
			
		||||
			{
 | 
			
		||||
				roots_hashes_l.push_back (std::make_pair (i->election->status.winner->hash (), i->election->status.winner->root ()));
 | 
			
		||||
				++i;
 | 
			
		||||
			}
 | 
			
		||||
			nano::confirm_req req (roots_hashes_l);
 | 
			
		||||
			channel->send (req);
 | 
			
		||||
		}
 | 
			
		||||
		else if (single_count++ < max_confirm_req)
 | 
			
		||||
		{
 | 
			
		||||
			node.network.broadcast_confirm_req (i->election->status.winner);
 | 
			
		||||
			++i;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	prepared = false;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								nano/node/confirmation_solicitor.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								nano/node/confirmation_solicitor.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,51 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <nano/node/repcrawler.hpp>
 | 
			
		||||
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
namespace nano
 | 
			
		||||
{
 | 
			
		||||
class election;
 | 
			
		||||
class node;
 | 
			
		||||
/** This class accepts elections that need further votes before they can be confirmed and bundles them in to single confirm_req packets */
 | 
			
		||||
class confirmation_solicitor final
 | 
			
		||||
{
 | 
			
		||||
	class request
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		std::shared_ptr<nano::transport::channel> channel;
 | 
			
		||||
		std::shared_ptr<nano::election> election;
 | 
			
		||||
		bool operator== (nano::confirmation_solicitor::request const & other_a) const
 | 
			
		||||
		{
 | 
			
		||||
			return *channel == *other_a.channel && election == other_a.election;
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
	class request_hash
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		size_t operator () (nano::confirmation_solicitor::request const & item_a) const
 | 
			
		||||
		{
 | 
			
		||||
			return std::hash<std::shared_ptr<nano::election>> ()(item_a.election) ^ std::hash<nano::transport::channel> ()(*item_a.channel);
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
public:
 | 
			
		||||
	confirmation_solicitor (nano::node &);
 | 
			
		||||
	/** Prepare object for batching election confirmation requests*/
 | 
			
		||||
	void prepare ();
 | 
			
		||||
	/** Add an election that needs to be confirmed */
 | 
			
		||||
	void add (std::shared_ptr<nano::election>);
 | 
			
		||||
	/** Bundle hashes together for identical channels in to a single confirm_req by hash packet */
 | 
			
		||||
	void flush ();
 | 
			
		||||
private:
 | 
			
		||||
	static size_t constexpr max_confirm_req_batches = 20;
 | 
			
		||||
	static size_t constexpr max_confirm_req = 5;
 | 
			
		||||
	static size_t constexpr max_block_broadcasts = 30;
 | 
			
		||||
	int rebroadcasted { 0 };
 | 
			
		||||
	nano::node & node;
 | 
			
		||||
	std::vector<nano::representative> representatives;
 | 
			
		||||
	/** Unique channel/hash to be requested */
 | 
			
		||||
	std::unordered_set<request, nano::confirmation_solicitor::request_hash> requests;
 | 
			
		||||
	bool prepared { false };
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue