Skip to content

Commit 02bc051

Browse files
authored
Merge pull request #1265 from AntelopeIO/GH-1245-gossip-bp-peers
P2P: Add gossip of BP peers
2 parents 2ff8d1e + 107647b commit 02bc051

23 files changed

+1272
-469
lines changed

libraries/chain/controller.cpp

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,7 @@ struct controller_impl {
12861286
}
12871287
}
12881288

1289-
getpeerkeys_res_t get_top_producer_keys(fc::time_point deadline) {
1289+
getpeerkeys_res_t get_top_producer_keys() {
12901290
try {
12911291
auto get_getpeerkeys_transaction = [&]() {
12921292
auto perms = vector<permission_level>{};
@@ -1303,7 +1303,7 @@ struct controller_impl {
13031303
transaction_metadata::trx_type::read_only);
13041304

13051305
// allow a max of 20ms for getpeerkeys
1306-
auto trace = push_transaction(metadata, deadline, fc::milliseconds(20), 0, false, 0);
1306+
auto trace = push_transaction(metadata, fc::time_point::maximum(), fc::milliseconds(20), 0, false, 0);
13071307

13081308
if( trace->except_ptr )
13091309
std::rethrow_exception(trace->except_ptr);
@@ -3237,6 +3237,11 @@ struct controller_impl {
32373237

32383238
auto& bb = std::get<building_block>(pending->_block_stage);
32393239

3240+
// limit to complete type to avoid multiple calls per block number due to speculative blocks
3241+
if (pending->_block_status == controller::block_status::complete) {
3242+
update_peer_keys();
3243+
}
3244+
32403245
transaction_trace_ptr onblock_trace;
32413246

32423247
// block status is either ephemeral or incomplete. Modify state of speculative block only if we are building a
@@ -3384,12 +3389,16 @@ struct controller_impl {
33843389
return onblock_trace;
33853390
} /// start_block
33863391

3387-
void update_peer_keys(fc::time_point deadline) {
3392+
void update_peer_keys() {
3393+
// if syncing or replaying old blocks don't bother updating peer keys
3394+
if (!peer_keys_db.is_active() || fc::time_point::now() - chain_head.timestamp() > fc::minutes(5))
3395+
return;
3396+
33883397
try {
3389-
// update peer public keys from chainbase db using a readonly trx
3390-
auto block_num = chain_head.block_num();
3391-
if (block_num % 120 == 0) { // update once/minute
3392-
peer_keys_db.update_peer_keys(get_top_producer_keys(deadline));
3398+
auto block_num = chain_head.block_num() + 1;
3399+
if (peer_keys_db.should_update(block_num)) { // update once/minute
3400+
// update peer public keys from chainbase db using a readonly trx
3401+
peer_keys_db.update_peer_keys(block_num, get_top_producer_keys());
33933402
}
33943403
} FC_LOG_AND_DROP()
33953404
}
@@ -5348,10 +5357,6 @@ transaction_trace_ptr controller::start_block( block_timestamp_type when,
53485357
bs, std::optional<block_id_type>(), deadline );
53495358
}
53505359

5351-
void controller::update_peer_keys(fc::time_point deadline) {
5352-
my->update_peer_keys(deadline);
5353-
}
5354-
53555360
void controller::assemble_and_complete_block( const signer_callback_type& signer_callback ) {
53565361
validate_db_available_size();
53575362

@@ -5848,16 +5853,20 @@ chain_id_type controller::get_chain_id()const {
58485853
return my->chain_id;
58495854
}
58505855

5851-
void controller::set_peer_keys_retrieval_active(bool active) {
5852-
my->peer_keys_db.set_active(active);
5856+
void controller::set_peer_keys_retrieval_active(peer_name_set_t configured_bp_peers) {
5857+
my->peer_keys_db.set_active(std::move(configured_bp_peers));
58535858
}
58545859

5855-
peer_info_t controller::get_peer_info(name n) const {
5860+
std::optional<peer_info_t> controller::get_peer_info(name n) const {
58565861
return my->peer_keys_db.get_peer_info(n);
58575862
}
58585863

5859-
getpeerkeys_res_t controller::get_top_producer_keys(fc::time_point deadline) {
5860-
return my->get_top_producer_keys(deadline);
5864+
bool controller::configured_peer_keys_updated() {
5865+
return my->peer_keys_db.configured_peer_keys_updated();
5866+
}
5867+
5868+
getpeerkeys_res_t controller::get_top_producer_keys() {
5869+
return my->get_top_producer_keys();
58615870
}
58625871

58635872
db_read_mode controller::get_read_mode()const {

libraries/chain/include/eosio/chain/controller.hpp

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <eosio/chain/webassembly/eos-vm-oc/config.hpp>
1111
#include <eosio/chain/vote_message.hpp>
1212
#include <eosio/chain/finalizer.hpp>
13+
#include <eosio/chain/peer_keys_db.hpp>
1314

1415
#include <chainbase/pinnable_mapped_file.hpp>
1516

@@ -80,23 +81,6 @@ namespace eosio::chain {
8081
class resource_limits_manager;
8182
};
8283

83-
// vector, sorted by rank, of the top-50 producers by `total_votes` (whether
84-
// active or not) and their peer key if populated on-chain.
85-
// -------------------------------------------------------------------------
86-
struct peerkeys_t {
87-
name producer_name;
88-
std::optional<public_key_type> peer_key;
89-
};
90-
using getpeerkeys_res_t = std::vector<peerkeys_t>;
91-
92-
struct peer_info_t {
93-
// rank by `total_votes` of all producers, active or not, may not match schedule rank
94-
uint32_t rank{std::numeric_limits<uint32_t>::max()};
95-
std::optional<public_key_type> key;
96-
97-
bool operator==(const peer_info_t&) const = default;
98-
};
99-
10084
struct controller_impl;
10185
using chainbase::database;
10286
using chainbase::pinnable_mapped_file;
@@ -248,7 +232,6 @@ namespace eosio::chain {
248232
void assemble_and_complete_block( const signer_callback_type& signer_callback );
249233
void sign_block( const signer_callback_type& signer_callback );
250234
void commit_block();
251-
void update_peer_keys(fc::time_point deadline);
252235
void testing_allow_voting(bool val);
253236
bool get_testing_allow_voting_flag();
254237
void set_async_voting(async_t val);
@@ -446,9 +429,11 @@ namespace eosio::chain {
446429

447430
chain_id_type get_chain_id()const;
448431

449-
void set_peer_keys_retrieval_active(bool active);
450-
peer_info_t get_peer_info(name n) const; // thread safe
451-
getpeerkeys_res_t get_top_producer_keys(fc::time_point deadline); // must be called from main thread
432+
void set_peer_keys_retrieval_active(peer_name_set_t configured_bp_peers);
433+
std::optional<peer_info_t> get_peer_info(name n) const; // thread safe
434+
bool configured_peer_keys_updated(); // thread safe
435+
// used for testing, only call with an active pending block from main thread
436+
getpeerkeys_res_t get_top_producer_keys();
452437

453438
// thread safe
454439
db_read_mode get_read_mode()const;

libraries/chain/include/eosio/chain/peer_keys_db.hpp

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,72 @@
11
#pragma once
22

3-
#include <eosio/chain/controller.hpp>
4-
#include <boost/unordered/unordered_flat_map.hpp>
3+
#include <eosio/chain/types.hpp>
4+
55
#include <fc/mutex.hpp>
66

7+
#include <boost/unordered/unordered_flat_map.hpp>
8+
#include <boost/container/flat_set.hpp>
9+
710
namespace eosio::chain {
811

12+
// vector, sorted by rank, of the top-50 producers by `total_votes` (whether
13+
// active or not) and their peer key if populated on-chain.
14+
// -------------------------------------------------------------------------
15+
struct peerkeys_t {
16+
name producer_name;
17+
std::optional<public_key_type> peer_key;
18+
};
19+
using getpeerkeys_res_t = std::vector<peerkeys_t>;
20+
21+
struct peer_info_t {
22+
// rank by `total_votes` of all producers, active or not, may not match schedule rank
23+
uint32_t rank{std::numeric_limits<uint32_t>::max()};
24+
std::optional<public_key_type> key;
25+
26+
bool operator==(const peer_info_t&) const = default;
27+
};
28+
29+
using peer_key_map_t = boost::unordered_flat_map<name, peer_info_t, std::hash<name>>;
30+
using peer_name_set_t = flat_set<name>;
31+
932
/**
1033
* This class caches the on-chain public keys that BP use to sign the `gossip_bp_peers`
1134
* network message. These public keys are populated using the actions regpeerkey and
1235
* delpeerkey of eos-system-contracts.
1336
*/
1437
class peer_keys_db_t {
1538
public:
16-
using peer_key_map_t = boost::unordered_flat_map<name, peer_info_t, std::hash<name>>;
17-
using new_peers_t = flat_set<name>;
39+
peer_keys_db_t() = default;
1840

19-
peer_keys_db_t();
41+
// called on startup with configured bp peers of the node
42+
void set_active(peer_name_set_t configured_bp_peers) {
43+
_configured_bp_peers = std::move(configured_bp_peers);
44+
_active = true;
45+
}
2046

21-
void set_active(bool b) { _active = b; }
47+
// safe to be called from any thread, _active only modified on startup
48+
bool is_active() const { return _active; }
2249

23-
// must be called from main thread
24-
// return the new peers either:
25-
// - added to the top selected producers (according to "getpeerkeys"_n in system contracts)
26-
// - removed from the top selected producers
27-
// - whose key changed
28-
// since the last call to update_peer_keys
29-
// ---------------------------------------
30-
new_peers_t update_peer_keys(const getpeerkeys_res_t& v);
50+
// must be called from the main thread
51+
// return true if update_peer_keys should be called with new map of peer keys
52+
bool should_update(block_num_type block_num) { return _active && (_last_block_num == 0 || block_num % 120 == 0); }
53+
54+
// must be called from main thread, only call if should_update() returns true
55+
void update_peer_keys(block_num_type block_num, const getpeerkeys_res_t& v);
3156

3257
// safe to be called from any thread
33-
// peers no longer in top selected producers will have a rank of std::numeric_limits<uint32_t>::max()
34-
// ----------------------------------------------------------------------------------
35-
peer_info_t get_peer_info(name n) const;
58+
std::optional<peer_info_t> get_peer_info(name n) const;
3659

37-
private:
38-
std::optional<uint64_t> _get_version(const chainbase::database& db);
60+
// safe to be called from any thread
61+
// returns true if configured bp peers modified, also resets flag so next call returns false until updated again
62+
bool configured_peer_keys_updated();
3963

64+
private:
4065
bool _active = false; // if not active (the default), no update occurs
66+
block_num_type _last_block_num = 0;
67+
peer_name_set_t _configured_bp_peers; // no updates occurs
68+
std::atomic<bool> _configured_bp_peers_updated{false};
69+
4170
mutable fc::mutex _m;
4271
peer_key_map_t _peer_info_map GUARDED_BY(_m);
4372
};

libraries/chain/peer_keys_db.cpp

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,40 @@
33

44
namespace eosio::chain {
55

6-
peer_keys_db_t::peer_keys_db_t() : _active(false) {}
7-
8-
peer_info_t peer_keys_db_t::get_peer_info(name n) const {
6+
std::optional<peer_info_t> peer_keys_db_t::get_peer_info(name n) const {
97
fc::lock_guard g(_m);
108
assert(_active);
119
if (auto it = _peer_info_map.find(n); it != _peer_info_map.end())
12-
return it->second;
13-
return peer_info_t{};
10+
return std::optional<peer_info_t>(it->second);
11+
return std::optional<peer_info_t>{};
12+
}
13+
14+
bool peer_keys_db_t::configured_peer_keys_updated() {
15+
return _configured_bp_peers_updated.exchange(false);
1416
}
1517

16-
peer_keys_db_t::new_peers_t peer_keys_db_t::update_peer_keys(const getpeerkeys_res_t& v) {
17-
if (!_active || v.empty())
18-
return {};
18+
void peer_keys_db_t::update_peer_keys(block_num_type block_num, const getpeerkeys_res_t& v) {
19+
assert(_active);
20+
_last_block_num = block_num;
21+
22+
if (v.empty())
23+
return;
1924

2025
// create hash_map of current top selected producers (according to "getpeerkeys"_n in system contracts)
2126
// ----------------------------------------------------------------------------------------------------
2227
peer_key_map_t current;
2328
for (size_t i=0; i<v.size(); ++i)
2429
current[v[i].producer_name] = peer_info_t{static_cast<uint32_t>(i), v[i].peer_key};
2530

31+
bool configured_bp_peers_updated = false;
2632
fc::lock_guard g(_m);
27-
new_peers_t res;
2833

2934
// remove those that aren't among the top producers anymore
3035
// --------------------------------------------------------
3136
for (auto it = _peer_info_map.begin(); it != _peer_info_map.end(); ) {
3237
if (!current.contains(it->first)) {
33-
res.insert(it->first);
38+
if (_configured_bp_peers.contains(it->first))
39+
configured_bp_peers_updated = true;
3440
it = _peer_info_map.erase(it);
3541
} else {
3642
++it;
@@ -42,11 +48,13 @@ peer_keys_db_t::new_peers_t peer_keys_db_t::update_peer_keys(const getpeerkeys_r
4248
for (auto& pi : current) {
4349
if (!_peer_info_map.contains(pi.first) || _peer_info_map[pi.first] != pi.second) {
4450
_peer_info_map[pi.first] = pi.second;
45-
res.insert(pi.first);
51+
if (_configured_bp_peers.contains(pi.first))
52+
configured_bp_peers_updated = true;
4653
}
4754
}
48-
49-
return res;
55+
56+
if (configured_bp_peers_updated)
57+
_configured_bp_peers_updated = true;
5058
}
5159

5260
} // namespace eosio::chain

libraries/libfc/include/fc/crypto/signature.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ namespace fc { namespace crypto {
3030
explicit signature(const std::string& base58str);
3131
std::string to_string(const fc::yield_function_t& yield = fc::yield_function_t()) const;
3232

33+
constexpr bool is_webauthn() const { return _storage.index() == fc::get_index<storage_type, webauthn::signature>(); }
34+
3335
size_t which() const;
3436

3537
size_t variable_size() const;

0 commit comments

Comments
 (0)