Kagome
Polkadot Runtime Engine in C++17
babe_config_repository_impl.cpp
Go to the documentation of this file.
1 
7 
9 #include "babe_digests_util.hpp"
12 #include "common/visitor.hpp"
14 #include "crypto/hasher.hpp"
17 #include "scale/scale.hpp"
19 
20 namespace kagome::consensus::babe {
21 
23  const std::shared_ptr<application::AppStateManager> &app_state_manager,
24  std::shared_ptr<storage::BufferStorage> persistent_storage,
25  std::shared_ptr<blockchain::BlockTree> block_tree,
26  std::shared_ptr<blockchain::BlockHeaderRepository> header_repo,
27  std::shared_ptr<runtime::BabeApi> babe_api,
28  std::shared_ptr<crypto::Hasher> hasher,
30  const primitives::GenesisBlockHeader &genesis_block_header,
31  const BabeClock &clock)
32  : persistent_storage_(std::move(persistent_storage)),
33  block_tree_(std::move(block_tree)),
34  header_repo_(std::move(header_repo)),
35  babe_api_(std::move(babe_api)),
36  hasher_(std::move(hasher)),
37  chain_sub_([&] {
38  BOOST_ASSERT(chain_events_engine != nullptr);
39  return std::make_shared<primitives::events::ChainEventSubscriber>(
40  chain_events_engine);
41  }()),
42  genesis_block_hash_(genesis_block_header.hash),
43  clock_(clock),
44  logger_(log::createLogger("BabeConfigRepo", "babe_config_repo")) {
45  BOOST_ASSERT(persistent_storage_ != nullptr);
46  BOOST_ASSERT(block_tree_ != nullptr);
47  BOOST_ASSERT(header_repo_ != nullptr);
48  BOOST_ASSERT(babe_api_ != nullptr);
49  BOOST_ASSERT(hasher_ != nullptr);
50 
51  BOOST_ASSERT(app_state_manager != nullptr);
52  app_state_manager->atPrepare([this] { return prepare(); });
53  }
54 
56  auto load_res = load();
57  if (load_res.has_error()) {
58  SL_VERBOSE(logger_, "Can not load state: {}", load_res.error());
59  return false;
60  }
61 
62  chain_sub_->subscribe(chain_sub_->generateSubscriptionSetId(),
64  chain_sub_->setCallback(
65  [wp = weak_from_this()](
67  auto &&,
71  if (auto self = wp.lock()) {
72  const auto &header =
73  boost::get<primitives::events::HeadsEventParams>(event).get();
74  auto hash =
75  self->hasher_->blake2b_256(scale::encode(header).value());
76 
77  auto save_res = self->save();
78  if (save_res.has_error()) {
79  SL_WARN(self->logger_,
80  "Can not save state at finalization: {}",
81  save_res.error());
82  }
83  self->prune({header.number, hash});
84  }
85  }
86  });
87 
88  return true;
89  }
90 
91  outcome::result<void> BabeConfigRepositoryImpl::load() {
92  const auto finalized_block = block_tree_->getLastFinalized();
93 
94  // First, look up slot number of block number 1 sync epochs
95  if (finalized_block.number > 0) {
96  OUTCOME_TRY(first_block_header, block_tree_->getBlockHeader(1));
97 
98  auto babe_digest_res = consensus::getBabeDigests(first_block_header);
99  BOOST_ASSERT_MSG(babe_digest_res.has_value(),
100  "Any non genesis block must contain babe digest");
101  auto first_slot_number = babe_digest_res.value().second.slot_number;
102 
103  syncEpoch([&] { return std::tuple(first_slot_number, true); });
104  }
105 
106  // 1. Load last state
107  OUTCOME_TRY(encoded_last_state_opt,
108  persistent_storage_->tryLoad(
110 
111  if (encoded_last_state_opt.has_value()) {
112  auto last_state_res = scale::decode<std::shared_ptr<BabeConfigNode>>(
113  encoded_last_state_opt.value());
114 
115  if (last_state_res.has_value()) {
116  auto &last_state = last_state_res.value();
117  if (last_state->block.number <= finalized_block.number) {
118  root_ = std::move(last_state);
119  SL_DEBUG(logger_,
120  "State was initialized by last saved on block {}",
121  root_->block);
122  } else {
123  SL_WARN(
124  logger_,
125  "Last state not match with last finalized; Try to use savepoint");
126  }
127  } else {
128  SL_WARN(
129  logger_, "Can not decode last state: {}", last_state_res.error());
130  std::ignore = persistent_storage_->remove(
132  }
133  }
134 
135  // 2. Load from last control point, if state is still not found
136  if (root_ == nullptr) {
137  for (auto block_number =
138  (finalized_block.number / kSavepointEachSuchBlock)
140  block_number > 0;
141  block_number -= kSavepointEachSuchBlock) {
142  OUTCOME_TRY(encoded_saved_state_opt,
143  persistent_storage_->tryLoad(
145 
146  if (not encoded_saved_state_opt.has_value()) {
147  continue;
148  }
149 
150  auto saved_state_res = scale::decode<std::shared_ptr<BabeConfigNode>>(
151  encoded_saved_state_opt.value());
152 
153  if (saved_state_res.has_error()) {
154  SL_WARN(logger_,
155  "Can not decode state saved on block {}: {}",
156  block_number,
157  saved_state_res.error());
158  std::ignore = persistent_storage_->remove(
160  continue;
161  }
162 
163  root_ = std::move(saved_state_res.value());
164  SL_DEBUG(logger_,
165  "State was initialized by savepoint on block {}",
166  root_->block);
167  break;
168  }
169  }
170 
171  // 3. Load state from genesis, if state is still not found
172  if (root_ == nullptr) {
173  auto babe_config_res = babe_api_->configuration(genesis_block_hash_);
174  if (babe_config_res.has_error()) {
175  SL_WARN(logger_,
176  "Can't get babe config over babe API on genesis block: {}",
177  babe_config_res.error());
178  return babe_config_res.as_failure();
179  }
180  const auto &babe_config = babe_config_res.value();
181 
183  {0, genesis_block_hash_},
184  std::make_shared<const primitives::BabeConfiguration>(babe_config));
185  SL_DEBUG(logger_, "State was initialized by genesis block");
186  }
187 
188  BOOST_ASSERT_MSG(root_ != nullptr, "The root must be initialized by now");
189 
190  // Init slot duration and epoch length
191  auto slot_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
192  root_->config->slot_duration);
193  BOOST_ASSERT_MSG(slot_duration.count() > 0,
194  "Slot duration must be greater zero");
195  const_cast<BabeDuration &>(slot_duration_) = slot_duration;
196  auto epoch_length = root_->config->epoch_length;
197  BOOST_ASSERT_MSG(epoch_length, "Epoch length must be greater zero");
198  const_cast<EpochLength &>(epoch_length_) = epoch_length;
199 
200  // 4. Apply digests before last finalized
201  bool need_to_save = false;
202  for (auto block_number = root_->block.number + 1;
203  block_number <= finalized_block.number;
204  ++block_number) {
205  auto block_header_res = block_tree_->getBlockHeader(block_number);
206  if (block_header_res.has_error()) {
207  SL_WARN(logger_,
208  "Can't get header of some finalized block: {}",
209  block_header_res.error());
210  return block_header_res.as_failure();
211  }
212  const auto &block_header = block_header_res.value();
213  // TODO(xDimon): Would be more efficient to take parent hash of next block
214  auto block_hash =
215  hasher_->blake2b_256(scale::encode(block_header).value());
216  primitives::BlockInfo block_info(block_number, block_hash);
217 
218  for (auto &item : block_header.digest) {
219  auto res = visit_in_place(
220  item,
221  [&](const primitives::PreRuntime &msg) -> outcome::result<void> {
223  OUTCOME_TRY(
224  digest_item,
225  scale::decode<consensus::BabeBlockHeader>(msg.data));
226 
227  return onDigest(block_info, digest_item);
228  }
229  return outcome::success();
230  },
231  [&](const primitives::Consensus &msg) -> outcome::result<void> {
233  OUTCOME_TRY(digest_item,
234  scale::decode<primitives::BabeDigest>(msg.data));
235 
236  return onDigest(block_info, digest_item);
237  }
238  return outcome::success();
239  },
240  [](const auto &) { return outcome::success(); });
241  if (res.has_error()) {
242  SL_WARN(logger_,
243  "Can't apply babe digest of finalized block #{}: {}",
244  block_number,
245  res.error());
246  return res.as_failure();
247  }
248  }
249 
250  prune(block_info);
251 
252  if (block_info.number % (kSavepointEachSuchBlock / 10) == 0) {
253  // Make savepoint
254  auto save_res = save();
255  if (save_res.has_error()) {
256  SL_WARN(logger_, "Can't re-make savepoint: {}", save_res.error());
257  } else {
258  need_to_save = false;
259  }
260  } else {
261  need_to_save = true;
262  }
263  }
264 
265  // Save state on finalized part of blockchain
266  if (need_to_save) {
267  if (auto save_res = save(); save_res.has_error()) {
268  SL_WARN(logger_, "Can't re-save state: {}", save_res.error());
269  }
270  }
271 
272  // 4. Collect and apply digests of non-finalized blocks
273  auto leaves = block_tree_->getLeaves();
274  std::map<primitives::BlockInfo,
275  std::vector<boost::variant<consensus::BabeBlockHeader,
277  digests;
278  // 4.1 Collect digests
279  for (auto &leave_hash : leaves) {
280  for (auto hash = leave_hash;;) {
281  auto block_header_res = block_tree_->getBlockHeader(hash);
282  if (block_header_res.has_error()) {
283  SL_WARN(logger_,
284  "Can't get header of some finalized block: {}",
285  block_header_res.error());
286  return block_header_res.as_failure();
287  }
288  const auto &block_header = block_header_res.value();
289 
290  // This block is finalized
291  if (block_header.number <= finalized_block.number) {
292  break;
293  }
294 
295  primitives::BlockInfo block_info{block_header.number, hash};
296 
297  // This block was meet earlier
298  if (digests.find(block_info) != digests.end()) {
299  break;
300  }
301 
302  auto &digest_of_block = digests[block_info];
303 
304  // Search and collect babe digests
305  for (auto &item : block_header.digest) {
306  auto res = visit_in_place(
307  item,
308  [&](const primitives::PreRuntime &msg) -> outcome::result<void> {
310  auto res =
311  scale::decode<consensus::BabeBlockHeader>(msg.data);
312  if (res.has_error()) {
313  return res.as_failure();
314  }
315  const auto &digest_item = res.value();
316 
317  digest_of_block.emplace_back(digest_item);
318  }
319  return outcome::success();
320  },
321  [&](const primitives::Consensus &msg) -> outcome::result<void> {
322  if (msg.consensus_engine_id == primitives::kBabeEngineId) {
323  auto res = scale::decode<primitives::BabeDigest>(msg.data);
324  if (res.has_error()) {
325  return res.as_failure();
326  }
327  const auto &digest_item = res.value();
328 
329  digest_of_block.emplace_back(digest_item);
330  }
331  return outcome::success();
332  },
333  [](const auto &) { return outcome::success(); });
334  if (res.has_error()) {
335  SL_WARN(logger_,
336  "Can't collect babe digest of non-finalized block {}: {}",
337  block_info,
338  res.error());
339  return res.as_failure();
340  }
341  }
342 
343  hash = block_header.parent_hash;
344  }
345  }
346  // 4.2 Apply digests
347  for (const auto &[block_info_tmp, digests_of_block] : digests) {
348  const auto &block_info = block_info_tmp;
349  for (const auto &digest : digests_of_block) {
350  auto res = visit_in_place(digest, [&](const auto &digest_item) {
351  return onDigest(block_info, digest_item);
352  });
353  if (res.has_error()) {
354  SL_WARN(logger_,
355  "Can't apply babe digest of non-finalized block {}: {}",
356  block_info,
357  res.error());
358  return res.as_failure();
359  }
360  }
361  }
362 
363  prune(finalized_block);
364 
365  return outcome::success();
366  }
367 
368  outcome::result<void> BabeConfigRepositoryImpl::save() {
369  const auto finalized_block = block_tree_->getLastFinalized();
370 
371  BOOST_ASSERT(last_saved_state_block_ <= finalized_block.number);
372 
373  auto saving_state_node = getNode(finalized_block);
374  BOOST_ASSERT_MSG(saving_state_node != nullptr,
375  "Finalized block must have associated node");
376  const auto saving_state_block = saving_state_node->block;
377 
378  // Does not need to save
379  if (last_saved_state_block_ >= saving_state_block.number) {
380  return outcome::success();
381  }
382 
383  const auto last_savepoint =
386 
387  const auto new_savepoint =
388  (saving_state_block.number / kSavepointEachSuchBlock)
390 
391  // It's time to make savepoint
392  if (new_savepoint > last_savepoint) {
393  auto hash_res = header_repo_->getHashByNumber(new_savepoint);
394  if (hash_res.has_value()) {
395  primitives::BlockInfo savepoint_block(new_savepoint, hash_res.value());
396 
397  auto ancestor_node = getNode(savepoint_block);
398  if (ancestor_node != nullptr) {
399  auto node = ancestor_node->block == savepoint_block
400  ? ancestor_node
401  : ancestor_node->makeDescendant(savepoint_block);
402  auto res = persistent_storage_->put(
404  storage::Buffer(scale::encode(node).value()));
405  if (res.has_error()) {
406  SL_WARN(logger_,
407  "Can't make savepoint on block {}: {}",
408  savepoint_block,
409  hash_res.error());
410  return res.as_failure();
411  }
412  SL_DEBUG(logger_, "Savepoint has made on block {}", savepoint_block);
413  }
414  } else {
415  SL_WARN(logger_,
416  "Can't take hash of savepoint block {}: {}",
417  new_savepoint,
418  hash_res.error());
419  }
420  }
421 
422  auto res = persistent_storage_->put(
424  storage::Buffer(scale::encode(saving_state_node).value()));
425  if (res.has_error()) {
426  SL_WARN(logger_,
427  "Can't save last state on block {}: {}",
428  saving_state_block,
429  res.error());
430  return res.as_failure();
431  }
432  SL_DEBUG(logger_, "Last state has saved on block {}", saving_state_block);
433 
434  last_saved_state_block_ = saving_state_block.number;
435 
436  return outcome::success();
437  }
438 
439  std::shared_ptr<const primitives::BabeConfiguration>
441  consensus::EpochNumber epoch_number) {
442  auto node = getNode(block);
443  if (node) {
444  return node->config;
445  }
446  return {};
447  }
448 
450  BOOST_ASSERT_MSG(slot_duration_ != BabeDuration::zero(),
451  "Slot duration is not initialized");
452  return slot_duration_;
453  }
454 
456  BOOST_ASSERT_MSG(epoch_length_ != 0, "Epoch length is not initialized");
457  return epoch_length_;
458  }
459 
460  outcome::result<void> BabeConfigRepositoryImpl::onDigest(
461  const primitives::BlockInfo &block,
462  const consensus::BabeBlockHeader &digest) {
463  EpochNumber epoch_number = slotToEpoch(digest.slot_number);
464 
465  auto node = getNode(block);
466 
467  SL_LOG(logger_,
468  node->epoch != epoch_number ? log::Level::DEBUG : log::Level::TRACE,
469  "BabeBlockHeader babe-digest on block {}: "
470  "slot {}, epoch {}, authority #{}, {}",
471  block,
472  digest.slot_number,
473  epoch_number,
474  digest.authority_index,
475  digest.slotType() == SlotType::Primary ? "primary"
476  : digest.slotType() == SlotType::SecondaryVRF ? "secondary-vrf"
477  : digest.slotType() == SlotType::SecondaryPlain ? "secondary-plain"
478  : "???");
479 
480  if (node->block == block) {
482  }
483 
484  // Create descendant if and only if epoch is changed
485  if (node->epoch != epoch_number) {
486  auto new_node = node->makeDescendant(block, epoch_number);
487 
488  node->descendants.emplace_back(std::move(new_node));
489  }
490 
491  return outcome::success();
492  }
493 
494  outcome::result<void> BabeConfigRepositoryImpl::onDigest(
495  const primitives::BlockInfo &block,
496  const primitives::BabeDigest &digest) {
497  return visit_in_place(
498  digest,
499  [&](const primitives::NextEpochData &msg) -> outcome::result<void> {
500  SL_DEBUG(logger_,
501  "NextEpochData babe-digest on block {}: "
502  "{} authorities, randomness {}",
503  block,
504  msg.authorities.size(),
505  msg.randomness);
506  return onNextEpochData(block, msg);
507  },
508  [&](const primitives::OnDisabled &msg) {
509  SL_TRACE(
510  logger_,
511  "OnDisabled babe-digest on block {}: "
512  "disable authority #{}; ignored (it is checked only by runtime)",
513  block,
514  msg.authority_index);
515  // Implemented sending of OnDisabled events before actually preventing
516  // disabled validators from authoring, so it's possible that there are
517  // blocks on the chain that came from disabled validators (before they
518  // were booted from the set at the end of epoch). Currently, the
519  // runtime prevents disabled validators from authoring (it will just
520  // panic), so we don't do any client-side handling in substrate
521  // https://matrix.to/#/!oZltgdfyakVMtEAWCI:web3.foundation/$hArAlUKaxvquGdaRG9W8ihcsNrO6wD4Q2CQjDIb3MMY?via=web3.foundation&via=matrix.org&via=matrix.parity.io
522  return outcome::success();
523  },
524  [&](const primitives::NextConfigData &msg) {
525  return visit_in_place(
526  msg,
527  [&](const primitives::NextConfigDataV1 &msg) {
528  SL_DEBUG(logger_,
529  "NextConfigData babe-digest on block {}: "
530  "ratio={}/{}, second_slot={}",
531  block,
532  msg.ratio.first,
533  msg.ratio.second,
534  to_string(msg.second_slot));
535  return onNextConfigData(block, msg);
536  },
537  [&](const auto &) {
538  SL_WARN(logger_,
539  "Unsupported NextConfigData babe-digest on block {}: "
540  "variant #{}",
541  block,
542  digest.which());
544  });
545  },
546  [&](auto &) {
547  SL_WARN(logger_,
548  "Unsupported babe-digest on block {}: variant #{}",
549  block,
550  digest.which());
551  throw std::runtime_error("RUN BREAKER");
553  });
554  }
555 
557  const primitives::BlockInfo &block,
558  const primitives::NextEpochData &msg) {
559  auto node = getNode(block);
560 
561  if (node->block != block) {
563  }
564 
565  auto config = node->next_config.value_or(node->config);
566 
567  if (config->authorities != msg.authorities
568  or config->randomness != msg.randomness) {
569  auto new_config =
570  std::make_shared<primitives::BabeConfiguration>(*config);
571  new_config->authorities = msg.authorities;
572  new_config->randomness = msg.randomness;
573  node->next_config = std::move(new_config);
574  }
575 
576  return outcome::success();
577  }
578 
580  const primitives::BlockInfo &block,
581  const primitives::NextConfigDataV1 &msg) {
582  auto node = getNode(block);
583 
584  if (node->block != block) {
586  }
587 
588  auto config = node->next_config.value_or(node->config);
589 
590  if (config->leadership_rate != msg.ratio
591  or config->allowed_slots != msg.second_slot) {
592  auto new_config =
593  std::make_shared<primitives::BabeConfiguration>(*config);
594  new_config->leadership_rate = msg.ratio;
595  new_config->allowed_slots = msg.second_slot;
596  node->next_config = std::move(new_config);
597  }
598 
599  return outcome::success();
600  }
601 
602  std::shared_ptr<BabeConfigNode> BabeConfigRepositoryImpl::getNode(
603  const primitives::BlockInfo &block) const {
604  BOOST_ASSERT(root_ != nullptr);
605 
606  // Target block is not descendant of the current root
607  if (root_->block.number > block.number
608  || (root_->block != block
609  && not directChainExists(root_->block, block))) {
610  return nullptr;
611  }
612 
613  std::shared_ptr<BabeConfigNode> ancestor = root_;
614  while (ancestor->block != block) {
615  bool goto_next_generation = false;
616  for (const auto &node : ancestor->descendants) {
617  if (node->block == block || directChainExists(node->block, block)) {
618  ancestor = node;
619  goto_next_generation = true;
620  break;
621  }
622  }
623  if (not goto_next_generation) {
624  break;
625  }
626  }
627  return ancestor;
628  }
629 
631  const primitives::BlockInfo &ancestor,
632  const primitives::BlockInfo &descendant) const {
633  SL_TRACE(logger_,
634  "Looking if direct chain exists between {} and {}",
635  ancestor,
636  descendant);
637  // Any block is descendant of genesis
638  if (ancestor.number <= 1 && ancestor.number < descendant.number) {
639  return true;
640  }
641  auto result =
642  ancestor.number < descendant.number
643  && block_tree_->hasDirectChain(ancestor.hash, descendant.hash);
644  return result;
645  }
646 
648  if (block == root_->block) {
649  return;
650  }
651 
652  if (block.number < root_->block.number) {
653  return;
654  }
655 
656  auto node = getNode(block);
657 
658  if (not node) {
659  return;
660  }
661 
662  if (node->block != block) {
663  // Reorganize ancestry
664  auto new_node = node->makeDescendant(block);
665  auto descendants = std::move(node->descendants);
666  for (auto &descendant : descendants) {
667  if (directChainExists(block, descendant->block)) {
668  new_node->descendants.emplace_back(std::move(descendant));
669  }
670  }
671  node = std::move(new_node);
672  }
673 
674  root_ = std::move(node);
675 
676  SL_TRACE(logger_, "Prune upto block {}", block);
677  }
678 
680  auto ancestor = getNode(block);
681 
682  if (ancestor == nullptr) {
683  SL_TRACE(logger_, "Can't remove node of block {}: no ancestor", block);
684  return;
685  }
686 
687  if (ancestor == root_) {
688  // Can't remove root
689  SL_TRACE(logger_, "Can't remove node of block {}: it is root", block);
690  return;
691  }
692 
693  if (ancestor->block == block) {
694  ancestor =
695  std::const_pointer_cast<BabeConfigNode>(ancestor->parent.lock());
696  BOOST_ASSERT_MSG(ancestor != nullptr, "Non root node must have a parent");
697  }
698 
699  auto it = std::find_if(ancestor->descendants.begin(),
700  ancestor->descendants.end(),
701  [&block](std::shared_ptr<BabeConfigNode> node) {
702  return node->block == block;
703  });
704 
705  if (it != ancestor->descendants.end()) {
706  if (not(*it)->descendants.empty()) {
707  // Has descendants - is not a leaf
708  SL_TRACE(logger_,
709  "Can't remove node of block {}: "
710  "not found such descendant of ancestor",
711  block);
712  return;
713  }
714 
715  ancestor->descendants.erase(it);
716  SL_DEBUG(logger_, "Node of block {} has removed", block);
717  }
718  }
719 
721  std::function<std::tuple<BabeSlotNumber, bool>()> &&f) {
722  if (not is_first_block_finalized_) {
723  auto [first_block_slot_number, is_first_block_finalized] = f();
724  first_block_slot_number_.emplace(first_block_slot_number);
725  is_first_block_finalized_ = is_first_block_finalized;
726  SL_TRACE(
727  logger_,
728  "Epoch beginning is synchronized: first block slot number is {} now",
729  first_block_slot_number_.value());
730  }
731  return first_block_slot_number_.value();
732  }
733 
735  return static_cast<BabeSlotNumber>(clock_.now().time_since_epoch()
736  / slotDuration());
737  }
738 
740  BabeSlotNumber slot) const {
741  return clock_.zero() + slot * slotDuration();
742  }
743 
745  BabeSlotNumber slot) const {
746  auto deadline = slotStartTime(slot);
747  auto now = clock_.now();
748  if (deadline > now) {
749  return deadline - now;
750  }
751  return BabeDuration{};
752  }
753 
755  BabeSlotNumber slot) const {
756  return slotStartTime(slot + 1);
757  }
758 
760  BabeSlotNumber slot) const {
761  return remainToStartOfSlot(slot + 1);
762  }
763 
765  if (first_block_slot_number_.has_value()) {
766  return first_block_slot_number_.value();
767  }
768 
769  return getCurrentSlot();
770  }
771 
773  auto genesis_slot_number =
774  const_cast<BabeConfigRepositoryImpl &>(*this).getFirstBlockSlotNumber();
775  if (slot > genesis_slot_number) {
776  return (slot - genesis_slot_number) / epochLength();
777  }
778  return 0;
779  }
780 
782  BabeSlotNumber slot) const {
783  auto genesis_slot_number =
784  const_cast<BabeConfigRepositoryImpl &>(*this).getFirstBlockSlotNumber();
785  if (slot > genesis_slot_number) {
786  return (slot - genesis_slot_number) % epochLength();
787  }
788  return 0;
789  }
790 
791 } // namespace kagome::consensus::babe
bool directChainExists(const primitives::BlockInfo &ancestor, const primitives::BlockInfo &descendant) const
Check if one block is direct ancestor of second one.
Class represents arbitrary (including empty) byte buffer.
Definition: buffer.hpp:29
common::Buffer kBabeConfigRepoStateLookupKey(Tag tag)
outcome::result< std::pair< Seal, BabeBlockHeader > > getBabeDigests(const primitives::BlockHeader &block_header)
A secondary deterministic slot assignment.
std::string_view to_string(SlotType s)
Definition: slot.hpp:22
primitives::AuthorityList authorities
The authorities actual for corresponding epoch.
A secondary deterministic slot assignment with VRF outputs.
outcome::result< void > onNextEpochData(const primitives::BlockInfo &block, const primitives::NextEpochData &msg)
STL namespace.
void cancel(const primitives::BlockInfo &block) override
BabeSlotNumber slot_number
slot, in which the block was produced
BabeConfigRepositoryImpl(const std::shared_ptr< application::AppStateManager > &app_state_manager, std::shared_ptr< storage::BufferStorage > persistent_storage, std::shared_ptr< blockchain::BlockTree > block_tree, std::shared_ptr< blockchain::BlockHeaderRepository > header_repo, std::shared_ptr< runtime::BabeApi > babe_api, std::shared_ptr< crypto::Hasher > hasher, primitives::events::ChainSubscriptionEnginePtr chain_events_engine, const primitives::GenesisBlockHeader &genesis_block_header, const BabeClock &clock)
std::shared_ptr< storage::BufferStorage > persistent_storage_
boost::variant< std::nullopt_t, HeadsEventParams, RuntimeVersionEventParams, NewRuntimeEventParams > ChainEventParams
Definition: event_types.hpp:51
static TimePoint zero()
Definition: clock.hpp:42
BabeTimePoint slotFinishTime(BabeSlotNumber slot) const override
std::shared_ptr< const primitives::BabeConfiguration > config(const primitives::BlockInfo &parent_block, consensus::EpochNumber epoch_number) override
BabeDuration remainToFinishOfSlot(BabeSlotNumber slot) const override
std::shared_ptr< ChainSubscriptionEngine > ChainSubscriptionEnginePtr
std::shared_ptr< blockchain::BlockHeaderRepository > header_repo_
outcome::result< void > onNextConfigData(const primitives::BlockInfo &block, const primitives::NextConfigDataV1 &msg)
EpochNumber slotToEpoch(BabeSlotNumber slot) const override
BabeDuration remainToStartOfSlot(BabeSlotNumber slot) const override
std::pair< uint64_t, uint64_t > ratio
outcome::result< void > onDigest(const primitives::BlockInfo &block, const consensus::BabeBlockHeader &digest) override
BabeClock::TimePoint BabeTimePoint
BABE uses system clock&#39;s time points.
Definition: common.hpp:18
boost::variant< Unused< 0 >, NextConfigDataV1 > NextConfigData
std::shared_ptr< primitives::events::ChainEventSubscriber > chain_sub_
BabeSlotNumber slotInEpoch(BabeSlotNumber slot) const override
uint64_t BabeSlotNumber
slot number of the Babe production
Definition: common.hpp:24
primitives::AuthorityIndex authority_index
authority index of the producer
A primary VRF-based slot assignment.
common::SLBuffer< consensus::kMaxValidatorsNumber *1024 > data
Definition: digest.hpp:45
EpochNumber EpochLength
Definition: common.hpp:30
BabeTimePoint slotStartTime(BabeSlotNumber slot) const override
detail::BlockInfoT< struct BlockInfoTag > BlockInfo
Definition: common.hpp:63
const auto kBabeEngineId
Definition: digest.hpp:25
static const primitives::BlockNumber kSavepointEachSuchBlock
boost::variant< Unused< 0 >, NextEpochData, OnDisabled, NextConfigData > BabeDigest
https://github.com/paritytech/substrate/blob/polkadot-v0.9.8/primitives/consensus/babe/src/lib.rs#L130
Definition: digest.hpp:63
Logger createLogger(const std::string &tag)
Definition: logger.cpp:112
static std::shared_ptr< BabeConfigNode > createAsRoot(primitives::BlockInfo block, std::shared_ptr< const primitives::BabeConfiguration > config)
uint64_t EpochNumber
number of the epoch in the Babe production
Definition: common.hpp:27
BabeSlotNumber syncEpoch(std::function< std::tuple< BabeSlotNumber, bool >()> &&f) override
virtual TimePoint now() const =0
BabeClock::Duration BabeDuration
Definition: common.hpp:21
Randomness randomness
The value of randomness to use for the slot-assignment.
std::shared_ptr< BabeConfigNode > getNode(const primitives::BlockInfo &block) const
Find schedule_node according to the block.