1use codec::{Decode, Encode};
21use parking_lot::RwLock;
22use sp_core::H256;
23use sp_runtime::{
24 generic::BlockId,
25 traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero},
26 Justifications,
27};
28use std::collections::{btree_set::BTreeSet, HashMap, VecDeque};
29use tracing::{debug, warn};
30
31use crate::{
32 error::{Error, Result},
33 header_metadata::HeaderMetadata,
34 tree_route, CachedHeaderMetadata,
35};
36
37pub trait HeaderBackend<Block: BlockT>: Send + Sync {
39 fn header(&self, hash: Block::Hash) -> Result<Option<Block::Header>>;
41 fn info(&self) -> Info<Block>;
43 fn status(&self, hash: Block::Hash) -> Result<BlockStatus>;
45 fn number(
47 &self,
48 hash: Block::Hash,
49 ) -> Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>>;
50 fn hash(&self, number: NumberFor<Block>) -> Result<Option<Block::Hash>>;
52
53 fn block_hash_from_id(&self, id: &BlockId<Block>) -> Result<Option<Block::Hash>> {
55 match *id {
56 BlockId::Hash(h) => Ok(Some(h)),
57 BlockId::Number(n) => self.hash(n),
58 }
59 }
60
61 fn block_number_from_id(&self, id: &BlockId<Block>) -> Result<Option<NumberFor<Block>>> {
63 match *id {
64 BlockId::Hash(h) => self.number(h),
65 BlockId::Number(n) => Ok(Some(n)),
66 }
67 }
68
69 fn expect_header(&self, hash: Block::Hash) -> Result<Block::Header> {
71 self.header(hash)?
72 .ok_or_else(|| Error::UnknownBlock(format!("Expect header: {}", hash)))
73 }
74
75 fn expect_block_number_from_id(&self, id: &BlockId<Block>) -> Result<NumberFor<Block>> {
78 self.block_number_from_id(id).and_then(|n| {
79 n.ok_or_else(|| Error::UnknownBlock(format!("Expect block number from id: {}", id)))
80 })
81 }
82
83 fn expect_block_hash_from_id(&self, id: &BlockId<Block>) -> Result<Block::Hash> {
86 self.block_hash_from_id(id).and_then(|h| {
87 h.ok_or_else(|| Error::UnknownBlock(format!("Expect block hash from id: {}", id)))
88 })
89 }
90}
91
92pub trait ForkBackend<Block: BlockT>:
94 HeaderMetadata<Block> + HeaderBackend<Block> + Send + Sync
95{
96 fn expand_forks(
104 &self,
105 fork_heads: &[Block::Hash],
106 ) -> std::result::Result<BTreeSet<Block::Hash>, Error> {
107 let mut expanded_forks = BTreeSet::new();
108 for fork_head in fork_heads {
109 match tree_route(self, *fork_head, self.info().finalized_hash) {
110 Ok(tree_route) => {
111 for block in tree_route.retracted() {
112 expanded_forks.insert(block.hash);
113 }
114 continue;
115 },
116 Err(_) => {
117 },
119 }
120 }
121
122 Ok(expanded_forks)
123 }
124}
125
126impl<Block, T> ForkBackend<Block> for T
127where
128 Block: BlockT,
129 T: HeaderMetadata<Block> + HeaderBackend<Block> + Send + Sync,
130{
131}
132
133struct MinimalBlockMetadata<Block: BlockT> {
134 number: NumberFor<Block>,
135 hash: Block::Hash,
136 parent: Block::Hash,
137}
138
139impl<Block> Clone for MinimalBlockMetadata<Block>
140where
141 Block: BlockT,
142{
143 fn clone(&self) -> Self {
144 Self { number: self.number, hash: self.hash, parent: self.parent }
145 }
146}
147
148impl<Block> Copy for MinimalBlockMetadata<Block> where Block: BlockT {}
149
150impl<Block> From<&CachedHeaderMetadata<Block>> for MinimalBlockMetadata<Block>
151where
152 Block: BlockT,
153{
154 fn from(value: &CachedHeaderMetadata<Block>) -> Self {
155 Self { number: value.number, hash: value.hash, parent: value.parent }
156 }
157}
158
159pub trait Backend<Block: BlockT>:
161 HeaderBackend<Block> + HeaderMetadata<Block, Error = Error>
162{
163 fn body(&self, hash: Block::Hash) -> Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
165 fn justifications(&self, hash: Block::Hash) -> Result<Option<Justifications>>;
167 fn last_finalized(&self) -> Result<Block::Hash>;
169
170 fn leaves(&self) -> Result<Vec<Block::Hash>>;
174
175 fn children(&self, parent_hash: Block::Hash) -> Result<Vec<Block::Hash>>;
177
178 fn longest_containing(
187 &self,
188 base_hash: Block::Hash,
189 import_lock: &RwLock<()>,
190 ) -> Result<Option<Block::Hash>> {
191 let Some(base_header) = self.header(base_hash)? else { return Ok(None) };
192
193 let leaves = {
194 let _import_guard = import_lock.read();
198 let info = self.info();
199 if info.finalized_number > *base_header.number() {
200 return Ok(None);
202 }
203 self.leaves()?
204 };
205
206 for leaf_hash in leaves {
208 let mut current_hash = leaf_hash;
209 loop {
211 if current_hash == base_hash {
212 return Ok(Some(leaf_hash));
213 }
214
215 let current_header = self
216 .header(current_hash)?
217 .ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?;
218
219 if current_header.number() < base_header.number() {
221 break;
222 }
223
224 current_hash = *current_header.parent_hash();
225 }
226 }
227
228 warn!(
233 target: crate::LOG_TARGET,
234 "Block {:?} exists in chain but not found when following all leaves backwards",
235 base_hash,
236 );
237
238 Ok(None)
239 }
240
241 fn indexed_transaction(&self, hash: H256) -> Result<Option<Vec<u8>>>;
245
246 fn has_indexed_transaction(&self, hash: H256) -> Result<bool> {
248 Ok(self.indexed_transaction(hash)?.is_some())
249 }
250
251 fn block_indexed_hashes(&self, hash: Block::Hash) -> Result<Option<Vec<H256>>>;
257
258 fn block_indexed_body(&self, hash: Block::Hash) -> Result<Option<Vec<Vec<u8>>>>;
263
264 fn displaced_leaves_after_finalizing(
266 &self,
267 finalized_block_hash: Block::Hash,
268 finalized_block_number: NumberFor<Block>,
269 finalized_block_parent_hash: Block::Hash,
270 ) -> std::result::Result<DisplacedLeavesAfterFinalization<Block>, Error> {
271 if finalized_block_number.is_zero() {
273 return Ok(DisplacedLeavesAfterFinalization::default());
274 }
275
276 let leaves = self.leaves()?;
277
278 let now = std::time::Instant::now();
279 debug!(
280 target: crate::LOG_TARGET,
281 ?leaves,
282 ?finalized_block_hash,
283 ?finalized_block_number,
284 "Checking for displaced leaves after finalization."
285 );
286
287 let mut finalized_chain = VecDeque::new();
290 finalized_chain.push_front(MinimalBlockMetadata {
291 number: finalized_block_number,
292 hash: finalized_block_hash,
293 parent: finalized_block_parent_hash,
294 });
295
296 let mut local_cache = HashMap::<Block::Hash, MinimalBlockMetadata<Block>>::new();
299
300 let mut result = DisplacedLeavesAfterFinalization {
301 displaced_leaves: Vec::with_capacity(leaves.len()),
302 displaced_blocks: Vec::with_capacity(leaves.len()),
303 };
304
305 let mut displaced_blocks_candidates = Vec::new();
306
307 let genesis_hash = self.info().genesis_hash;
308
309 for leaf_hash in leaves {
310 let mut current_header_metadata =
311 MinimalBlockMetadata::from(&self.header_metadata(leaf_hash).map_err(|err| {
312 debug!(
313 target: crate::LOG_TARGET,
314 ?leaf_hash,
315 ?err,
316 elapsed = ?now.elapsed(),
317 "Failed to fetch leaf header.",
318 );
319 err
320 })?);
321 let leaf_number = current_header_metadata.number;
322
323 if leaf_hash == genesis_hash {
325 result.displaced_leaves.push((leaf_number, leaf_hash));
326 debug!(
327 target: crate::LOG_TARGET,
328 ?leaf_hash,
329 elapsed = ?now.elapsed(),
330 "Added genesis leaf to displaced leaves."
331 );
332 continue;
333 }
334
335 debug!(
336 target: crate::LOG_TARGET,
337 ?leaf_number,
338 ?leaf_hash,
339 elapsed = ?now.elapsed(),
340 "Handle displaced leaf.",
341 );
342
343 displaced_blocks_candidates.clear();
345 while current_header_metadata.number > finalized_block_number {
346 displaced_blocks_candidates.push(current_header_metadata.hash);
347
348 let parent_hash = current_header_metadata.parent;
349 match local_cache.get(&parent_hash) {
350 Some(metadata_header) => {
351 current_header_metadata = *metadata_header;
352 },
353 None => {
354 current_header_metadata = MinimalBlockMetadata::from(
355 &self.header_metadata(parent_hash).map_err(|err| {
356 debug!(
357 target: crate::LOG_TARGET,
358 ?err,
359 ?parent_hash,
360 ?leaf_hash,
361 elapsed = ?now.elapsed(),
362 "Failed to fetch parent header during leaf tracking.",
363 );
364
365 err
366 })?,
367 );
368 local_cache.insert(parent_hash, current_header_metadata);
371 },
372 }
373 }
374
375 if current_header_metadata.hash == finalized_block_hash {
378 debug!(
379 target: crate::LOG_TARGET,
380 ?leaf_hash,
381 elapsed = ?now.elapsed(),
382 "Leaf points to the finalized header, skipping for now.",
383 );
384
385 continue;
386 }
387
388 displaced_blocks_candidates.push(current_header_metadata.hash);
392
393 debug!(
394 target: crate::LOG_TARGET,
395 current_hash = ?current_header_metadata.hash,
396 current_num = ?current_header_metadata.number,
397 ?finalized_block_number,
398 elapsed = ?now.elapsed(),
399 "Looking for path from finalized block number to current leaf number"
400 );
401
402 for distance_from_finalized in 1_u32.. {
404 let (finalized_chain_block_number, finalized_chain_block_hash) =
406 match finalized_chain.iter().rev().nth(distance_from_finalized as usize) {
407 Some(header) => (header.number, header.hash),
408 None => {
409 let to_fetch = finalized_chain.front().expect("Not empty; qed");
410 let metadata = match self.header_metadata(to_fetch.parent) {
411 Ok(metadata) => metadata,
412 Err(Error::UnknownBlock(_)) => {
413 debug!(
414 target: crate::LOG_TARGET,
415 distance_from_finalized,
416 hash = ?to_fetch.parent,
417 number = ?to_fetch.number,
418 elapsed = ?now.elapsed(),
419 "Tried to fetch unknown block, block ancestry has gaps."
420 );
421 break;
422 },
423 Err(err) => {
424 debug!(
425 target: crate::LOG_TARGET,
426 hash = ?to_fetch.parent,
427 number = ?to_fetch.number,
428 ?err,
429 elapsed = ?now.elapsed(),
430 "Failed to fetch header for parent hash.",
431 );
432 return Err(err);
433 },
434 };
435 let metadata = MinimalBlockMetadata::from(&metadata);
436 let result = (metadata.number, metadata.hash);
437 finalized_chain.push_front(metadata);
438 result
439 },
440 };
441
442 if current_header_metadata.hash == finalized_chain_block_hash {
443 result.displaced_leaves.push((leaf_number, leaf_hash));
445
446 debug!(
447 target: crate::LOG_TARGET,
448 ?leaf_hash,
449 elapsed = ?now.elapsed(),
450 "Leaf is ancestor of finalized block."
451 );
452 break;
453 }
454
455 if current_header_metadata.number <= finalized_chain_block_number {
456 continue;
459 }
460
461 let parent_hash = current_header_metadata.parent;
462 if finalized_chain_block_hash == parent_hash {
463 result.displaced_blocks.extend(displaced_blocks_candidates.drain(..));
465 result.displaced_leaves.push((leaf_number, leaf_hash));
466
467 debug!(
468 target: crate::LOG_TARGET,
469 ?leaf_hash,
470 elapsed = ?now.elapsed(),
471 "Found displaced leaf."
472 );
473 break;
474 }
475
476 debug!(
478 target: crate::LOG_TARGET,
479 ?parent_hash,
480 elapsed = ?now.elapsed(),
481 "Found displaced block. Looking further.",
482 );
483 displaced_blocks_candidates.push(parent_hash);
484 current_header_metadata = MinimalBlockMetadata::from(
485 &self.header_metadata(parent_hash).map_err(|err| {
486 debug!(
487 target: crate::LOG_TARGET,
488 ?err,
489 ?parent_hash,
490 elapsed = ?now.elapsed(),
491 "Failed to fetch header for parent during displaced block collection",
492 );
493 err
494 })?,
495 );
496 }
497 }
498
499 result.displaced_blocks.sort_unstable();
501 result.displaced_blocks.dedup();
502
503 debug!(
504 target: crate::LOG_TARGET,
505 %finalized_block_hash,
506 ?finalized_block_number,
507 ?result,
508 elapsed = ?now.elapsed(),
509 "Finished checking for displaced leaves after finalization.",
510 );
511
512 return Ok(result);
513 }
514}
515
516#[derive(Clone, Debug)]
518pub struct DisplacedLeavesAfterFinalization<Block: BlockT> {
519 pub displaced_leaves: Vec<(NumberFor<Block>, Block::Hash)>,
521
522 pub displaced_blocks: Vec<Block::Hash>,
524}
525
526impl<Block: BlockT> Default for DisplacedLeavesAfterFinalization<Block> {
527 fn default() -> Self {
528 Self { displaced_leaves: Vec::new(), displaced_blocks: Vec::new() }
529 }
530}
531
532impl<Block: BlockT> DisplacedLeavesAfterFinalization<Block> {
533 pub fn hashes(&self) -> impl Iterator<Item = Block::Hash> + '_ {
535 self.displaced_leaves.iter().map(|(_, hash)| *hash)
536 }
537}
538
539#[derive(Debug, Clone, Copy, Eq, PartialEq, Encode, Decode)]
541pub enum BlockGapType {
542 MissingHeaderAndBody,
544 MissingBody,
546}
547
548#[derive(Debug, Clone, Copy, Eq, PartialEq, Encode, Decode)]
553pub struct BlockGap<N> {
554 pub start: N,
556 pub end: N,
558 pub gap_type: BlockGapType,
560}
561
562#[derive(Debug, Eq, PartialEq, Clone)]
564pub struct Info<Block: BlockT> {
565 pub best_hash: Block::Hash,
567 pub best_number: <<Block as BlockT>::Header as HeaderT>::Number,
569 pub genesis_hash: Block::Hash,
571 pub finalized_hash: Block::Hash,
573 pub finalized_number: <<Block as BlockT>::Header as HeaderT>::Number,
575 pub finalized_state: Option<(Block::Hash, <<Block as BlockT>::Header as HeaderT>::Number)>,
577 pub number_leaves: usize,
579 pub block_gap: Option<BlockGap<NumberFor<Block>>>,
581}
582
583#[derive(Debug, Clone, Copy, PartialEq, Eq)]
585pub enum BlockStatus {
586 InChain,
588 Unknown,
590}