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::backend::AsTrieBackend;
14use sp_state_machine::BackendTransaction;
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        let state = self.backend.state_at(at)?;
50
51        let trie_backend = state.as_trie_backend();
52
53        let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_backend);
54        let runtime_code = state_runtime_code
55            .runtime_code()
56            .map_err(sp_blockchain::Error::RuntimeCode)?;
57
58        // TODO: avoid using the String API specified by `execution_method()`
59        // https://github.com/paritytech/substrate/discussions/11095
60        if let Some((delta, post_delta_root)) = delta_changes {
61            let delta_backend = create_delta_backend(trie_backend, &delta, post_delta_root);
62            sp_state_machine::prove_execution_on_trie_backend(
63                &delta_backend,
64                &mut Default::default(),
65                &*self.executor,
66                execution_phase.execution_method(),
67                call_data,
68                &runtime_code,
69                &mut Default::default(),
70            )
71            .map(|(_ret, proof)| proof)
72            .map_err(Into::into)
73        } else {
74            sp_state_machine::prove_execution_on_trie_backend(
75                trie_backend,
76                &mut Default::default(),
77                &*self.executor,
78                execution_phase.execution_method(),
79                call_data,
80                &runtime_code,
81                &mut Default::default(),
82            )
83            .map(|(_ret, proof)| proof)
84            .map_err(Into::into)
85        }
86    }
87}