1
// This file is part of Substrate.
2

            
3
// Copyright (C) Parity Technologies (UK) Ltd.
4
// SPDX-License-Identifier: Apache-2.0
5

            
6
// Licensed under the Apache License, Version 2.0 (the "License");
7
// you may not use this file except in compliance with the License.
8
// You may obtain a copy of the License at
9
//
10
// 	http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software
13
// distributed under the License is distributed on an "AS IS" BASIS,
14
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
// See the License for the specific language governing permissions and
16
// limitations under the License.
17

            
18
//! Substrate blockchain trait
19

            
20
use parking_lot::RwLock;
21
use sp_runtime::{
22
	generic::BlockId,
23
	traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero},
24
	Justifications,
25
};
26
use std::collections::{btree_set::BTreeSet, HashMap, VecDeque};
27
use tracing::{debug, warn};
28

            
29
use crate::{
30
	error::{Error, Result},
31
	header_metadata::HeaderMetadata,
32
	tree_route, CachedHeaderMetadata,
33
};
34

            
35
/// Blockchain database header backend. Does not perform any validation.
36
pub trait HeaderBackend<Block: BlockT>: Send + Sync {
37
	/// Get block header. Returns `None` if block is not found.
38
	fn header(&self, hash: Block::Hash) -> Result<Option<Block::Header>>;
39
	/// Get blockchain info.
40
	fn info(&self) -> Info<Block>;
41
	/// Get block status.
42
	fn status(&self, hash: Block::Hash) -> Result<BlockStatus>;
43
	/// Get block number by hash. Returns `None` if the header is not in the chain.
44
	fn number(
45
		&self,
46
		hash: Block::Hash,
47
	) -> Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>>;
48
	/// Get block hash by number. Returns `None` if the header is not in the chain.
49
	fn hash(&self, number: NumberFor<Block>) -> Result<Option<Block::Hash>>;
50

            
51
	/// Convert an arbitrary block ID into a block hash.
52
	fn block_hash_from_id(&self, id: &BlockId<Block>) -> Result<Option<Block::Hash>> {
53
		match *id {
54
			BlockId::Hash(h) => Ok(Some(h)),
55
			BlockId::Number(n) => self.hash(n),
56
		}
57
	}
58

            
59
	/// Convert an arbitrary block ID into a block hash.
60
	fn block_number_from_id(&self, id: &BlockId<Block>) -> Result<Option<NumberFor<Block>>> {
61
		match *id {
62
			BlockId::Hash(h) => self.number(h),
63
			BlockId::Number(n) => Ok(Some(n)),
64
		}
65
	}
66

            
67
	/// Get block header. Returns `UnknownBlock` error if block is not found.
68
	fn expect_header(&self, hash: Block::Hash) -> Result<Block::Header> {
69
		self.header(hash)?
70
			.ok_or_else(|| Error::UnknownBlock(format!("Expect header: {}", hash)))
71
	}
72

            
73
	/// Convert an arbitrary block ID into a block number. Returns `UnknownBlock` error if block is
74
	/// not found.
75
	fn expect_block_number_from_id(&self, id: &BlockId<Block>) -> Result<NumberFor<Block>> {
76
		self.block_number_from_id(id).and_then(|n| {
77
			n.ok_or_else(|| Error::UnknownBlock(format!("Expect block number from id: {}", id)))
78
		})
79
	}
80

            
81
	/// Convert an arbitrary block ID into a block hash. Returns `UnknownBlock` error if block is
82
	/// not found.
83
	fn expect_block_hash_from_id(&self, id: &BlockId<Block>) -> Result<Block::Hash> {
84
		self.block_hash_from_id(id).and_then(|h| {
85
			h.ok_or_else(|| Error::UnknownBlock(format!("Expect block hash from id: {}", id)))
86
		})
87
	}
88
}
89

            
90
/// Handles stale forks.
91
pub trait ForkBackend<Block: BlockT>:
92
	HeaderMetadata<Block> + HeaderBackend<Block> + Send + Sync
