Kagome
Polkadot Runtime Engine in C++17
environment_impl.cpp
Go to the documentation of this file.
1 
7 
8 #include <boost/optional/optional_io.hpp>
9 #include <utility>
10 
15 #include "primitives/common.hpp"
16 #include "scale/scale.hpp"
17 
19 
23  using primitives::Justification;
24 
26  std::shared_ptr<blockchain::BlockTree> block_tree,
27  std::shared_ptr<blockchain::BlockHeaderRepository> header_repository,
28  std::shared_ptr<authority::AuthorityManager> authority_manager,
29  std::shared_ptr<network::GrandpaTransmitter> transmitter)
30  : block_tree_{std::move(block_tree)},
31  header_repository_{std::move(header_repository)},
32  authority_manager_{std::move(authority_manager)},
33  transmitter_{std::move(transmitter)},
34  logger_{log::createLogger("GrandpaEnvironment", "grandpa")} {
35  BOOST_ASSERT(block_tree_ != nullptr);
36  BOOST_ASSERT(header_repository_ != nullptr);
37  BOOST_ASSERT(authority_manager_ != nullptr);
38  BOOST_ASSERT(transmitter_ != nullptr);
39  }
40 
41  outcome::result<bool> EnvironmentImpl::hasBlock(
42  const primitives::BlockHash &block) const {
43  return block_tree_->hasBlockHeader(block);
44  }
45 
46  outcome::result<std::vector<BlockHash>> EnvironmentImpl::getAncestry(
47  const BlockHash &base, const BlockHash &block) const {
48  // if base equal to block, then return list with single block
49  if (base == block) {
50  return std::vector<BlockHash>{base};
51  }
52 
53  OUTCOME_TRY(chain, block_tree_->getChainByBlocks(base, block));
54  std::reverse(chain.begin(), chain.end());
55  return std::move(chain);
56  }
57 
59  const BlockHash &block) const {
60  return base == block || block_tree_->hasDirectChain(base, block);
61  }
62 
63  outcome::result<BlockInfo> EnvironmentImpl::bestChainContaining(
64  const BlockHash &base,
65  std::optional<VoterSetId> voter_set_id) const {
66  SL_DEBUG(logger_, "Finding best chain containing block {}", base);
67  OUTCOME_TRY(best_block, block_tree_->getBestContaining(base, std::nullopt));
68 
69  // Select best block with actual set_id
70  if (voter_set_id.has_value()) {
71  while (true) {
72  OUTCOME_TRY(header,
73  header_repository_->getBlockHeader(best_block.hash));
74  BlockInfo parent_block{header.number - 1, header.parent_hash};
75 
76  auto voter_set = authority_manager_->authorities(
77  parent_block, IsBlockFinalized{true});
78 
79  if (voter_set.has_value()
80  && voter_set.value()->id == voter_set_id.value()) {
81  // found
82  break;
83  }
84 
85  best_block = parent_block;
86  }
87  }
88 
89  SL_DEBUG(logger_, "Found best chain: {}", best_block);
90  return std::move(best_block);
91  }
92 
93  outcome::result<void> EnvironmentImpl::onCatchUpRequested(
94  const libp2p::peer::PeerId &peer_id,
95  VoterSetId set_id,
96  RoundNumber round_number) {
97  network::CatchUpRequest message{.round_number = round_number,
98  .voter_set_id = set_id};
99  transmitter_->sendCatchUpRequest(peer_id, std::move(message));
100  return outcome::success();
101  }
102 
103  outcome::result<void> EnvironmentImpl::onCatchUpRespond(
104  const libp2p::peer::PeerId &peer_id,
105  VoterSetId set_id,
106  RoundNumber round_number,
107  std::vector<SignedPrevote> prevote_justification,
108  std::vector<SignedPrecommit> precommit_justification,
109  BlockInfo best_final_candidate) {
110  SL_DEBUG(logger_, "Send Catch-Up-Response upto round {}", round_number);
111  network::CatchUpResponse message{
112  .voter_set_id = set_id,
113  .round_number = round_number,
114  .prevote_justification = std::move(prevote_justification),
115  .precommit_justification = std::move(precommit_justification),
116  .best_final_candidate = best_final_candidate};
117  transmitter_->sendCatchUpResponse(peer_id, std::move(message));
118  return outcome::success();
119  }
120 
121  outcome::result<void> EnvironmentImpl::onVoted(RoundNumber round,
122  VoterSetId set_id,
123  const SignedMessage &vote) {
124  SL_DEBUG(logger_,
125  "Round #{}: Send {} signed by {} for block {}",
126  round,
127  visit_in_place(
128  vote.message,
129  [&](const Prevote &) { return "prevote"; },
130  [&](const Precommit &) { return "precommit"; },
131  [&](const PrimaryPropose &) { return "primary propose"; }),
132  vote.id,
133  vote.getBlockInfo());
134 
135  network::GrandpaVote message{
136  {.round_number = round, .counter = set_id, .vote = vote}};
137  transmitter_->sendVoteMessage(std::move(message));
138  return outcome::success();
139  }
140 
142  const MovableRoundState &state,
143  VoterSetId voter_set_id) {
144  auto send = [&](const SignedMessage &vote) {
145  SL_DEBUG(logger_,
146  "Round #{}: Send {} signed by {} for block {} (as send state)",
147  state.round_number,
148  visit_in_place(
149  vote.message,
150  [&](const Prevote &) { return "prevote"; },
151  [&](const Precommit &) { return "precommit"; },
152  [&](const PrimaryPropose &) { return "primary propose"; }),
153  vote.id,
154  vote.getBlockInfo());
155 
156  network::GrandpaVote message{{.round_number = state.round_number,
157  .counter = voter_set_id,
158  .vote = vote}};
159  transmitter_->sendVoteMessage(peer_id, std::move(message));
160  };
161 
162  for (const auto &vv : state.votes) {
163  visit_in_place(
164  vv,
165  [&](const SignedMessage &vote) { send(vote); },
166  [&](const EquivocatorySignedMessage &pair_vote) {
167  send(pair_vote.first);
168  send(pair_vote.second);
169  });
170  }
171  }
172 
173  outcome::result<void> EnvironmentImpl::onCommitted(
174  RoundNumber round,
175  VoterSetId voter_ser_id,
176  const BlockInfo &vote,
177  const GrandpaJustification &justification) {
178  if (round == 0) {
179  return outcome::success();
180  }
181 
182  SL_DEBUG(logger_, "Round #{}: Send commit of block {}", round, vote);
183 
185  .round = round,
186  .set_id = voter_ser_id,
187  .message = {.target_hash = vote.hash, .target_number = vote.number}};
188  for (const auto &item : justification.items) {
189  BOOST_ASSERT(item.is<Precommit>());
190  const auto &precommit = boost::relaxed_get<Precommit>(item.message);
191  message.message.precommits.push_back(precommit);
192  message.message.auth_data.emplace_back(item.signature, item.id);
193  }
194  transmitter_->sendCommitMessage(std::move(message));
195 
196  return outcome::success();
197  }
198 
200  RoundNumber round, VoterSetId set_id, BlockNumber last_finalized) {
201  SL_DEBUG(logger_, "Round #{}: Send neighbor message", round);
202 
204  .voter_set_id = set_id,
205  .last_finalized = last_finalized};
206  transmitter_->sendNeighborMessage(std::move(message));
207 
208  return outcome::success();
209  }
210 
211  outcome::result<void> EnvironmentImpl::applyJustification(
212  const BlockInfo &block_info,
213  const primitives::Justification &raw_justification) {
214  auto justification_observer = justification_observer_.lock();
215  BOOST_ASSERT(justification_observer);
216 
217  OUTCOME_TRY(
218  justification,
219  scale::decode<grandpa::GrandpaJustification>(raw_justification.data));
220 
221  SL_DEBUG(logger_,
222  "Trying to apply justification on round #{} for block {}",
223  justification.round_number,
224  justification.block_info);
225 
226  OUTCOME_TRY(
227  justification_observer->applyJustification(block_info, justification));
228 
229  return outcome::success();
230  }
231 
232  outcome::result<void> EnvironmentImpl::finalize(
233  VoterSetId id, const GrandpaJustification &grandpa_justification) {
234  primitives::Justification justification;
235  OUTCOME_TRY(enc, scale::encode(grandpa_justification));
236  justification.data.put(enc);
237  OUTCOME_TRY(block_tree_->finalize(grandpa_justification.block_info.hash,
238  justification));
239 
240  return outcome::success();
241  }
242 
243  outcome::result<GrandpaJustification> EnvironmentImpl::getJustification(
244  const BlockHash &block_hash) {
245  OUTCOME_TRY(encoded_justification,
246  block_tree_->getBlockJustification(block_hash));
247 
248  OUTCOME_TRY(
249  grandpa_justification,
250  scale::decode<GrandpaJustification>(encoded_justification.data));
251 
252  return outcome::success(std::move(grandpa_justification));
253  }
254 
255 } // namespace kagome::consensus::grandpa
outcome::result< std::vector< primitives::BlockHash > > getAncestry(const primitives::BlockHash &base, const primitives::BlockHash &block) const override
Get the ancestry of a {.
Tagged< bool, struct IsBlockFinalizedTag > IsBlockFinalized
outcome::result< void > finalize(VoterSetId id, const GrandpaJustification &justification) override
outcome::result< void > onCatchUpRespond(const libp2p::peer::PeerId &peer_id, VoterSetId set_id, RoundNumber round_number, std::vector< SignedPrevote > prevote_justification, std::vector< SignedPrecommit > precommit_justification, BlockInfo best_final_candidate) override
std::vector< SignedPrecommit > items
Definition: structs.hpp:156
outcome::result< void > onVoted(RoundNumber round, VoterSetId set_id, const SignedMessage &vote) override
bool hasAncestry(const primitives::BlockHash &base, const primitives::BlockHash &block) const override
Check if block is ancestor for second one.
EnvironmentImpl(std::shared_ptr< blockchain::BlockTree > block_tree, std::shared_ptr< blockchain::BlockHeaderRepository > header_repository, std::shared_ptr< authority::AuthorityManager > authority_manager, std::shared_ptr< network::GrandpaTransmitter > transmitter)
uint32_t BlockNumber
Definition: common.hpp:18
outcome::result< void > applyJustification(const BlockInfo &block_info, const primitives::Justification &justification) override
outcome::result< void > onNeighborMessageSent(RoundNumber round, VoterSetId set_id, BlockNumber last_finalized) override
libp2p::peer::PeerId PeerId
SLBuffer & put(std::string_view view)
Put a string into byte buffer.
Definition: buffer.hpp:117
primitives::BlockNumber BlockNumber
Definition: common.hpp:24
std::shared_ptr< blockchain::BlockHeaderRepository > header_repository_
std::shared_ptr< authority::AuthorityManager > authority_manager_
common::Hash256 BlockHash
Definition: block_id.hpp:15
std::weak_ptr< JustificationObserver > justification_observer_
std::pair< SignedMessage, SignedMessage > EquivocatorySignedMessage
Definition: structs.hpp:94
outcome::result< void > onCatchUpRequested(const libp2p::peer::PeerId &peer_id, VoterSetId set_id, RoundNumber round_number) override
Stores the current state of the round.
outcome::result< BlockInfo > bestChainContaining(const primitives::BlockHash &base, std::optional< VoterSetId > voter_set_id) const override
outcome::result< GrandpaJustification > getJustification(const BlockHash &block_hash) override
Logger createLogger(const std::string &tag)
Definition: logger.cpp:112
void sendState(const libp2p::peer::PeerId &peer_id, const MovableRoundState &state, VoterSetId voter_set_id) override
std::shared_ptr< network::GrandpaTransmitter > transmitter_
std::shared_ptr< blockchain::BlockTree > block_tree_
outcome::result< bool > hasBlock(const primitives::BlockHash &block) const override
Checks if {.
outcome::result< void > onCommitted(RoundNumber round, VoterSetId voter_ser_id, const BlockInfo &vote, const GrandpaJustification &justification) override
Tagged< bool, struct IsBlockFinalizedTag > IsBlockFinalized