Kagome
Polkadot Runtime Engine in C++17
address_publisher.cpp
Go to the documentation of this file.
1 
7 
8 #include "authority_discovery/protobuf/authority_discovery.v2.pb.h"
9 
10 #include "crypto/sha/sha256.hpp"
11 
12 #define _PB_SPAN(f) [&](gsl::span<const uint8_t> a) { (f)(a.data(), a.size()); }
13 #define PB_SPAN_SET(a, b, c) _PB_SPAN((a).set_##b)(c)
14 #define PB_SPAN_ADD(a, b, c) _PB_SPAN((a).add_##b)(c)
15 
16 template <typename T>
17 std::vector<uint8_t> pbEncodeVec(const T &v) {
18  std::vector<uint8_t> r(v.ByteSizeLong());
19  v.SerializeToArray(r.data(), r.size());
20  return r;
21 }
22 
25  std::shared_ptr<runtime::AuthorityDiscoveryApi> authority_discovery_api,
26  network::Roles roles,
27  std::shared_ptr<application::AppStateManager> app_state_manager,
28  std::shared_ptr<blockchain::BlockTree> block_tree,
29  std::shared_ptr<crypto::SessionKeys> keys,
30  const libp2p::crypto::KeyPair &libp2p_key,
31  const libp2p::crypto::marshaller::KeyMarshaller &key_marshaller,
32  std::shared_ptr<crypto::Ed25519Provider> ed_crypto_provider,
33  std::shared_ptr<crypto::Sr25519Provider> sr_crypto_provider,
34  libp2p::Host &host,
35  std::shared_ptr<libp2p::protocol::kademlia::Kademlia> kademlia,
36  std::shared_ptr<libp2p::basic::Scheduler> scheduler)
37  : authority_discovery_api_(std::move(authority_discovery_api)),
38  roles_(roles),
39  block_tree_(std::move(block_tree)),
40  keys_(std::move(keys)),
41  ed_crypto_provider_(std::move(ed_crypto_provider)),
42  sr_crypto_provider_(std::move(sr_crypto_provider)),
43  host_(host),
44  kademlia_(std::move(kademlia)),
45  scheduler_(std::move(scheduler)),
46  log_{log::createLogger("AddressPublisher")} {
47  BOOST_ASSERT(authority_discovery_api_ != nullptr);
48  BOOST_ASSERT(app_state_manager != nullptr);
49  BOOST_ASSERT(block_tree_ != nullptr);
50  BOOST_ASSERT(keys_ != nullptr);
51  BOOST_ASSERT(ed_crypto_provider_ != nullptr);
52  BOOST_ASSERT(sr_crypto_provider_ != nullptr);
53  BOOST_ASSERT(kademlia_ != nullptr);
54  BOOST_ASSERT(scheduler_ != nullptr);
55  app_state_manager->atLaunch([=] { return start(); });
56  if (libp2p_key.privateKey.type == libp2p::crypto::Key::Type::Ed25519) {
58  .secret_key =
59  crypto::Ed25519PrivateKey::fromSpan(libp2p_key.privateKey.data)
60  .value(),
61  .public_key =
62  crypto::Ed25519PublicKey::fromSpan(libp2p_key.publicKey.data)
63  .value(),
64  });
65  libp2p_key_pb_.emplace(
66  key_marshaller.marshal(libp2p_key.publicKey).value());
67  } else {
68  SL_WARN(log_, "Peer key is not ed25519");
69  }
70  }
71 
73  if (not libp2p_key_) {
74  return true;
75  }
76  if (not roles_.flags.authority) {
77  return true;
78  }
79  // TODO(ortyomka): #1358, republish in scheduler with some interval
80  auto maybe_error = publishOwnAddress();
81  if (maybe_error.has_error()) {
82  SL_ERROR(log_, "publishOwnAddress failed: {}", maybe_error.error());
83  }
84  return true;
85  }
86 
87  outcome::result<void> AddressPublisher::publishOwnAddress() {
88  auto addresses = host_.getAddresses();
89  // TODO(turuslan): #1357, filter local addresses
90  if (addresses.empty()) {
91  SL_ERROR(log_, "No listening addresses");
92  return outcome::success();
93  }
94 
95  auto audi_key = keys_->getAudiKeyPair();
96  if (not audi_key) {
97  SL_VERBOSE(log_, "No authority discovery key");
98  return outcome::success();
99  }
100 
101  OUTCOME_TRY(
102  authorities,
103  authority_discovery_api_->authorities(block_tree_->deepestLeaf().hash));
104 
105  if (std::find(authorities.begin(), authorities.end(), audi_key->public_key)
106  == authorities.end()) {
107  // we are not authority
108  return outcome::success();
109  }
110 
111  ::authority_discovery::v2::AuthorityRecord record;
112  for (const auto &address : addresses) {
113  PB_SPAN_ADD(record, addresses, address.getBytesAddress());
114  }
115 
116  auto record_pb = pbEncodeVec(record);
117  OUTCOME_TRY(signature, ed_crypto_provider_->sign(*libp2p_key_, record_pb));
118  OUTCOME_TRY(auth_signature,
119  sr_crypto_provider_->sign(*audi_key, record_pb));
120 
121  ::authority_discovery::v2::SignedAuthorityRecord signed_record;
122  PB_SPAN_SET(signed_record, auth_signature, auth_signature);
123  PB_SPAN_SET(signed_record, record, record_pb);
124  auto &ps = *signed_record.mutable_peer_signature();
125  PB_SPAN_SET(ps, signature, signature);
126  PB_SPAN_SET(ps, public_key, libp2p_key_pb_->key);
127 
128  auto hash = crypto::sha256(audi_key->public_key);
129  return kademlia_->putValue({hash.begin(), hash.end()},
130  pbEncodeVec(signed_record));
131  }
132 } // namespace kagome::authority_discovery
std::optional< crypto::Ed25519Keypair > libp2p_key_
struct kagome::network::Roles::@11 flags
std::shared_ptr< blockchain::BlockTree > block_tree_
#define PB_SPAN_SET(a, b, c)
std::vector< uint8_t > pbEncodeVec(const T &v)
std::shared_ptr< crypto::Ed25519Provider > ed_crypto_provider_
STL namespace.
#define PB_SPAN_ADD(a, b, c)
std::shared_ptr< libp2p::basic::Scheduler > scheduler_
AddressPublisher(std::shared_ptr< runtime::AuthorityDiscoveryApi > authority_discovery_api, network::Roles roles, std::shared_ptr< application::AppStateManager > app_state_manager, std::shared_ptr< blockchain::BlockTree > block_tree, std::shared_ptr< crypto::SessionKeys > keys, const libp2p::crypto::KeyPair &libp2p_key, const libp2p::crypto::marshaller::KeyMarshaller &key_marshaller, std::shared_ptr< crypto::Ed25519Provider > ed_crypto_provider, std::shared_ptr< crypto::Sr25519Provider > sr_crypto_provider, libp2p::Host &host, std::shared_ptr< libp2p::protocol::kademlia::Kademlia > kademlia, std::shared_ptr< libp2p::basic::Scheduler > scheduler)
std::shared_ptr< crypto::SessionKeys > keys_
std::shared_ptr< libp2p::protocol::kademlia::Kademlia > kademlia_
std::optional< libp2p::crypto::ProtobufKey > libp2p_key_pb_
std::shared_ptr< runtime::AuthorityDiscoveryApi > authority_discovery_api_
common::Hash256 sha256(std::string_view input)
Definition: sha256.cpp:11
std::shared_ptr< crypto::Sr25519Provider > sr_crypto_provider_
Logger createLogger(const std::string &tag)
Definition: logger.cpp:112