93
{
94
	/// Returns block hashes for provided fork heads. It skips the fork if when blocks are missing
95
	/// (e.g. warp-sync) and internal `tree_route` function fails.
96
	///
97
	/// Example:
98
	///  G --- A1 --- A2 --- A3 --- A4           ( < fork1 )
99
	///                       \-----C4 --- C5    ( < fork2 )
100
	/// We finalize A3 and call expand_fork(C5). Result = (C5,C4).
101
	fn expand_forks(
102
		&self,
103
		fork_heads: &[Block::Hash],
104
	) -> std::result::Result<BTreeSet<Block::Hash>, Error> {
105
		let mut expanded_forks = BTreeSet::new();
106
		for fork_head in fork_heads {
107
			match tree_route(self, *fork_head, self.info().finalized_hash) {
108
				Ok(tree_route) => {
109
					for block in tree_route.retracted() {
110
						expanded_forks.insert(block.hash);
111
					}
112
					continue
113
				},
114
				Err(_) => {
115
					// There are cases when blocks are missing (e.g. warp-sync).
116
				},
117
			}
118
		}
119

            
120
		Ok(expanded_forks)
121
	}
122
}
123

            
124
impl<Block, T> ForkBackend<Block> for T
125
where
126
	Block: BlockT,
127
	T: HeaderMetadata<Block> + HeaderBackend<Block> + Send + Sync,
128
{
129
}
130

            
131
struct MinimalBlockMetadata<Block: BlockT> {
132
	number: NumberFor<Block>,
133
	hash: Block::Hash,
134
	parent: Block::Hash,
135
}
136

            
137
impl<Block> Clone for MinimalBlockMetadata<Block>
138
where
139
	Block: BlockT,
140
{
141
	fn clone(&self) -> Self {
142
		Self { number: self.number, hash: self.hash, parent: self.parent }
143
	}
144
}
145

            
146
impl<Block> Copy for MinimalBlockMetadata<Block> where Block: BlockT {}
147

            
148
impl<Block> From<&CachedHeaderMetadata<Block>> for MinimalBlockMetadata<Block>
149
where
150
	Block: BlockT,
151
{
152
	fn from(value: &CachedHeaderMetadata<Block>) -> Self {
153
		Self { number: value.number, hash: value.hash, parent: value.parent }
154
	}
155
}
156

            
157
/// Blockchain database backend. Does not perform any validation.
158
pub trait Backend<Block: BlockT>:
159
	HeaderBackend<Block> + HeaderMetadata<Block, Error = Error>
