-
Notifications
You must be signed in to change notification settings - Fork 795
/
Copy pathconfirmation_solicitor.cpp
116 lines (109 loc) · 4.1 KB
/
confirmation_solicitor.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <nano/lib/blocks.hpp>
#include <nano/node/confirmation_solicitor.hpp>
#include <nano/node/election.hpp>
#include <nano/node/nodeconfig.hpp>
using namespace std::chrono_literals;
nano::confirmation_solicitor::confirmation_solicitor (nano::network & network_a, nano::node_config const & config_a) :
max_block_broadcasts (config_a.network_params.network.is_dev_network () ? 4 : 30),
max_election_requests (50),
max_election_broadcasts (std::max<std::size_t> (network_a.fanout () / 2, 1)),
network (network_a),
config (config_a)
{
}
void nano::confirmation_solicitor::prepare (std::vector<nano::representative> const & representatives_a)
{
debug_assert (!prepared);
debug_assert (std::none_of (representatives_a.begin (), representatives_a.end (), [] (auto const & rep) { return rep.channel == nullptr; }));
requests.clear ();
rebroadcasted = 0;
/** Two copies are required as representatives can be erased from \p representatives_requests */
representatives_requests = representatives_a;
representatives_broadcasts = representatives_a;
prepared = true;
}
bool nano::confirmation_solicitor::broadcast (nano::election const & election_a)
{
debug_assert (prepared);
bool error (true);
if (rebroadcasted++ < max_block_broadcasts)
{
auto const & hash (election_a.status.winner->hash ());
nano::publish winner{ config.network_params.network, election_a.status.winner };
unsigned count = 0;
// Directed broadcasting to principal representatives
for (auto i (representatives_broadcasts.begin ()), n (representatives_broadcasts.end ()); i != n && count < max_election_broadcasts; ++i)
{
auto existing (election_a.last_votes.find (i->account));
bool const exists (existing != election_a.last_votes.end ());
bool const different (exists && existing->second.hash != hash);
if (!exists || different)
{
i->channel->send (winner, nano::transport::traffic_type::block_broadcast);
count += different ? 0 : 1;
}
}
// Random flood for block propagation
// TODO: Avoid broadcasting to the same peers that were already broadcasted to
network.flood_message (winner, nano::transport::traffic_type::block_broadcast, 0.5f);
error = false;
}
return error;
}
bool nano::confirmation_solicitor::add (nano::election const & election_a)
{
debug_assert (prepared);
bool error (true);
unsigned count = 0;
auto const & hash (election_a.status.winner->hash ());
for (auto i (representatives_requests.begin ()); i != representatives_requests.end () && count < max_election_requests;)
{
bool full_queue (false);
auto rep (*i);
auto existing (election_a.last_votes.find (rep.account));
bool const exists (existing != election_a.last_votes.end ());
bool const is_final (exists && (!election_a.is_quorum.load () || existing->second.timestamp == std::numeric_limits<uint64_t>::max ()));
bool const different (exists && existing->second.hash != hash);
if (!exists || !is_final || different)
{
if (!rep.channel->max (nano::transport::traffic_type::confirmation_requests))
{
auto & request_queue (requests[rep.channel]);
request_queue.emplace_back (election_a.status.winner->hash (), election_a.status.winner->root ());
count += different ? 0 : 1;
error = false;
}
else
{
full_queue = true;
}
}
i = !full_queue ? i + 1 : representatives_requests.erase (i);
}
return error;
}
void nano::confirmation_solicitor::flush ()
{
debug_assert (prepared);
for (auto const & request_queue : requests)
{
auto const & channel (request_queue.first);
std::vector<std::pair<nano::block_hash, nano::root>> roots_hashes_l;
for (auto const & root_hash : request_queue.second)
{
roots_hashes_l.push_back (root_hash);
if (roots_hashes_l.size () == nano::network::confirm_req_hashes_max)
{
nano::confirm_req req{ config.network_params.network, roots_hashes_l };
channel->send (req, nano::transport::traffic_type::confirmation_requests);
roots_hashes_l.clear ();
}
}
if (!roots_hashes_l.empty ())
{
nano::confirm_req req{ config.network_params.network, roots_hashes_l };
channel->send (req, nano::transport::traffic_type::confirmation_requests);
}
}
prepared = false;
}