Skip to main content

sp_subspace_mmr/
runtime_interface.rs

1//! Runtime interface for Subspace-specific MMR operations.
2//! Used to verify MMR proofs in the domain runtime, based on the consensus MMR state.
3
4#[cfg(all(feature = "std", not(feature = "runtime-benchmarks")))]
5use crate::host_functions::SubspaceMmrExtension;
6use parity_scale_codec::{Decode, Encode};
7use scale_info::TypeInfo;
8use scale_info::prelude::vec::Vec;
9use sp_core::H256;
10#[cfg(all(feature = "std", not(feature = "runtime-benchmarks")))]
11use sp_externalities::ExternalitiesExt;
12use sp_mmr_primitives::EncodableOpaqueLeaf;
13use sp_runtime_interface::pass_by::{
14    AllocateAndReturnByCodec, PassFatPointerAndDecode, PassFatPointerAndRead,
15    PassPointerAndReadCopy,
16};
17use sp_runtime_interface::runtime_interface;
18use subspace_core_primitives::BlockNumber;
19
20/// MMR related runtime interface
21#[runtime_interface]
22pub trait SubspaceMmrRuntimeInterface {
23    /// Returns the MMR leaf for the given consensus block.
24    fn get_mmr_leaf_data(
25        &mut self,
26        consensus_block_hash: PassPointerAndReadCopy<H256, 32>,
27    ) -> AllocateAndReturnByCodec<Option<LeafData>> {
28        #[cfg(not(feature = "runtime-benchmarks"))]
29        {
30            self.extension::<SubspaceMmrExtension>()
31                .expect("No `SubspaceMmrExtension` associated for the current context!")
32                .get_mmr_leaf_data(consensus_block_hash)
33        }
34
35        // We assume this implementation costs slightly less than the real implementation,
36        // but it's the best we can do for now.
37        // TODO: when custom extensions are supported in benchmarks, remove this code and call
38        // directly into SubspaceMmrExtension.
39        // <https://github.com/paritytech/polkadot-sdk/issues/137>
40        #[cfg(feature = "runtime-benchmarks")]
41        {
42            crate::benchmarking::mock_subspace_mmr_extension()
43                .get_mmr_leaf_data(consensus_block_hash)
44        }
45    }
46
47    /// Returns the consensus block hash for a given block number.
48    fn consensus_block_hash(
49        &mut self,
50        block_number: BlockNumber,
51    ) -> AllocateAndReturnByCodec<Option<H256>> {
52        #[cfg(not(feature = "runtime-benchmarks"))]
53        {
54            self.extension::<SubspaceMmrExtension>()
55                .expect("No `SubspaceMmrExtension` associated for the current context!")
56                .consensus_block_hash(block_number)
57        }
58
59        // We assume this implementation costs slightly less than the real implementation,
60        // but it's the best we can do for now.
61        // TODO: when custom extensions are supported, call directly into SubspaceMmrExtension.
62        #[cfg(feature = "runtime-benchmarks")]
63        {
64            crate::benchmarking::mock_subspace_mmr_extension().consensus_block_hash(block_number)
65        }
66    }
67}
68
69/// Leaf data sent back from host function.
70#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, Default)]
71pub struct LeafData {
72    pub state_root: H256,
73    pub extrinsics_root: H256,
74}
75
76#[runtime_interface]
77pub trait DomainMmrRuntimeInterface {
78    /// Verifies the given MMR proof using the leaves provided.
79    fn verify_mmr_proof(
80        &mut self,
81        leaves: PassFatPointerAndDecode<Vec<EncodableOpaqueLeaf>>,
82        encoded_proof: PassFatPointerAndRead<Vec<u8>>,
83    ) -> bool {
84        #[cfg(not(feature = "runtime-benchmarks"))]
85        {
86            self.extension::<SubspaceMmrExtension>()
87                .expect("No `SubspaceMmrExtension` associated for the current context!")
88                .verify_mmr_proof(leaves, encoded_proof)
89        }
90
91        // We assume this implementation costs slightly less than the real implementation,
92        // but it's the best we can do for now.
93        // TODO: when custom extensions are supported, call directly into SubspaceMmrExtension.
94        #[cfg(feature = "runtime-benchmarks")]
95        {
96            crate::benchmarking::mock_subspace_mmr_extension()
97                .verify_mmr_proof(leaves, encoded_proof)
98        }
99    }
100
101    // Return `true` if the given consensus block is finalized.
102    // BlockNumber (u32) and bool are primitives with direct RIType impls — no ABI wrapper needed.
103    fn is_consensus_block_finalized(&mut self, block_number: BlockNumber) -> bool {
104        #[cfg(not(feature = "runtime-benchmarks"))]
105        {
106            self.extension::<SubspaceMmrExtension>()
107                .expect("No `SubspaceMmrExtension` associated for the current context!")
108                .is_consensus_block_finalized(block_number)
109        }
110
111        // This implementation obviously costs less than the real implementation, but it's the best
112        // we can do for now.
113        // TODO: when custom extensions are supported, call directly into SubspaceMmrExtension.
114        #[cfg(feature = "runtime-benchmarks")]
115        {
116            crate::benchmarking::mock_subspace_mmr_extension()
117                .is_consensus_block_finalized(block_number)
118        }
119    }
120}