160
{
161
	/// Get block body. Returns `None` if block is not found.
162
	fn body(&self, hash: Block::Hash) -> Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
163
	/// Get block justifications. Returns `None` if no justification exists.
164
	fn justifications(&self, hash: Block::Hash) -> Result<Option<Justifications>>;
165
	/// Get last finalized block hash.
166
	fn last_finalized(&self) -> Result<Block::Hash>;
167

            
168
	/// Returns hashes of all blocks that are leaves of the block tree.
169
	/// in other words, that have no children, are chain heads.
170
	/// Results must be ordered best (longest, highest) chain first.
171
	fn leaves(&self) -> Result<Vec<Block::Hash>>;
172

            
173
	/// Return hashes of all blocks that are children of the block with `parent_hash`.
174
	fn children(&self, parent_hash: Block::Hash) -> Result<Vec<Block::Hash>>;
175

            
176
	/// Get the most recent block hash of the longest chain that contains
177
	/// a block with the given `base_hash`.
178
	///
179
	/// The search space is always limited to blocks which are in the finalized
180
	/// chain or descendants of it.
181
	///
182
	/// Returns `Ok(None)` if `base_hash` is not found in search space.
183
	// TODO: document time complexity of this, see [#1444](https://github.com/paritytech/substrate/issues/1444)
184
	fn longest_containing(
185
		&self,
186
		base_hash: Block::Hash,
187
		import_lock: &RwLock<()>,
188
	) -> Result<Option<Block::Hash>> {
189
		let Some(base_header) = self.header(base_hash)? else { return Ok(None) };
190

            
191
		let leaves = {
192
			// ensure no blocks are imported during this code block.
193
			// an import could trigger a reorg which could change the canonical chain.
194
			// we depend on the canonical chain staying the same during this code block.
195
			let _import_guard = import_lock.read();
196
			let info = self.info();
197
			if info.finalized_number > *base_header.number() {
198
				// `base_header` is on a dead fork.
199
				return Ok(None)
200
			}
201
			self.leaves()?
202
		};
203

            
204
		// for each chain. longest chain first. shortest last
205
		for leaf_hash in leaves {
206
			let mut current_hash = leaf_hash;
207
			// go backwards through the chain (via parent links)
208
			loop {
209
				if current_hash == base_hash {
210
					return Ok(Some(leaf_hash))
211
				}
212

            
213
				let current_header = self
214
					.header(current_hash)?
215
					.ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?;
216

            
217
				// stop search in this chain once we go below the target's block number
218
				if current_header.number() < base_header.number() {
219
					break
220
				}
221

            
222
				current_hash = *current_header.parent_hash();
223
			}
224
		}
225

            
226
		// header may be on a dead fork -- the only leaves that are considered are
227
		// those which can still be finalized.
228
		//
229
		// FIXME #1558 only issue this warning when not on a dead fork
230
		warn!(
231
			target: crate::LOG_TARGET,
232
			"Block {:?} exists in chain but not found when following all leaves backwards",
233
			base_hash,
234
		);
235

            
236
		Ok(None)
237
	}
238

            
239
	/// Get single indexed transaction by content hash. Note that this will only fetch transactions
240
	/// that are indexed by the runtime with `storage_index_transaction`.
241
	fn indexed_transaction(&self, hash: Block::Hash) -> Result<Option<Vec<u8>>>;
242

            
243
	/// Check if indexed transaction exists.
244
	fn has_indexed_transaction(&self, hash: Block::Hash) -> Result<bool> {
245
		Ok(self.indexed_transaction(hash)?.is_some())
246
	}
247

            
248
	fn block_indexed_body(&self, hash: Block::Hash) -> Result<Option<Vec<Vec<u8>>>>;
249

            
250
	/// Returns all leaves that will be displaced after the block finalization.
251
	fn displaced_leaves_after_finalizing(
252
		&self,
253
		finalized_block_hash: Block::Hash,
254
		finalized_block_number: NumberFor<Block>,
255
	) -> std::result::Result<DisplacedLeavesAfterFinalization<Block>, Error> {
256
		let leaves = self.leaves()?;
257

            
258
		let now = std::time::Instant::now();
259
		debug!(
260
			target: crate::LOG_TARGET,
261
			?leaves,
262
			?finalized_block_hash,
263
			?finalized_block_number,
264
			"Checking for displaced leaves after finalization."
265
		);
266

            
267
		// If we have only one leaf there are no forks, and we can return early.
268
		if finalized_block_number == Zero::zero() || leaves.len() == 1 {
269
			return Ok(DisplacedLeavesAfterFinalization::default())
270
		}
271

            
272
		// Store hashes of finalized blocks for quick checking later, the last block is the
273
		// finalized one
274
		let mut finalized_chain = VecDeque::new();
275
		let current_finalized = match self.header_metadata(finalized_block_hash) {
276
			Ok(metadata) => metadata,
277
			Err(Error::UnknownBlock(_)) => {
278
				debug!(
279
					target: crate::LOG_TARGET,
280
					hash = ?finalized_block_hash,
281
					elapsed = ?now.elapsed(),
282
					"Tried to fetch unknown block, block ancestry has gaps.",
283
				);
284
				return Ok(DisplacedLeavesAfterFinalization::default());
285
			},
286
			Err(e) => {
287
				debug!(
288
					target: crate::LOG_TARGET,
289
					hash = ?finalized_block_hash,
290
					err = ?e,
291
					elapsed = ?now.elapsed(),
292
					"Failed to fetch block.",
293
				);
294
				return Err(e);
295
			},
296
		};
297
		finalized_chain.push_front(MinimalBlockMetadata::from(&current_finalized));
298

            
299
		// Local cache is a performance optimization in case of finalized block deep below the
300
		// tip of the chain with a lot of leaves above finalized block
301
		let mut local_cache = HashMap::<Block::Hash, MinimalBlockMetadata<Block>>::new();
302

            
303
		let mut result = DisplacedLeavesAfterFinalization {
304
			displaced_leaves: Vec::with_capacity(leaves.len()),
305
			displaced_blocks: Vec::with_capacity(leaves.len()),
306
		};
307

            
308
		let mut displaced_blocks_candidates = Vec::new();
309

            
310
		let genesis_hash = self.info().genesis_hash;
311

            
312
		for leaf_hash in leaves {
313
			let mut current_header_metadata =
314
				MinimalBlockMetadata::from(&self.header_metadata(leaf_hash).map_err(|err| {
315
					debug!(
316
						target: crate::LOG_TARGET,
317
						?leaf_hash,
318
						?err,
319
						elapsed = ?now.elapsed(),
320
						"Failed to fetch leaf header.",
321
					);
322
					err
323
				})?);
324
			let leaf_number = current_header_metadata.number;
325

            
326
			// The genesis block is part of the canonical chain.
327
			if leaf_hash == genesis_hash {
328
				result.displaced_leaves.push((leaf_number, leaf_hash));
329
				debug!(
330
					target: crate::LOG_TARGET,
331
					?leaf_hash,
332
					elapsed = ?now.elapsed(),
333
					"Added genesis leaf to displaced leaves."
334
				);
335
				continue
336
			}
337

            
338
			debug!(
339
				target: crate::LOG_TARGET,
340
				?leaf_number,
341
				?leaf_hash,
342
				elapsed = ?now.elapsed(),
343
				"Handle displaced leaf.",
344
			);
345

            
346
			// Collect all block hashes until the height of the finalized block
347
			displaced_blocks_candidates.clear();
348
			while current_header_metadata.number > finalized_block_number {
349
				displaced_blocks_candidates.push(current_header_metadata.hash);
350

            
351
				let parent_hash = current_header_metadata.parent;
352
				match local_cache.get(&parent_hash) {
353
					Some(metadata_header) => {
354
						current_header_metadata = *metadata_header;
355
					},
356
					None => {
357
						current_header_metadata = MinimalBlockMetadata::from(
358
							&self.header_metadata(parent_hash).map_err(|err| {
359
								debug!(
360
									target: crate::LOG_TARGET,
361
									?err,
362
									?parent_hash,
363
									?leaf_hash,
364
									elapsed = ?now.elapsed(),
365
									"Failed to fetch parent header during leaf tracking.",
366
								);
367

            
368
								err
369
							})?,
370
						);
371
						// Cache locally in case more branches above finalized block reference
372
						// the same block hash
373
						local_cache.insert(parent_hash, current_header_metadata);
374
					},
375
				}
376
			}
377

            
378
			// If points back to the finalized header then nothing left to do, this leaf will be
379
			// checked again later
380
			if current_header_metadata.hash == finalized_block_hash {
381
				debug!(
382
					target: crate::LOG_TARGET,
383
					?leaf_hash,
384
					elapsed = ?now.elapsed(),
385
					"Leaf points to the finalized header, skipping for now.",
386
				);
387

            
388
				continue;
389
			}
390

            
391
			// We reuse `displaced_blocks_candidates` to store the current metadata.
392
			// This block is not displaced if there is a gap in the ancestry. We
393
			// check for this gap later.
394
			displaced_blocks_candidates.push(current_header_metadata.hash);
395

            
396
			debug!(
397
				target: crate::LOG_TARGET,
398
				current_hash = ?current_header_metadata.hash,
399
				current_num = ?current_header_metadata.number,
400
				?finalized_block_number,
401
				elapsed = ?now.elapsed(),
402
				"Looking for path from finalized block number to current leaf number"
403
			);
404

            
405
			// Collect the rest of the displaced blocks of leaf branch
406
			for distance_from_finalized in 1_u32.. {
407
				// Find block at `distance_from_finalized` from finalized block
408
				let (finalized_chain_block_number, finalized_chain_block_hash) =
409
					match finalized_chain.iter().rev().nth(distance_from_finalized as usize) {
410
						Some(header) => (header.number, header.hash),
411
						None => {
412
							let to_fetch = finalized_chain.front().expect("Not empty; qed");
413
							let metadata = match self.header_metadata(to_fetch.parent) {
414
								Ok(metadata) => metadata,
415
								Err(Error::UnknownBlock(_)) => {
416
									debug!(
417
										target: crate::LOG_TARGET,
418
										distance_from_finalized,
419
										hash = ?to_fetch.parent,
420
										number = ?to_fetch.number,
421
										elapsed = ?now.elapsed(),
422
										"Tried to fetch unknown block, block ancestry has gaps."
423
									);
424
									break;
425
								},
426
								Err(err) => {
427
									debug!(
428
										target: crate::LOG_TARGET,
429
										hash = ?to_fetch.parent,
430
										number = ?to_fetch.number,
431
										?err,
432
										elapsed = ?now.elapsed(),
433
										"Failed to fetch header for parent hash.",
434
									);
435
									return Err(err);
436
								},
437
							};
438
							let metadata = MinimalBlockMetadata::from(&metadata);
439
							let result = (metadata.number, metadata.hash);
440
							finalized_chain.push_front(metadata);
441
							result
442
						},
443
					};
444

            
445
				if current_header_metadata.hash == finalized_chain_block_hash {
446
					// Found the block on the finalized chain, nothing left to do
447
					result.displaced_leaves.push((leaf_number, leaf_hash));
448

            
449
					debug!(
450
						target: crate::LOG_TARGET,
451
						?leaf_hash,
452
						elapsed = ?now.elapsed(),
453
						"Leaf is ancestor of finalized block."
454
					);
455
					break;
456
				}
457

            
458
				if current_header_metadata.number <= finalized_chain_block_number {
459
					// Skip more blocks until we get all blocks on finalized chain until the height
460
					// of the parent block
461
					continue;
462
				}
463

            
464
				let parent_hash = current_header_metadata.parent;
465
				if finalized_chain_block_hash == parent_hash {
466
					// Reached finalized chain, nothing left to do
467
					result.displaced_blocks.extend(displaced_blocks_candidates.drain(..));
468
					result.displaced_leaves.push((leaf_number, leaf_hash));
469

            
470
					debug!(
471
						target: crate::LOG_TARGET,
472
						?leaf_hash,
473
						elapsed = ?now.elapsed(),
474
						"Found displaced leaf."
475
					);
476
					break;
477
				}
478

            
479
				// Store displaced block and look deeper for block on finalized chain
480
				debug!(
481
					target: crate::LOG_TARGET,
482
					?parent_hash,
483
					elapsed = ?now.elapsed(),
484
					"Found displaced block. Looking further.",
485
				);
486
				displaced_blocks_candidates.push(parent_hash);
487
				current_header_metadata = MinimalBlockMetadata::from(
488
					&self.header_metadata(parent_hash).map_err(|err| {
489
						debug!(
490
							target: crate::LOG_TARGET,
491
							?err,
492
							?parent_hash,
493
							elapsed = ?now.elapsed(),
494
							"Failed to fetch header for parent during displaced block collection",
495
						);
496
						err
497
					})?,
498
				);
499
			}
500
		}
501

            
502
		// There could be duplicates shared by multiple branches, clean them up
503
		result.displaced_blocks.sort_unstable();
504
		result.displaced_blocks.dedup();
505

            
506
		debug!(
507
			target: crate::LOG_TARGET,
508
			%finalized_block_hash,
509
			?finalized_block_number,
510
			?result,
511
			elapsed = ?now.elapsed(),
512
			"Finished checking for displaced leaves after finalization.",
513
		);
514

            
515
		return Ok(result);
516
	}
517
}
518

            
519
/// Result of  [`Backend::displaced_leaves_after_finalizing`].
520
#[derive(Clone, Debug)]
521
pub struct DisplacedLeavesAfterFinalization<Block: BlockT> {
522
	/// A list of hashes and block numbers of displaced leaves.
523
	pub displaced_leaves: Vec<(NumberFor<Block>, Block::Hash)>,
524

            
525
	/// A list of hashes displaced blocks from all displaced leaves.
526
	pub displaced_blocks: Vec<Block::Hash>,
527
}
528

            
529
impl<Block: BlockT> Default for DisplacedLeavesAfterFinalization<Block> {
530
	fn default() -> Self {
531
		Self { displaced_leaves: Vec::new(), displaced_blocks: Vec::new() }
532
	}
533
}
534

            
535
impl<Block: BlockT> DisplacedLeavesAfterFinalization<Block> {
536
	/// Returns a collection of hashes for the displaced leaves.
537
	pub fn hashes(&self) -> impl Iterator<Item = Block::Hash> + '_ {
538
		self.displaced_leaves.iter().map(|(_, hash)| *hash)
539
	}
540
}
541

            
542
/// Blockchain info
543
#[derive(Debug, Eq, PartialEq, Clone)]
544
pub struct Info<Block: BlockT> {
545
	/// Best block hash.
546
	pub best_hash: Block::Hash,
547
	/// Best block number.
548
	pub best_number: <<Block as BlockT>::Header as HeaderT>::Number,
549
	/// Genesis block hash.
550
	pub genesis_hash: Block::Hash,
551
	/// The head of the finalized chain.
552
	pub finalized_hash: Block::Hash,
553
	/// Last finalized block number.
554
	pub finalized_number: <<Block as BlockT>::Header as HeaderT>::Number,
555
	/// Last finalized state.
556
	pub finalized_state: Option<(Block::Hash, <<Block as BlockT>::Header as HeaderT>::Number)>,
557
	/// Number of concurrent leave forks.
558
	pub number_leaves: usize,
559
	/// Missing blocks after warp sync. (start, end).
560
	pub block_gap: Option<(NumberFor<Block>, NumberFor<Block>)>,
561
}
562

            
563
/// Block status.
564
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
565
pub enum BlockStatus {
566
	/// Already in the blockchain.
567
	InChain,
568
	/// Not in the queue or the blockchain.
569
	Unknown,
570
}