Kagome
Polkadot Runtime Engine in C++17
sync_protocol_observer_impl.cpp
Go to the documentation of this file.
1 
7 
8 #include <boost/assert.hpp>
9 
11 #include "network/common.hpp"
13 #include "primitives/common.hpp"
14 
17  e) {
19  switch (e) {
20  case E::DUPLICATE_REQUEST_ID:
21  return "Request with a same id is handling right now";
22  }
23  return "unknown error";
24 }
25 
26 namespace kagome::network {
27 
29  std::shared_ptr<blockchain::BlockTree> block_tree,
30  std::shared_ptr<blockchain::BlockHeaderRepository> blocks_headers)
31  : block_tree_{std::move(block_tree)},
32  blocks_headers_{std::move(blocks_headers)},
33  log_(log::createLogger("SyncProtocolObserver", "network")) {
34  BOOST_ASSERT(block_tree_);
35  BOOST_ASSERT(blocks_headers_);
36  }
37 
38  outcome::result<network::BlocksResponse>
40  const BlocksRequest &request) const {
41  auto request_id = request.fingerprint();
42  if (!requested_ids_.emplace(request_id).second) {
44  }
45 
46  BlocksResponse response;
47 
48  // firstly, check if we have both "from" & "to" blocks (if set)
49  auto from_hash_res = blocks_headers_->getHashById(request.from);
50  if (not from_hash_res.has_value()) {
51  log_->warn("cannot find a requested block with id {}", request.from);
52  requested_ids_.erase(request_id);
53  return response;
54  }
55  const auto &from_hash = from_hash_res.value();
56 
57  // secondly, retrieve hashes of blocks the other peer is interested in
58  auto chain_hash_res = retrieveRequestedHashes(request, from_hash);
59  if (not chain_hash_res.has_value()) {
60  log_->warn("cannot retrieve a chain of blocks: {}",
61  chain_hash_res.error().message());
62  requested_ids_.erase(request_id);
63  return response;
64  }
65  const auto &chain_hash = chain_hash_res.value();
66 
67  // thirdly, fill the resulting response with data, which we were asked for
68  fillBlocksResponse(request, response, chain_hash);
69  if (response.blocks.empty()) {
70  SL_DEBUG(log_, "Return response id={}: no blocks", request_id);
71  } else if (response.blocks.size() == 1) {
72  if (response.blocks.front().header.has_value()) {
73  SL_DEBUG(log_,
74  "Return response id={}: {}, count 1",
75  request_id,
76  primitives::BlockInfo(response.blocks.front().header->number,
77  response.blocks.front().hash));
78  } else {
79  SL_DEBUG(log_,
80  "Return response id={}: {}, count 1",
81  request_id,
82  response.blocks.front().hash);
83  }
84  } else {
85  if (response.blocks.front().header.has_value()
86  and response.blocks.back().header.has_value()) {
87  SL_DEBUG(log_,
88  "Return response id={}: from {} to {}, count {}",
89  request_id,
90  primitives::BlockInfo(response.blocks.front().header->number,
91  response.blocks.front().hash),
92  primitives::BlockInfo(response.blocks.back().header->number,
93  response.blocks.back().hash),
94  response.blocks.size());
95  } else {
96  SL_DEBUG(log_,
97  "Return response id={}: from {} to {}, count {}",
98  request_id,
99  response.blocks.front().hash,
100  response.blocks.back().hash,
101  response.blocks.size());
102  }
103  }
104 
105  requested_ids_.erase(request_id);
106  return response;
107  }
108 
111  const BlocksRequest &request,
112  const primitives::BlockHash &from_hash) const {
113  auto direction = request.direction == network::Direction::ASCENDING
116  blockchain::BlockTree::BlockHashVecRes chain_hash_res{{}};
117 
118  uint32_t request_count =
120  if (request.max.has_value()) {
121  request_count = std::clamp(
122  request.max.value(),
125  }
126 
127  // Note: request.to is not used in substrate
128 
129  switch (direction) {
131  OUTCOME_TRY(
132  chain_hash,
133  block_tree_->getBestChainFromBlock(from_hash, request_count));
134  return std::move(chain_hash);
135  }
137  OUTCOME_TRY(
138  chain_hash,
139  block_tree_->getDescendingChainToBlock(from_hash, request_count));
140  return std::move(chain_hash);
141  }
142  default:
143  BOOST_UNREACHABLE_RETURN({});
144  }
145  }
146 
148  const BlocksRequest &request,
149  BlocksResponse &response,
150  const std::vector<primitives::BlockHash> &hash_chain) const {
151  auto header_needed =
153  auto body_needed = request.attributeIsSet(network::BlockAttribute::BODY);
154  auto justification_needed =
156 
157  for (const auto &hash : hash_chain) {
158  auto &new_block =
159  response.blocks.emplace_back(primitives::BlockData{hash});
160 
161  if (header_needed) {
162  auto header_res = blocks_headers_->getBlockHeader(hash);
163  if (header_res) {
164  new_block.header = std::move(header_res.value());
165  } else {
166  response.blocks.pop_back();
167  break;
168  }
169  }
170  if (body_needed) {
171  auto body_res = block_tree_->getBlockBody(hash);
172  if (body_res) {
173  new_block.body = std::move(body_res.value());
174  } else {
175  response.blocks.pop_back();
176  break;
177  }
178  }
179  if (justification_needed) {
180  auto justification_res = block_tree_->getBlockJustification(hash);
181  if (justification_res) {
182  new_block.justification = std::move(justification_res.value());
183  }
184  }
185  }
186  }
187 } // namespace kagome::network
blockchain::BlockTree::BlockHashVecRes retrieveRequestedHashes(const network::BlocksRequest &request, const primitives::BlockHash &from_hash) const
Include a justification for the block.
OUTCOME_CPP_DEFINE_CATEGORY(kagome::network, SyncProtocolObserverImpl::Error, e)
bool attributeIsSet(const BlockAttribute &attribute) const
std::shared_ptr< blockchain::BlockTree > block_tree_
static constexpr uint32_t kAbsolutMinBlocksInResponse
static constexpr uint32_t kAbsolutMaxBlocksInResponse
outcome::result< std::vector< primitives::BlockHash >> BlockHashVecRes
Definition: block_tree.hpp:32
primitives::BlockId from
start from this block
outcome::result< BlocksResponse > onBlocksRequest(const BlocksRequest &request) const override
SyncProtocolObserverImpl(std::shared_ptr< blockchain::BlockTree > block_tree, std::shared_ptr< blockchain::BlockHeaderRepository > blocks_headers)
std::unordered_set< BlocksRequest::Fingerprint > requested_ids_
Logger createLogger(const std::string &tag)
Definition: logger.cpp:112
Fingerprint fingerprint() const
std::optional< uint32_t > max
void fillBlocksResponse(const network::BlocksRequest &request, network::BlocksResponse &response, const std::vector< primitives::BlockHash > &hash_chain) const
Direction direction
sequence direction
common::SLVector< primitives::BlockData, kMaxBlocksInResponse > blocks
std::shared_ptr< blockchain::BlockHeaderRepository > blocks_headers_