1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use sc_client_api::backend;
use sp_blockchain::{Backend, HeaderBackend};
use sp_consensus::{Error as ConsensusError, SelectChain};
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, NumberFor},
};
use std::{marker::PhantomData, sync::Arc};
pub struct LongestChain<B, Block> {
backend: Arc<B>,
_phantom: PhantomData<Block>,
}
impl<B, Block> Clone for LongestChain<B, Block> {
fn clone(&self) -> Self {
let backend = self.backend.clone();
LongestChain { backend, _phantom: Default::default() }
}
}
impl<B, Block> LongestChain<B, Block>
where
B: backend::Backend<Block>,
Block: BlockT,
{
pub fn new(backend: Arc<B>) -> Self {
LongestChain { backend, _phantom: Default::default() }
}
fn best_block_header(&self) -> sp_blockchain::Result<<Block as BlockT>::Header> {
let info = self.backend.blockchain().info();
let import_lock = self.backend.get_import_lock();
let best_hash = self
.backend
.blockchain()
.best_containing(info.best_hash, None, import_lock)?
.unwrap_or(info.best_hash);
Ok(self
.backend
.blockchain()
.header(BlockId::Hash(best_hash))?
.expect("given block hash was fetched from block in db; qed"))
}
fn leaves(&self) -> Result<Vec<<Block as BlockT>::Hash>, sp_blockchain::Error> {
self.backend.blockchain().leaves()
}
}
#[async_trait::async_trait]
impl<B, Block> SelectChain<Block> for LongestChain<B, Block>
where
B: backend::Backend<Block>,
Block: BlockT,
{
async fn leaves(&self) -> Result<Vec<<Block as BlockT>::Hash>, ConsensusError> {
LongestChain::leaves(self).map_err(|e| ConsensusError::ChainLookup(e.to_string()).into())
}
async fn best_chain(&self) -> Result<<Block as BlockT>::Header, ConsensusError> {
LongestChain::best_block_header(&self)
.map_err(|e| ConsensusError::ChainLookup(e.to_string()).into())
}
async fn finality_target(
&self,
target_hash: Block::Hash,
maybe_max_number: Option<NumberFor<Block>>,
) -> Result<Option<Block::Hash>, ConsensusError> {
let import_lock = self.backend.get_import_lock();
self.backend
.blockchain()
.best_containing(target_hash, maybe_max_number, import_lock)
.map_err(|e| ConsensusError::ChainLookup(e.to_string()).into())
}
}