sc_domains/
lib.rs

1//! Domain specific Host functions and Extension factory
2
3pub mod domain_block_er;
4
5use sc_client_api::execution_extensions::ExtensionsFactory as ExtensionsFactoryT;
6use sc_executor::RuntimeVersionOf;
7use sp_api::ProvideRuntimeApi;
8use sp_blockchain::HeaderBackend;
9use sp_core::traits::CodeExecutor;
10use sp_core::H256;
11use sp_domains::DomainsApi;
12use sp_domains_fraud_proof::storage_proof::{
13    FraudProofStorageKeyProviderInstance, FraudProofStorageKeyRequest,
14};
15use sp_domains_fraud_proof::FraudProofApi;
16use sp_externalities::Extensions;
17use sp_messenger_host_functions::{MessengerApi, MessengerExtension, MessengerHostFunctionsImpl};
18use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor, One};
19use sp_subspace_mmr::host_functions::{MmrApi, SubspaceMmrExtension, SubspaceMmrHostFunctionsImpl};
20use sp_subspace_mmr::ConsensusChainMmrLeafProof;
21use std::marker::PhantomData;
22use std::sync::Arc;
23
24/// Host functions required for Subspace domain
25#[cfg(not(feature = "runtime-benchmarks"))]
26pub type HostFunctions = (
27    sp_auto_id::auto_id_runtime_interface::HostFunctions,
28    sp_io::SubstrateHostFunctions,
29    sp_messenger_host_functions::HostFunctions,
30    sp_subspace_mmr::DomainHostFunctions,
31);
32
33/// Host functions required for Subspace domain
34#[cfg(feature = "runtime-benchmarks")]
35pub type HostFunctions = (
36    sp_auto_id::auto_id_runtime_interface::HostFunctions,
37    sp_io::SubstrateHostFunctions,
38    sp_messenger_host_functions::HostFunctions,
39    sp_subspace_mmr::DomainHostFunctions,
40    frame_benchmarking::benchmarking::HostFunctions,
41);
42
43/// Runtime executor for Domains
44pub type RuntimeExecutor = sc_executor::WasmExecutor<HostFunctions>;
45
46/// Extensions factory for subspace domains.
47pub struct ExtensionsFactory<CClient, CBlock, Block, Executor> {
48    consensus_client: Arc<CClient>,
49    executor: Arc<Executor>,
50    confirmation_depth_k: u32,
51    _marker: PhantomData<(CBlock, Block)>,
52}
53
54impl<CClient, CBlock, Block, Executor> ExtensionsFactory<CClient, CBlock, Block, Executor> {
55    pub fn new(
56        consensus_client: Arc<CClient>,
57        executor: Arc<Executor>,
58        confirmation_depth_k: u32,
59    ) -> Self {
60        Self {
61            consensus_client,
62            executor,
63            confirmation_depth_k,
64            _marker: Default::default(),
65        }
66    }
67}
68
69impl<CClient, CBlock, Block, Executor> ExtensionsFactoryT<Block>
70    for ExtensionsFactory<CClient, CBlock, Block, Executor>
71where
72    Block: BlockT,
73    CBlock: BlockT,
74    CBlock::Hash: From<H256> + Into<H256>,
75    CClient: HeaderBackend<CBlock> + ProvideRuntimeApi<CBlock> + 'static,
76    CClient::Api: MmrApi<CBlock, H256, NumberFor<CBlock>>
77        + MessengerApi<CBlock, NumberFor<CBlock>, CBlock::Hash>
78        + DomainsApi<CBlock, Block::Header>,
79    Executor: CodeExecutor + RuntimeVersionOf,
80{
81    fn extensions_for(
82        &self,
83        _block_hash: Block::Hash,
84        _block_number: NumberFor<Block>,
85    ) -> Extensions {
86        let mut exts = Extensions::new();
87        exts.register(SubspaceMmrExtension::new(Arc::new(
88            SubspaceMmrHostFunctionsImpl::<CBlock, _>::new(
89                self.consensus_client.clone(),
90                self.confirmation_depth_k,
91            ),
92        )));
93
94        exts.register(MessengerExtension::new(Arc::new(
95            MessengerHostFunctionsImpl::<CBlock, _, Block, _>::new(
96                self.consensus_client.clone(),
97                self.executor.clone(),
98            ),
99        )));
100
101        exts.register(sp_auto_id::host_functions::HostFunctionExtension::new(
102            Arc::new(sp_auto_id::host_functions::HostFunctionsImpl),
103        ));
104
105        exts
106    }
107}
108
109pub struct FPStorageKeyProvider<CBlock, DomainHeader, CClient> {
110    consensus_client: Arc<CClient>,
111    _phantom: PhantomData<(CBlock, DomainHeader)>,
112}
113
114impl<CBlock, DomainHeader, CClient> Clone for FPStorageKeyProvider<CBlock, DomainHeader, CClient> {
115    fn clone(&self) -> Self {
116        Self {
117            consensus_client: self.consensus_client.clone(),
118            _phantom: self._phantom,
119        }
120    }
121}
122
123impl<CBlock, DomainHeader, CClient> FPStorageKeyProvider<CBlock, DomainHeader, CClient> {
124    pub fn new(consensus_client: Arc<CClient>) -> Self {
125        Self {
126            consensus_client,
127            _phantom: Default::default(),
128        }
129    }
130}
131
132impl<CBlock, DomainHeader, CClient> FraudProofStorageKeyProviderInstance<NumberFor<CBlock>>
133    for FPStorageKeyProvider<CBlock, DomainHeader, CClient>
134where
135    CBlock: BlockT,
136    DomainHeader: HeaderT,
137    CClient: HeaderBackend<CBlock> + ProvideRuntimeApi<CBlock> + 'static,
138    CClient::Api: FraudProofApi<CBlock, DomainHeader>,
139{
140    fn storage_key(&self, req: FraudProofStorageKeyRequest<NumberFor<CBlock>>) -> Option<Vec<u8>> {
141        let best_hash = self.consensus_client.info().best_hash;
142        self.consensus_client
143            .runtime_api()
144            .fraud_proof_storage_key(best_hash, req)
145            .ok()
146    }
147}
148
149/// Generate MMR proof for the block `to_prove` in the current best fork.
150///
151/// The returned proof can be later used to verify stateless (without query offchain MMR leaf) and
152/// extract the state root at `to_prove`.
153pub fn generate_mmr_proof<CClient, CBlock>(
154    consensus_client: &Arc<CClient>,
155    to_prove: NumberFor<CBlock>,
156) -> sp_blockchain::Result<ConsensusChainMmrLeafProof<NumberFor<CBlock>, CBlock::Hash, H256>>
157where
158    CBlock: BlockT,
159    CClient: HeaderBackend<CBlock> + ProvideRuntimeApi<CBlock> + 'static,
160    CClient::Api: MmrApi<CBlock, H256, NumberFor<CBlock>>,
161{
162    let api = consensus_client.runtime_api();
163    let prove_at_hash = consensus_client.info().best_hash;
164    let prove_at_number = consensus_client.info().best_number;
165
166    if to_prove >= prove_at_number {
167        return Err(sp_blockchain::Error::Application(Box::from(format!(
168            "Can't generate MMR proof for block {to_prove:?} >= best block {prove_at_number:?}"
169        ))));
170    }
171
172    let (mut leaves, proof) = api
173        // NOTE: the mmr leaf data is added in the next block so to generate the MMR proof of
174        // block `to_prove` we need to use `to_prove + 1` here.
175        .generate_proof(
176            prove_at_hash,
177            vec![to_prove + One::one()],
178            Some(prove_at_number),
179        )?
180        .map_err(|err| {
181            sp_blockchain::Error::Application(Box::from(format!(
182                "Failed to generate MMR proof: {err}"
183            )))
184        })?;
185    debug_assert!(leaves.len() == 1, "should always be of length 1");
186    let leaf = leaves
187        .pop()
188        .ok_or(sp_blockchain::Error::Application(Box::from(
189            "Unexpected missing mmr leaf".to_string(),
190        )))?;
191
192    Ok(ConsensusChainMmrLeafProof {
193        consensus_block_number: prove_at_number,
194        consensus_block_hash: prove_at_hash,
195        opaque_mmr_leaf: leaf,
196        proof,
197    })
198}