sp_subspace_mmr/
host_functions.rs1use crate::runtime_interface::LeafData;
2use parity_scale_codec::Decode;
3use sp_api::ProvideRuntimeApi;
4use sp_blockchain::HeaderBackend;
5use sp_core::H256;
6pub use sp_mmr_primitives::{EncodableOpaqueLeaf, LeafProof, MmrApi};
7use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor, Saturating};
8use std::marker::PhantomData;
9use std::sync::Arc;
10use subspace_core_primitives::BlockNumber;
11
12pub trait SubspaceMmrHostFunctions: Send + Sync {
14 fn get_mmr_leaf_data(&self, consensus_block_hash: H256) -> Option<LeafData>;
16
17 fn verify_mmr_proof(&self, leaves: Vec<EncodableOpaqueLeaf>, encoded_proof: Vec<u8>) -> bool;
19
20 fn consensus_block_hash(
22 &self,
23 block_number: subspace_core_primitives::BlockNumber,
24 ) -> Option<H256>;
25
26 fn is_consensus_block_finalized(&self, block_number: BlockNumber) -> bool;
28}
29
30sp_externalities::decl_extension! {
31 pub struct SubspaceMmrExtension(Arc<dyn SubspaceMmrHostFunctions>);
32}
33
34impl SubspaceMmrExtension {
35 pub fn new(inner: Arc<dyn SubspaceMmrHostFunctions>) -> Self {
37 Self(inner)
38 }
39}
40
41pub struct SubspaceMmrHostFunctionsImpl<Block, Client> {
43 consensus_client: Arc<Client>,
44 confirmation_depth_k: BlockNumber,
45 _phantom: PhantomData<Block>,
46}
47
48impl<Block, Client> SubspaceMmrHostFunctionsImpl<Block, Client> {
49 pub fn new(consensus_client: Arc<Client>, confirmation_depth_k: BlockNumber) -> Self {
50 SubspaceMmrHostFunctionsImpl {
51 consensus_client,
52 confirmation_depth_k,
53 _phantom: Default::default(),
54 }
55 }
56}
57
58impl<Block, Client> SubspaceMmrHostFunctions for SubspaceMmrHostFunctionsImpl<Block, Client>
59where
60 Block: BlockT,
61 Block::Hash: From<H256> + Into<H256>,
62 Client: HeaderBackend<Block> + ProvideRuntimeApi<Block>,
63 Client::Api: MmrApi<Block, H256, NumberFor<Block>>,
64{
65 fn get_mmr_leaf_data(&self, consensus_block_hash: H256) -> Option<LeafData> {
66 let header = self
67 .consensus_client
68 .header(consensus_block_hash.into())
69 .expect(
70 "Database error is fatal in host function, there is no recovery from this; qed",
71 )?;
72
73 Some(LeafData {
74 state_root: H256::from_slice(header.state_root().as_ref()),
75 extrinsics_root: H256::from_slice(header.extrinsics_root().as_ref()),
76 })
77 }
78
79 fn verify_mmr_proof(&self, leaves: Vec<EncodableOpaqueLeaf>, encoded_proof: Vec<u8>) -> bool {
80 let parent_hash = *self
82 .consensus_client
83 .header(self.consensus_client.info().best_hash)
84 .expect("Database error is fatal in host function, there is no recovery from this; qed")
85 .expect("Header must be available. There is no recovery if not available; qed.")
86 .parent_hash();
87 let api = self.consensus_client.runtime_api();
88 let proof = match LeafProof::<H256>::decode(&mut encoded_proof.as_ref()) {
89 Ok(proof) => proof,
90 Err(_) => return false,
91 };
92 api.verify_proof(parent_hash, leaves, proof).expect(
93 "Runtime Api should not fail in host function, there is no recovery from this; qed.",
94 ).is_ok()
95 }
96
97 fn consensus_block_hash(&self, block_number: BlockNumber) -> Option<H256> {
98 let block_number = NumberFor::<Block>::from(block_number);
99 self.consensus_client
100 .hash(block_number)
101 .expect("Header must be available. This is unrecoverable error")
102 .map(|block_hash| block_hash.into())
103 }
104
105 fn is_consensus_block_finalized(&self, block_number: BlockNumber) -> bool {
106 let block_number = NumberFor::<Block>::from(block_number);
107 let last_finalized_block = self
108 .consensus_client
109 .info()
110 .best_number
111 .saturating_sub(self.confirmation_depth_k.into());
112
113 block_number <= last_finalized_block
114 }
115}