Skip to main content

pallet_subspace_mmr/
lib.rs

1//! Pallet that provides necessary Leaf data for MMR.
2
3#![cfg_attr(not(feature = "std"), no_std)]
4// TODO: Remove once FRAME macros stop generating `.clone()` calls on `Copy` types with user spans
5#![expect(clippy::clone_on_copy, reason = "Comes from Substrate")]
6
7use frame_system::pallet_prelude::BlockNumberFor;
8pub use pallet::*;
9use sp_core::Get;
10use sp_mmr_primitives::{LeafDataProvider, OnNewRoot};
11use sp_runtime::traits::{CheckedSub, One};
12use sp_subspace_mmr::subspace_mmr_runtime_interface::get_mmr_leaf_data;
13use sp_subspace_mmr::{LeafDataV0, MmrLeaf};
14
15#[frame_support::pallet]
16mod pallet {
17    use frame_support::Parameter;
18    use frame_support::pallet_prelude::*;
19    use frame_system::pallet_prelude::BlockNumberFor;
20    use sp_core::H256;
21
22    #[pallet::pallet]
23    pub struct Pallet<T>(_);
24
25    #[pallet::config]
26    pub trait Config: frame_system::Config<Hash: Into<H256> + From<H256>> {
27        type MmrRootHash: Parameter + Copy + MaxEncodedLen;
28
29        /// The number of mmr root hashes to store in the runtime. It will be used to verify mmr
30        /// proof statelessly and the number of roots stored here represents the number of blocks
31        /// for which the mmr proof is valid since it is generated. After that the mmr proof
32        /// will be expired and the prover needs to re-generate the proof.
33        type MmrRootHashCount: Get<u32>;
34    }
35
36    /// Map of block numbers to mmr root hashes.
37    #[pallet::storage]
38    #[pallet::getter(fn mmr_root_hash)]
39    pub type MmrRootHashes<T: Config> =
40        StorageMap<_, Twox64Concat, BlockNumberFor<T>, T::MmrRootHash, OptionQuery>;
41}
42
43impl<T: Config> OnNewRoot<T::MmrRootHash> for Pallet<T> {
44    fn on_new_root(root: &T::MmrRootHash) {
45        let block_number = frame_system::Pallet::<T>::block_number();
46        <MmrRootHashes<T>>::insert(block_number, *root);
47        if let Some(to_prune) = block_number.checked_sub(&T::MmrRootHashCount::get().into()) {
48            <MmrRootHashes<T>>::remove(to_prune);
49        }
50    }
51}
52
53impl<T: Config> LeafDataProvider for Pallet<T> {
54    type LeafData = MmrLeaf<BlockNumberFor<T>, T::Hash>;
55
56    fn leaf_data() -> Self::LeafData {
57        #[cfg(not(feature = "runtime-benchmarks"))]
58        let block_number = frame_system::Pallet::<T>::block_number()
59            .checked_sub(&One::one())
60            .expect("`block_number` will always be >= 1; qed");
61        #[cfg(feature = "runtime-benchmarks")]
62        let block_number = sp_runtime::Saturating::saturating_sub(
63            frame_system::Pallet::<T>::block_number(),
64            One::one(),
65        );
66
67        let block_hash = frame_system::Pallet::<T>::parent_hash();
68        let leaf_data = get_mmr_leaf_data(block_hash.into())
69            .expect("leaf data for parent hash must always be derived; qed");
70        MmrLeaf::V0(LeafDataV0 {
71            block_number,
72            block_hash,
73            state_root: leaf_data.state_root.into(),
74            extrinsics_root: leaf_data.extrinsics_root.into(),
75        })
76    }
77}