Skip to main content

sp_domains_fraud_proof/
execution_prover.rs

1//! This module provides the feature of generating and verifying the execution proof used in
2//! the Subspace fraud proof mechanism.
3//!
4//! The execution is more fine-grained than the entire block execution, block execution hooks
5//! (`initialize_block` and `finalize_block`) and any specific extrinsic execution are supported.
6
7use crate::fraud_proof::ExecutionPhase;
8use domain_block_builder::create_delta_backend;
9use sc_client_api::backend::Backend;
10use sp_api::StorageProof;
11use sp_core::traits::CodeExecutor;
12use sp_runtime::traits::{Block as BlockT, HashingFor};
13use sp_state_machine::BackendTransaction;
14use sp_state_machine::backend::AsTrieBackend;
15use std::marker::PhantomData;
16use std::sync::Arc;
17
18/// Creates storage proof for verifying an execution without owning the whole state.
19pub struct ExecutionProver<Block, B, Exec> {
20    backend: Arc<B>,
21    executor: Arc<Exec>,
22    _phantom: PhantomData<Block>,
23}
24
25impl<Block, B, Exec> ExecutionProver<Block, B, Exec>
26where
27    Block: BlockT,
28    B: Backend<Block>,
29    Exec: CodeExecutor + 'static,
30{
31    /// Constructs a new instance of [`ExecutionProver`].
32    pub fn new(backend: Arc<B>, executor: Arc<Exec>) -> Self {
33        Self {
34            backend,
35            executor,
36            _phantom: PhantomData::<Block>,
37        }
38    }
39
40    /// Returns a storage proof which can be used to reconstruct a partial state trie to re-run
41    /// the execution by someone who does not own the whole state.
42    pub fn prove_execution(
43        &self,
44        at: Block::Hash,
45        execution_phase: &ExecutionPhase,
46        call_data: &[u8],
47        delta_changes: Option<(BackendTransaction<HashingFor<Block>>, Block::Hash)>,
48    ) -> sp_blockchain::Result<StorageProof> {
49        // Trusted: bounded block-processing context (fraud proof generation)
50        let state = self
51            .backend
52            .state_at(at, sc_client_api::TrieCacheContext::Trusted)?;
53
54        let trie_backend = state.as_trie_backend();
55
56        let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_backend);
57        let runtime_code = state_runtime_code
58            .runtime_code()
59            .map_err(sp_blockchain::Error::RuntimeCode)?;
60
61        // TODO: avoid using the String API specified by `execution_method()`
62        // https://github.com/paritytech/substrate/discussions/11095
63        if let Some((delta, post_delta_root)) = delta_changes {
64            let delta_backend = create_delta_backend(trie_backend, &delta, post_delta_root);
65            sp_state_machine::prove_execution_on_trie_backend(
66                &delta_backend,
67                &mut Default::default(),
68                &*self.executor,
69                execution_phase.execution_method(),
70                call_data,
71                &runtime_code,
72                &mut Default::default(),
73            )
74            .map(|(_ret, proof)| proof)
75            .map_err(Into::into)
76        } else {
77            sp_state_machine::prove_execution_on_trie_backend(
78                trie_backend,
79                &mut Default::default(),
80                &*self.executor,
81                execution_phase.execution_method(),
82                call_data,
83                &runtime_code,
84                &mut Default::default(),
85            )
86            .map(|(_ret, proof)| proof)
87            .map_err(Into::into)
88        }
89    }
90}