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 finalized_block_parent_hash: Block::Hash,
257 ) -> std::result::Result<DisplacedLeavesAfterFinalization<Block>, Error> {
258 if finalized_block_number.is_zero() {
260 return Ok(DisplacedLeavesAfterFinalization::default());
261 }
262
263 let leaves = self.leaves()?;
264
265 let now = std::time::Instant::now();
266 debug!(
267 target: crate::LOG_TARGET,
268 ?leaves,
269 ?finalized_block_hash,
270 ?finalized_block_number,
271 "Checking for displaced leaves after finalization."
272 );
273
274 let mut finalized_chain = VecDeque::new();
277 finalized_chain.push_front(MinimalBlockMetadata {
278 number: finalized_block_number,
279 hash: finalized_block_hash,
280 parent: finalized_block_parent_hash,
281 });
282
283 let mut local_cache = HashMap::<Block::Hash, MinimalBlockMetadata<Block>>::new();
286
287 let mut result = DisplacedLeavesAfterFinalization {
288 displaced_leaves: Vec::with_capacity(leaves.len()),
289 displaced_blocks: Vec::with_capacity(leaves.len()),
290 };
291
292 let mut displaced_blocks_candidates = Vec::new();
293
294 let genesis_hash = self.info().genesis_hash;
295
296 for leaf_hash in leaves {
297 let mut current_header_metadata =
298 MinimalBlockMetadata::from(&self.header_metadata(leaf_hash).map_err(|err| {
299 debug!(
300 target: crate::LOG_TARGET,
301 ?leaf_hash,
302 ?err,
303 elapsed = ?now.elapsed(),
304 "Failed to fetch leaf header.",
305 );
306 err
307 })?);
308 let leaf_number = current_header_metadata.number;
309
310 if leaf_hash == genesis_hash {
312 result.displaced_leaves.push((leaf_number, leaf_hash));
313 debug!(
314 target: crate::LOG_TARGET,
315 ?leaf_hash,
316 elapsed = ?now.elapsed(),
317 "Added genesis leaf to displaced leaves."
318 );
319 continue;
320 }
321
322 debug!(
323 target: crate::LOG_TARGET,
324 ?leaf_number,
325 ?leaf_hash,
326 elapsed = ?now.elapsed(),
327 "Handle displaced leaf.",
328 );
329
330 displaced_blocks_candidates.clear();
332 while current_header_metadata.number > finalized_block_number {
333 displaced_blocks_candidates.push(current_header_metadata.hash);
334
335 let parent_hash = current_header_metadata.parent;
336 match local_cache.get(&parent_hash) {
337 Some(metadata_header) => {
338 current_header_metadata = *metadata_header;
339 },
340 None => {
341 current_header_metadata = MinimalBlockMetadata::from(
342 &self.header_metadata(parent_hash).map_err(|err| {
343 debug!(
344 target: crate::LOG_TARGET,
345 ?err,
346 ?parent_hash,
347 ?leaf_hash,
348 elapsed = ?now.elapsed(),
349 "Failed to fetch parent header during leaf tracking.",
350 );
351
352 err
353 })?,
354 );
355 local_cache.insert(parent_hash, current_header_metadata);
358 },
359 }
360 }
361
362 if current_header_metadata.hash == finalized_block_hash {
365 debug!(
366 target: crate::LOG_TARGET,
367 ?leaf_hash,
368 elapsed = ?now.elapsed(),
369 "Leaf points to the finalized header, skipping for now.",
370 );
371
372 continue;
373 }
374
375 displaced_blocks_candidates.push(current_header_metadata.hash);
379
380 debug!(
381 target: crate::LOG_TARGET,
382 current_hash = ?current_header_metadata.hash,
383 current_num = ?current_header_metadata.number,
384 ?finalized_block_number,
385 elapsed = ?now.elapsed(),
386 "Looking for path from finalized block number to current leaf number"
387 );
388
389 for distance_from_finalized in 1_u32.. {
391 let (finalized_chain_block_number, finalized_chain_block_hash) =
393 match finalized_chain.iter().rev().nth(distance_from_finalized as usize) {
394 Some(header) => (header.number, header.hash),
395 None => {
396 let to_fetch = finalized_chain.front().expect("Not empty; qed");
397 let metadata = match self.header_metadata(to_fetch.parent) {
398 Ok(metadata) => metadata,
399 Err(Error::UnknownBlock(_)) => {
400 debug!(
401 target: crate::LOG_TARGET,
402 distance_from_finalized,
403 hash = ?to_fetch.parent,
404 number = ?to_fetch.number,
405 elapsed = ?now.elapsed(),
406 "Tried to fetch unknown block, block ancestry has gaps."
407 );
408 break;
409 },
410 Err(err) => {
411 debug!(
412 target: crate::LOG_TARGET,
413 hash = ?to_fetch.parent,
414 number = ?to_fetch.number,
415 ?err,
416 elapsed = ?now.elapsed(),
417 "Failed to fetch header for parent hash.",
418 );
419 return Err(err);
420 },
421 };
422 let metadata = MinimalBlockMetadata::from(&metadata);
423 let result = (metadata.number, metadata.hash);
424 finalized_chain.push_front(metadata);
425 result
426 },
427 };
428
429 if current_header_metadata.hash == finalized_chain_block_hash {
430 result.displaced_leaves.push((leaf_number, leaf_hash));
432
433 debug!(
434 target: crate::LOG_TARGET,
435 ?leaf_hash,
436 elapsed = ?now.elapsed(),
437 "Leaf is ancestor of finalized block."
438 );
439 break;
440 }
441
442 if current_header_metadata.number <= finalized_chain_block_number {
443 continue;
446 }
447
448 let parent_hash = current_header_metadata.parent;
449 if finalized_chain_block_hash == parent_hash {
450 result.displaced_blocks.extend(displaced_blocks_candidates.drain(..));
452 result.displaced_leaves.push((leaf_number, leaf_hash));
453
454 debug!(
455 target: crate::LOG_TARGET,
456 ?leaf_hash,
457 elapsed = ?now.elapsed(),
458 "Found displaced leaf."
459 );
460 break;
461 }
462
463 debug!(
465 target: crate::LOG_TARGET,
466 ?parent_hash,
467 elapsed = ?now.elapsed(),
468 "Found displaced block. Looking further.",
469 );
470 displaced_blocks_candidates.push(parent_hash);
471 current_header_metadata = MinimalBlockMetadata::from(
472 &self.header_metadata(parent_hash).map_err(|err| {
473 debug!(
474 target: crate::LOG_TARGET,
475 ?err,
476 ?parent_hash,
477 elapsed = ?now.elapsed(),
478 "Failed to fetch header for parent during displaced block collection",
479 );
480 err
481 })?,
482 );
483 }
484 }
485
486 result.displaced_blocks.sort_unstable();
488 result.displaced_blocks.dedup();
489
490 debug!(
491 target: crate::LOG_TARGET,
492 %finalized_block_hash,
493 ?finalized_block_number,
494 ?result,
495 elapsed = ?now.elapsed(),
496 "Finished checking for displaced leaves after finalization.",
497 );
498
499 return Ok(result);
500 }
501}
502
503#[derive(Clone, Debug)]
505pub struct DisplacedLeavesAfterFinalization<Block: BlockT> {
506 pub displaced_leaves: Vec<(NumberFor<Block>, Block::Hash)>,
508
509 pub displaced_blocks: Vec<Block::Hash>,
511}
512
513impl<Block: BlockT> Default for DisplacedLeavesAfterFinalization<Block> {
514 fn default() -> Self {
515 Self { displaced_leaves: Vec::new(), displaced_blocks: Vec::new() }
516 }
517}
518
519impl<Block: BlockT> DisplacedLeavesAfterFinalization<Block> {
520 pub fn hashes(&self) -> impl Iterator<Item = Block::Hash> + '_ {
522 self.displaced_leaves.iter().map(|(_, hash)| *hash)
523 }
524}
525
526#[derive(Debug, Clone, Copy, Eq, PartialEq, Encode, Decode)]
528pub enum BlockGapType {
529 MissingHeaderAndBody,
531 MissingBody,
533}
534
535#[derive(Debug, Clone, Copy, Eq, PartialEq, Encode, Decode)]
540pub struct BlockGap<N> {
541 pub start: N,
543 pub end: N,
545 pub gap_type: BlockGapType,
547}
548
549#[derive(Debug, Eq, PartialEq, Clone)]
551pub struct Info<Block: BlockT> {
552 pub best_hash: Block::Hash,
554 pub best_number: <<Block as BlockT>::Header as HeaderT>::Number,
556 pub genesis_hash: Block::Hash,
558 pub finalized_hash: Block::Hash,
560 pub finalized_number: <<Block as BlockT>::Header as HeaderT>::Number,
562 pub finalized_state: Option<(Block::Hash, <<Block as BlockT>::Header as HeaderT>::Number)>,
564 pub number_leaves: usize,
566 pub block_gap: Option<BlockGap<NumberFor<Block>>>,
568}
569
570#[derive(Debug, Clone, Copy, PartialEq, Eq)]
572pub enum BlockStatus {
573 InChain,
575 Unknown,
577}