23 constexpr
auto blockHeightMetricName =
"kagome_block_height";
24 constexpr
auto knownChainLeavesMetricName =
"kagome_number_leaves";
34 outcome::result<std::set<primitives::BlockInfo>> loadLeaves(
35 const std::shared_ptr<BlockStorage> &storage,
36 const std::shared_ptr<BlockHeaderRepository> &header_repo,
38 BOOST_ASSERT(storage !=
nullptr);
39 BOOST_ASSERT(header_repo !=
nullptr);
41 std::set<primitives::BlockInfo> block_tree_leaves;
43 OUTCOME_TRY(block_tree_unordered_leaves, storage->getBlockTreeLeaves());
45 "List of leaves has loaded: {} leaves",
46 block_tree_unordered_leaves.size());
48 BOOST_ASSERT_MSG(not block_tree_unordered_leaves.empty(),
49 "Must be known or calculated at least one leaf");
51 for (
auto &hash : block_tree_unordered_leaves) {
52 auto res = header_repo->getNumberById(hash);
53 if (res.has_error()) {
57 SL_TRACE(log,
"Leaf {} not found", hash);
61 log,
"Leaf {} is corrupted: {}", hash, res.error().message());
62 return res.as_failure();
64 auto number = res.value();
66 block_tree_leaves.emplace(number, hash);
70 if (block_tree_leaves.empty()) {
71 SL_WARN(log,
"No one leaf was found. Trying to repair");
74 auto lower = std::numeric_limits<primitives::BlockNumber>::min();
75 auto upper = std::numeric_limits<primitives::BlockNumber>::max();
78 number = lower + (upper - lower) / 2;
80 auto res = storage->hasBlockHeader(number);
81 if (res.has_failure()) {
83 log,
"Search best block has failed: {}", res.error().message());
88 SL_TRACE(log,
"bisect {} -> found", number);
91 SL_TRACE(log,
"bisect {} -> not found", number);
100 OUTCOME_TRY(hash, header_repo->getHashById(number));
101 block_tree_leaves.emplace(number, hash);
103 if (
auto res = storage->setBlockTreeLeaves({hash}); res.has_error()) {
105 "Can't save recovered block tree leaves: {}",
106 res.error().message());
107 return res.as_failure();
111 return block_tree_leaves;
116 std::shared_ptr<BlockHeaderRepository> header_repo,
117 std::shared_ptr<BlockStorage> storage,
118 std::shared_ptr<network::ExtrinsicObserver> extrinsic_observer,
119 std::shared_ptr<crypto::Hasher> hasher,
122 extrinsic_events_engine,
123 std::shared_ptr<subscription::ExtrinsicEventKeyRepository>
124 extrinsic_event_key_repo,
125 std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker,
126 std::shared_ptr<const class JustificationStoragePolicy>
127 justification_storage_policy) {
128 BOOST_ASSERT(storage !=
nullptr);
129 BOOST_ASSERT(header_repo !=
nullptr);
133 OUTCOME_TRY(block_tree_leaves, loadLeaves(storage, header_repo, log));
135 BOOST_ASSERT_MSG(not block_tree_leaves.empty(),
136 "Must be known or calculated at least one leaf");
139 auto least_leaf = *block_tree_leaves.begin();
140 auto best_leaf = *block_tree_leaves.rbegin();
142 OUTCOME_TRY(last_finalized_block_info, storage->getLastFinalized());
145 auto finalized_block_header_res =
146 storage->getBlockHeader(last_finalized_block_info.hash);
147 BOOST_ASSERT_MSG(finalized_block_header_res.has_value()
148 and finalized_block_header_res.value().has_value(),
149 "Initialized block tree must be have finalized block");
150 chain_events_engine->notify(
152 finalized_block_header_res.value().value());
154 OUTCOME_TRY(last_finalized_justification,
155 storage->getJustification(last_finalized_block_info.hash));
157 auto hash_tmp = last_finalized_block_info.hash;
160 std::multimap<primitives::BlockInfo, primitives::BlockHeader> collected;
163 std::unordered_set<primitives::BlockHash> observed;
164 for (
auto &leaf : block_tree_leaves) {
165 for (
auto hash = leaf.hash;;) {
166 if (hash == last_finalized_block_info.hash) {
170 if (not observed.emplace(hash).second) {
174 auto header_res = storage->getBlockHeader(hash);
175 if (header_res.has_error()) {
177 "Can't get header of existing non-finalized block {}: {}",
179 header_res.error().message());
182 auto &header_opt = header_res.value();
183 if (!header_opt.has_value()) {
185 "Can't get header of existing block {}: not found in block " 188 header_res.error().message());
192 const auto &header = header_opt.value();
195 collected.emplace(block, header);
197 hash = header.parent_hash;
203 auto tree = std::make_shared<TreeNode>(
204 last_finalized_block_info.hash, last_finalized_block_info.number,
true);
205 SL_DEBUG(log,
"Last finalized block #{}", tree->depth);
206 auto meta = std::make_shared<TreeMeta>(tree, last_finalized_justification);
211 std::make_unique<CachedTree>(tree, meta),
212 std::move(extrinsic_observer),
214 std::move(chain_events_engine),
215 std::move(extrinsic_events_engine),
216 std::move(extrinsic_event_key_repo),
217 std::move(changes_tracker),
218 std::move(justification_storage_policy));
221 for (
auto &e : collected) {
222 const auto &block = e.first;
223 const auto header = std::move(e.second);
225 auto res = block_tree->addExistingBlock(block.hash, header);
226 if (res.has_error()) {
228 "Can't add existing non-finalized block {} to block tree: {}",
230 res.error().message());
233 log,
"Existing non-finalized block {} is added to block tree", block);
236 return std::shared_ptr<BlockTreeImpl>(block_tree);
241 std::shared_ptr<BlockStorage> storage,
242 std::shared_ptr<BlockHeaderRepository> header_repo,
243 std::shared_ptr<const storage::trie::TrieStorage> trie_storage,
244 std::shared_ptr<blockchain::BlockTree> block_tree) {
245 BOOST_ASSERT(storage !=
nullptr);
246 BOOST_ASSERT(header_repo !=
nullptr);
247 BOOST_ASSERT(trie_storage !=
nullptr);
251 OUTCOME_TRY(block_tree_leaves, loadLeaves(storage, header_repo, log));
253 BOOST_ASSERT_MSG(not block_tree_leaves.empty(),
254 "Must be known or calculated at least one leaf");
257 auto target_block_header_opt_res = storage->getBlockHeader(target_block);
258 if (target_block_header_opt_res.has_error()) {
260 "Can't get header of target block: {}",
261 target_block_header_opt_res.error().message());
262 return target_block_header_opt_res.as_failure();
264 const auto &target_block_header_opt = target_block_header_opt_res.value();
265 if (not target_block_header_opt.has_value()) {
269 const auto &target_block_header = target_block_header_opt.value();
270 const auto &state_root = target_block_header.state_root;
273 if (
auto res = trie_storage->getEphemeralBatchAt(state_root);
276 log,
"Can't get state of target block: {}", res.error().message());
279 "You will need to use `--sync Fast' CLI arg the next time you start");
282 for (
auto it = block_tree_leaves.rbegin(); it != block_tree_leaves.rend();
283 it = block_tree_leaves.rbegin()) {
285 if (target_block_header.number >= block.number) {
289 auto header_opt_res = storage->getBlockHeader(block.hash);
290 if (header_opt_res.has_error()) {
292 "Can't get header of one of removing block: {}",
293 header_opt_res.error().message());
294 return header_opt_res.as_failure();
296 const auto &header_opt = header_opt_res.value();
297 if (not header_opt.has_value()) {
301 const auto &header = header_opt.value();
302 block_tree_leaves.emplace(block.number - 1, header.parent_hash);
303 block_tree_leaves.erase(block);
305 std::vector<primitives::BlockHash> leaves;
306 std::transform(block_tree_leaves.begin(),
307 block_tree_leaves.end(),
308 std::back_inserter(leaves),
309 [](
const auto it) {
return it.hash; });
310 if (
auto res = storage->setBlockTreeLeaves(leaves); res.has_error()) {
312 "Can't save updated block tree leaves: {}",
313 res.error().message());
314 return res.as_failure();
317 if (
auto res = block_tree->removeLeaf(block.hash); res.has_error()) {
319 log,
"Can't remove block {}: {}", block, res.error().message());
320 return res.as_failure();
324 return outcome::success();
328 std::shared_ptr<BlockHeaderRepository> header_repo,
329 std::shared_ptr<BlockStorage> storage,
330 std::unique_ptr<CachedTree> cached_tree,
331 std::shared_ptr<network::ExtrinsicObserver> extrinsic_observer,
332 std::shared_ptr<crypto::Hasher> hasher,
335 extrinsic_events_engine,
336 std::shared_ptr<subscription::ExtrinsicEventKeyRepository>
337 extrinsic_event_key_repo,
338 std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker,
339 std::shared_ptr<const JustificationStoragePolicy>
340 justification_storage_policy)
343 tree_{std::move(cached_tree)},
353 BOOST_ASSERT(
tree_ !=
nullptr);
355 BOOST_ASSERT(
hasher_ !=
nullptr);
365 "Block height info of the chain");
368 blockHeightMetricName, {{
"status",
"best"}});
370 tree_->getMetadata().deepest_leaf.lock()->depth);
373 blockHeightMetricName, {{
"status",
"finalized"}});
375 tree_->getMetadata().last_finalized.lock()->depth);
378 knownChainLeavesMetricName,
"Number of known chain leaves (aka forks)");
393 BOOST_ASSERT_MSG(res.has_value(),
394 "Block tree must contain at least genesis block");
396 const_cast<std::decay_t<decltype(genesis_block_hash_)> &
>(
398 .emplace(res.value());
408 OUTCOME_TRY(block_hash,
storage_->putBlockHeader(header));
410 std::optional<consensus::EpochDigest> next_epoch;
412 digest.has_value()) {
413 next_epoch.emplace(std::move(digest.value()));
418 std::make_shared<TreeNode>(block_hash, header.
number, parent);
420 tree_->updateMeta(new_node);
425 storage_->setBlockTreeLeaves({tree_->getMetadata().leaves.begin(),
426 tree_->getMetadata().leaves.end()}));
430 tree_->getMetadata().deepest_leaf.lock()->depth);
435 return outcome::success();
447 OUTCOME_TRY(block_hash,
storage_->putBlock(block));
449 std::optional<consensus::EpochDigest> next_epoch;
451 digest.has_value()) {
452 next_epoch.emplace(std::move(digest.value()));
457 std::make_shared<TreeNode>(block_hash, block.
header.
number, parent);
459 tree_->updateMeta(new_node);
464 storage_->setBlockTreeLeaves({tree_->getMetadata().leaves.begin(),
465 tree_->getMetadata().leaves.end()}));
470 for (
const auto &ext : block.
body) {
482 tree_->getMetadata().deepest_leaf.lock()->depth);
484 return outcome::success();
490 if (
tree_->getMetadata().leaves.count(block_hash) == 0) {
494 auto node =
tree_->getRoot().findByHash(block_hash);
495 BOOST_ASSERT_MSG(node !=
nullptr,
496 "As checked before, block exists as one of leaves");
498 if (not node->parent.expired()) {
500 tree_->removeFromMeta(node);
506 auto hash_res =
header_repo_->getHashByNumber(node->depth - 1);
507 BOOST_ASSERT_MSG(hash_res.has_value(),
508 "Non genesis block must have parent");
511 auto tree = std::make_shared<TreeNode>(block.hash, block.number,
true);
512 auto meta = std::make_shared<TreeMeta>(tree, std::nullopt);
513 tree_ = std::make_unique<CachedTree>(std::move(tree), std::move(meta));
517 OUTCOME_TRY(
storage_->removeBlock({node->depth, node->block_hash}));
520 storage_->setBlockTreeLeaves({tree_->getMetadata().leaves.begin(),
521 tree_->getMetadata().leaves.end()}));
523 return outcome::success();
530 "Trying to add block {} into block tree",
533 auto node =
tree_->getRoot().findByHash(block_hash);
535 if (node !=
nullptr) {
537 "Block {} exists in block tree",
545 if (parent ==
nullptr) {
547 "Block {} parent of {} has not found in block tree. " 548 "Trying to restore missed branch",
554 std::stack<std::pair<primitives::BlockHash, primitives::BlockHeader>>
558 OUTCOME_TRY(header_opt,
storage_->getBlockHeader(hash));
559 if (not header_opt.has_value()) {
563 auto &header = header_opt.value();
565 "Block {} has found in storage and enqueued to add",
568 to_add.emplace(hash, std::move(header));
570 if (
tree_->getRoot().findByHash(header.parent_hash) !=
nullptr) {
572 "Block {} parent of {} has found in block tree",
580 "Block {} has not found in block tree. " 581 "Trying to restore from storage",
584 hash = header.parent_hash;
587 while (not to_add.empty()) {
588 const auto &[hash, header] = to_add.top();
594 BOOST_ASSERT_MSG(parent !=
nullptr,
595 "Parent must be restored at this moment");
598 "Trying to add block {} into block tree",
602 std::optional<consensus::EpochDigest> next_epoch;
604 digest.has_value()) {
605 next_epoch.emplace(std::move(digest.value()));
610 std::make_shared<TreeNode>(block_hash, block_header.
number, parent);
612 tree_->updateMeta(new_node);
617 storage_->setBlockTreeLeaves({tree_->getMetadata().leaves.begin(),
618 tree_->getMetadata().leaves.end()}));
622 tree_->getMetadata().deepest_leaf.lock()->depth);
624 return outcome::success();
632 return storage_->putBlockData(block_number, block_data);
638 auto node =
tree_->getRoot().findByHash(block_hash);
645 return outcome::success();
649 "Finalizing block {}",
652 OUTCOME_TRY(header_opt,
storage_->getBlockHeader(node->block_hash));
653 if (!header_opt.has_value()) {
656 auto &header = header_opt.value();
658 auto last_finalized_block_info =
659 tree_->getMetadata().last_finalized.lock()->getBlockInfo();
662 node->finalized =
true;
664 OUTCOME_TRY(
prune(node));
666 tree_->updateTreeRoot(node, justification);
671 storage_->setBlockTreeLeaves({tree_->getMetadata().leaves.begin(),
672 tree_->getMetadata().leaves.end()}));
677 OUTCOME_TRY(body,
storage_->getBlockBody(node->block_hash));
678 if (body.has_value()) {
679 for (
auto &ext : body.value()) {
681 hasher_->blake2b_256(ext.data))) {
685 key.value(), block_hash));
691 log_->info(
"Finalized block {}", finalized_block);
692 telemetry_->notifyBlockFinalized(finalized_block);
698 storage_->putJustification(justification, block_hash, node->depth));
700 "Store justification for finalized block #{} {}",
706 OUTCOME_TRY(last_finalized_header_opt,
707 storage_->getBlockHeader(last_finalized_block_info.number));
709 auto &last_finalized_header = last_finalized_header_opt.value();
711 shouldStoreLastFinalized,
713 if (!shouldStoreLastFinalized) {
714 OUTCOME_TRY(justification_opt,
715 storage_->getJustification(last_finalized_block_info.hash));
716 if (justification_opt.has_value()) {
718 "Purge redundant justification for finalized block {}",
719 last_finalized_block_info);
720 OUTCOME_TRY(
storage_->removeJustification(
721 last_finalized_block_info.hash, last_finalized_block_info.number));
727 return outcome::success();
732 return storage_->hasBlockHeader(block);
737 OUTCOME_TRY(header,
storage_->getBlockHeader(block));
738 if (header.has_value())
return header.value();
744 OUTCOME_TRY(body,
storage_->getBlockBody(block));
745 if (body.has_value())
return body.value();
749 outcome::result<primitives::Justification>
751 OUTCOME_TRY(justification,
storage_->getJustification(block));
752 if (justification.has_value())
return justification.value();
758 auto block_number_res =
header_repo_->getNumberByHash(block);
759 if (block_number_res.has_error()) {
760 log_->error(
"cannot retrieve block with hash {}: {}",
762 block_number_res.error().message());
765 auto start_block_number = block_number_res.value();
768 return std::vector{block};
771 auto deepest_leaf =
tree_->getMetadata().deepest_leaf.lock();
772 BOOST_ASSERT(deepest_leaf !=
nullptr);
773 auto current_depth = deepest_leaf->depth;
775 if (start_block_number >= current_depth) {
776 return std::vector{block};
780 std::min<uint64_t>(current_depth - start_block_number + 1, maximum);
783 start_block_number + count - 1;
785 auto finish_block_hash_res =
787 if (finish_block_hash_res.has_error()) {
788 log_->error(
"cannot retrieve block with number {}: {}",
790 finish_block_hash_res.error().message());
793 const auto &finish_block_hash = finish_block_hash_res.value();
796 if (chain.back() != block) {
797 return std::vector{block};
799 std::reverse(chain.begin(), chain.end());
800 return std::move(chain);
805 std::vector<primitives::BlockHash> chain;
807 auto hash = to_block;
810 if (
auto node =
tree_->getRoot().findByHash(hash)) {
811 while (maximum > chain.size()) {
812 auto parent = node->parent.lock();
814 hash = node->block_hash;
817 chain.emplace_back(node->block_hash);
822 while (maximum > chain.size()) {
824 if (header_res.has_error()) {
826 log_->error(
"cannot retrieve block with hash {}: {}",
828 header_res.error().message());
833 const auto &header = header_res.value();
835 chain.emplace_back(hash);
837 if (header.number == 0) {
841 hash = header.parent_hash;
850 OUTCOME_TRY(from,
header_repo_->getNumberByHash(ancestor));
851 OUTCOME_TRY(to,
header_repo_->getNumberByHash(descendant));
855 auto count = to - from + 1;
857 BOOST_ASSERT(chain.size() == count);
858 if (chain.back() != ancestor) {
861 std::reverse(chain.begin(), chain.end());
862 return std::move(chain);
868 auto ancestor_node_ptr =
tree_->getRoot().findByHash(ancestor);
869 auto descendant_node_ptr =
tree_->getRoot().findByHash(descendant);
880 if (ancestor_node_ptr) {
881 ancestor_depth = ancestor_node_ptr->depth;
883 auto number_res =
header_repo_->getNumberByHash(ancestor);
887 ancestor_depth = number_res.value();
889 if (descendant_node_ptr) {
890 descendant_depth = descendant_node_ptr->depth;
892 auto number_res =
header_repo_->getNumberByHash(descendant);
896 descendant_depth = number_res.value();
898 if (descendant_depth < ancestor_depth) {
900 "Ancestor block is lower. {} in comparison with {}",
908 if (ancestor_node_ptr && descendant_node_ptr) {
909 auto current_node = descendant_node_ptr;
910 while (current_node != ancestor_node_ptr) {
911 if (current_node->depth <= ancestor_node_ptr->depth) {
914 if (
auto parent = current_node->parent; !parent.expired()) {
915 current_node = parent.lock();
927 auto res =
header_repo_->getHashByNumber(descendant_depth);
928 BOOST_ASSERT_MSG(res.has_value(),
929 "Any finalized block must be accessible by number");
931 if (res.value() == descendant) {
933 BOOST_ASSERT_MSG(res.has_value(),
934 "Any finalized block must be accessible by number");
935 if (res.value() == ancestor) {
947 auto current_hash = descendant;
949 while (current_hash != ancestor) {
950 auto current_header_res =
header_repo_->getBlockHeader(current_hash);
951 if (!current_header_res) {
954 if (current_header_res.value().number <= ancestor_depth) {
957 current_hash = current_header_res.value().parent_hash;
964 auto &&leaf =
tree_->getMetadata().deepest_leaf.lock();
965 BOOST_ASSERT(leaf !=
nullptr);
966 return {leaf->depth, leaf->block_hash};
971 const std::optional<primitives::BlockNumber> &max_number)
const {
972 OUTCOME_TRY(target_header,
header_repo_->getBlockHeader(target_hash));
973 if (max_number.has_value() && target_header.number > max_number.value()) {
976 OUTCOME_TRY(canon_hash,
981 if (canon_hash == target_hash) {
982 if (max_number.has_value()) {
983 auto header =
header_repo_->getBlockHeader(max_number.value());
991 OUTCOME_TRY(last_finalized,
993 if (last_finalized >= target_header.number) {
998 auto current_hash = leaf_hash;
999 auto best_hash = current_hash;
1000 if (max_number.has_value()) {
1003 current_hash = hash;
1005 OUTCOME_TRY(best_header,
header_repo_->getBlockHeader(best_hash));
1008 OUTCOME_TRY(current_header,
header_repo_->getBlockHeader(current_hash));
1009 if (current_hash == target_hash) {
1012 current_block_number = current_header.number;
1013 current_hash = current_header.parent_hash;
1014 }
while (current_block_number >= target_header.number);
1018 "Block {} exists in chain but not found when following all leaves " 1019 "backwards. Max block number = {}",
1020 target_hash.
toHex(),
1021 max_number.has_value() ? max_number.value() : -1);
1026 std::vector<primitives::BlockHash> result;
1027 result.reserve(
tree_->getMetadata().leaves.size());
1028 std::transform(
tree_->getMetadata().leaves.begin(),
1029 tree_->getMetadata().leaves.end(),
1030 std::back_inserter(result),
1031 [](
const auto &hash) {
return hash; });
1037 if (
auto node =
tree_->getRoot().findByHash(block); node !=
nullptr) {
1038 std::vector<primitives::BlockHash> result;
1039 result.reserve(node->children.size());
1040 for (
const auto &child : node->children) {
1041 result.push_back(child->block_hash);
1045 OUTCOME_TRY(header,
storage_->getBlockHeader(block));
1048 OUTCOME_TRY(child_hash,
1049 header_repo_->getHashByNumber(header.value().number + 1));
1050 return outcome::success(std::vector<primitives::BlockHash>{child_hash});
1054 const auto &last =
tree_->getMetadata().last_finalized.lock();
1055 BOOST_ASSERT(last !=
nullptr);
1060 std::vector<primitives::BlockInfo> leaf_depths;
1062 leaf_depths.reserve(leaves.size());
1063 for (
auto &leaf : leaves) {
1064 auto leaf_node =
tree_->getRoot().findByHash(leaf);
1065 leaf_depths.emplace_back(
1069 leaf_depths.begin(),
1071 [](
auto const &p1,
auto const &p2) {
return p1.number > p2.number; });
1072 std::vector<primitives::BlockHash> leaf_hashes;
1073 leaf_hashes.reserve(leaf_depths.size());
1074 std::transform(leaf_depths.begin(),
1076 std::back_inserter(leaf_hashes),
1077 [](
auto &p) {
return p.hash; });
1084 auto current_hash = start;
1086 OUTCOME_TRY(current_header,
header_repo_->getBlockHeader(current_hash));
1087 if (current_header.number <= limit) {
1088 return current_hash;
1090 current_hash = current_header.parent_hash;
1095 const std::shared_ptr<TreeNode> &lastFinalizedNode) {
1096 std::deque<std::shared_ptr<TreeNode>> to_remove;
1098 auto following_node = lastFinalizedNode;
1100 for (
auto current_node = following_node->parent.lock();
1101 current_node && !current_node->finalized;
1102 current_node = current_node->parent.lock()) {
1104 to_remove.emplace_back();
1105 std::copy_if(current_node->children.begin(),
1106 current_node->children.end(),
1107 std::back_inserter(to_remove),
1108 [&](
const auto &child) {
return child != following_node; });
1109 auto last = to_remove.back();
1110 while (last !=
nullptr) {
1111 to_remove.pop_back();
1112 std::copy(last->children.begin(),
1113 last->children.end(),
1114 std::back_inserter(to_remove));
1115 to_remove.emplace_front(std::move(last));
1116 last = to_remove.back();
1118 to_remove.pop_back();
1121 current_node->children = {following_node};
1122 following_node = current_node;
1125 std::vector<primitives::Extrinsic> extrinsics;
1128 for (
const auto &node : to_remove) {
1129 OUTCOME_TRY(block_body_res,
storage_->getBlockBody(node->block_hash));
1130 if (block_body_res.has_value()) {
1131 extrinsics.reserve(extrinsics.size() + block_body_res.value().size());
1132 for (
auto &ext : block_body_res.value()) {
1134 hasher_->blake2b_256(ext.data))) {
1138 key.value(), node->block_hash));
1140 extrinsics.emplace_back(std::move(ext));
1144 tree_->removeFromMeta(node);
1145 OUTCOME_TRY(
storage_->removeBlock({node->depth, node->block_hash}));
1149 for (
auto &&extrinsic : extrinsics) {
1152 SL_DEBUG(
log_,
"Tx {} was reapplied", result.value().toHex());
1154 SL_DEBUG(
log_,
"Tx was skipped: {}", result.error().message());
1158 return outcome::success();
1163 if (block.number == 0) {
1164 return outcome::success();
1166 auto hash_res =
header_repo_->getHashByNumber(block.number);
1167 if (hash_res.has_error()) {
1170 return hash_res.as_failure();
1172 }
else if (block.hash == hash_res.value()) {
1173 return outcome::success();
1178 OUTCOME_TRY(
storage_->putNumberToIndexKey(block));
1179 if (block.number == 0)
break;
1181 auto parent_hash_res =
header_repo_->getHashByNumber(block.number - 1);
1182 if (parent_hash_res.has_error()) {
1185 return parent_hash_res.as_failure();
1187 }
else if (header.parent_hash == parent_hash_res.value()) {
1191 block = {block.number - 1, header.parent_hash};
1195 SL_DEBUG(
log_,
"Best chain reorganized for {} blocks deep", count);
1198 return outcome::success();
static outcome::result< std::shared_ptr< BlockTreeImpl > > create(std::shared_ptr< BlockHeaderRepository > header_repo, std::shared_ptr< BlockStorage > storage, std::shared_ptr< network::ExtrinsicObserver > extrinsic_observer, std::shared_ptr< crypto::Hasher > hasher, primitives::events::ChainSubscriptionEnginePtr chain_events_engine, primitives::events::ExtrinsicSubscriptionEnginePtr extrinsic_events_engine, std::shared_ptr< subscription::ExtrinsicEventKeyRepository > extrinsic_event_key_repo, std::shared_ptr< storage::changes_trie::ChangesTracker > changes_tracker, std::shared_ptr< const class JustificationStoragePolicy > justification_storage_policy)
Create an instance of block tree.
outcome::result< primitives::BlockHeader > getBlockHeader(const primitives::BlockId &block) const override
#define KAGOME_PROFILE_END(scope)
std::shared_ptr< BlockStorage > storage_
BlockTreeImpl(std::shared_ptr< BlockHeaderRepository > header_repo, std::shared_ptr< BlockStorage > storage, std::unique_ptr< CachedTree > cached_tree, std::shared_ptr< network::ExtrinsicObserver > extrinsic_observer, std::shared_ptr< crypto::Hasher > hasher, primitives::events::ChainSubscriptionEnginePtr chain_events_engine, primitives::events::ExtrinsicSubscriptionEnginePtr extrinsic_events_engine, std::shared_ptr< subscription::ExtrinsicEventKeyRepository > extrinsic_event_key_repo, std::shared_ptr< storage::changes_trie::ChangesTracker > changes_tracker, std::shared_ptr< const class JustificationStoragePolicy > justification_storage_policy)
BlockHashVecRes getBestChainFromBlock(const primitives::BlockHash &block, uint64_t maximum) const override
outcome::result< void > addBlockBody(primitives::BlockNumber block_number, const primitives::BlockHash &block_hash, const primitives::BlockBody &body) override
virtual void set(double val)=0
Set the gauge to the given value.
static outcome::result< void > recover(primitives::BlockId target_block, std::shared_ptr< BlockStorage > storage, std::shared_ptr< BlockHeaderRepository > header_repo, std::shared_ptr< const storage::trie::TrieStorage > trie_storage, std::shared_ptr< blockchain::BlockTree > block_tree)
Recover block tree state at provided block.
std::vector< Extrinsic > BlockBody
Block class represents polkadot block primitive.
primitives::events::ExtrinsicSubscriptionEnginePtr extrinsic_events_engine_
std::shared_ptr< crypto::Hasher > hasher_
DatabaseError
universal database interface error
std::shared_ptr< const class JustificationStoragePolicy > justification_storage_policy_
static ExtrinsicLifecycleEvent Retracted(SubscribedExtrinsicId id, Hash256Span retracted_block)
primitives::BlockInfo deepestLeaf() const override
outcome::result< EpochDigest > getNextEpochDigest(const primitives::BlockHeader &header)
outcome::result< primitives::BlockHash > walkBackUntilLess(const primitives::BlockHash &start, const primitives::BlockNumber &limit) const
std::vector< primitives::BlockHash > getLeaves() const override
outcome::result< bool > hasBlockHeader(const primitives::BlockId &block) const override
std::vector< primitives::BlockHash > getLeavesSorted() const
metrics::RegistryPtr metrics_registry_
outcome::result< void > prune(const std::shared_ptr< TreeNode > &lastFinalizedNode)
const primitives::BlockHash & getGenesisBlockHash() const override
outcome::result< void > reorganize()
primitives::BlockInfo getLastFinalized() const override
static ExtrinsicLifecycleEvent Finalized(SubscribedExtrinsicId id, Hash256Span block)
SLBuffer< std::numeric_limits< size_t >::max()> Buffer
std::shared_ptr< ChainSubscriptionEngine > ChainSubscriptionEnginePtr
outcome::result< void > addBlock(const primitives::Block &block) override
outcome::result< void > finalize(const primitives::BlockHash &block_hash, const primitives::Justification &justification) override
outcome::result< primitives::BlockBody > getBlockBody(const primitives::BlockId &block) const override
std::shared_ptr< soralog::Logger > Logger
outcome::result< void > removeLeaf(const primitives::BlockHash &block_hash) override
metrics::Gauge * metric_finalized_block_height_
std::unique_ptr< CachedTree > tree_
static ExtrinsicLifecycleEvent InBlock(SubscribedExtrinsicId id, Hash256Span block)
std::shared_ptr< network::ExtrinsicObserver > extrinsic_observer_
std::shared_ptr< storage::changes_trie::ChangesTracker > trie_changes_tracker_
BlockHashVecRes getChainByBlocks(const primitives::BlockHash &ancestor, const primitives::BlockHash &descendant) const override
outcome::result< std::vector< primitives::BlockHash >> BlockHashVecRes
std::optional< primitives::BlockHash > genesis_block_hash_
std::shared_ptr< ExtrinsicSubscriptionEngine > ExtrinsicSubscriptionEnginePtr
std::string toHex() const noexcept
metrics::Gauge * metric_best_block_height_
outcome::result< void > addBlockHeader(const primitives::BlockHeader &header) override
BlockHashVecRes getDescendingChainToBlock(const primitives::BlockHash &block, uint64_t maximum) const override
BlockHashVecRes getChildren(const primitives::BlockHash &block) const override
primitives::events::ChainSubscriptionEnginePtr chain_events_engine_
telemetry::Telemetry telemetry_
std::shared_ptr< subscription::ExtrinsicEventKeyRepository > extrinsic_event_key_repo_
bool hasDirectChain(const primitives::BlockHash &ancestor, const primitives::BlockHash &descendant) const override
boost::variant< BlockHash, BlockNumber > BlockId
Block id is the variant over BlockHash and BlockNumber.
#define KAGOME_PROFILE_START(scope)
outcome::result< primitives::Justification > getBlockJustification(const primitives::BlockId &block) const override
BlockHeader header
block header
Logger createLogger(const std::string &tag)
outcome::result< primitives::BlockInfo > getBestContaining(const primitives::BlockHash &target_hash, const std::optional< primitives::BlockNumber > &max_number) const override
Get the most recent block of the best (longest) chain among those that contain a block with...
primitives::BlockHash hash
BlockBody body
extrinsics collection
metrics::Gauge * metric_known_chain_leaves_
outcome::result< void > addExistingBlock(const primitives::BlockHash &block_hash, const primitives::BlockHeader &block_header) override
std::shared_ptr< BlockHeaderRepository > header_repo_