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