From 5c887d3c8c5ee5cb655d0553b5dfdb0b60578b36 Mon Sep 17 00:00:00 2001 From: vedhavyas Date: Mon, 6 Jan 2025 17:56:49 +0530 Subject: [PATCH] add trie backend api --- Cargo.lock | 1 + .../src/execution_prover.rs | 7 +- domains/client/block-builder/Cargo.toml | 1 + .../client/block-builder/src/custom_api.rs | 149 ++++++++++++++++-- domains/client/block-builder/src/lib.rs | 1 + 5 files changed, 140 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0222643f16..c65d4830d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2513,6 +2513,7 @@ dependencies = [ "sp-block-builder", "sp-blockchain", "sp-core", + "sp-externalities", "sp-inherents", "sp-runtime", "sp-state-machine", diff --git a/crates/sp-domains-fraud-proof/src/execution_prover.rs b/crates/sp-domains-fraud-proof/src/execution_prover.rs index 84fe2919a4..3414d1c282 100644 --- a/crates/sp-domains-fraud-proof/src/execution_prover.rs +++ b/crates/sp-domains-fraud-proof/src/execution_prover.rs @@ -6,13 +6,12 @@ use crate::fraud_proof::ExecutionPhase; use domain_block_builder::create_delta_backend; -use hash_db::HashDB; use sc_client_api::backend::Backend; use sp_api::StorageProof; use sp_core::traits::CodeExecutor; use sp_runtime::traits::{Block as BlockT, HashingFor}; use sp_state_machine::backend::AsTrieBackend; -use sp_trie::DBValue; +use sp_state_machine::BackendTransaction; use std::marker::PhantomData; use std::sync::Arc; @@ -40,12 +39,12 @@ where /// Returns a storage proof which can be used to reconstruct a partial state trie to re-run /// the execution by someone who does not own the whole state. - pub fn prove_execution, DBValue>>( + pub fn prove_execution( &self, at: Block::Hash, execution_phase: &ExecutionPhase, call_data: &[u8], - delta_changes: Option<(DB, Block::Hash)>, + delta_changes: Option<(BackendTransaction>, Block::Hash)>, ) -> sp_blockchain::Result { let state = self.backend.state_at(at)?; diff --git a/domains/client/block-builder/Cargo.toml b/domains/client/block-builder/Cargo.toml index 18daefca98..5798ca4122 100644 --- a/domains/client/block-builder/Cargo.toml +++ b/domains/client/block-builder/Cargo.toml @@ -20,6 +20,7 @@ sp-api = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89 sp-blockchain = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305" } sp-block-builder = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305" } sp-core = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305" } +sp-externalities = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305" } sp-inherents = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305" } sp-runtime = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305" } sp-state-machine = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305" } diff --git a/domains/client/block-builder/src/custom_api.rs b/domains/client/block-builder/src/custom_api.rs index f07aba67da..fc5347c644 100644 --- a/domains/client/block-builder/src/custom_api.rs +++ b/domains/client/block-builder/src/custom_api.rs @@ -1,29 +1,63 @@ //! Custom API that is efficient to collect storage roots. -use codec::Codec; +// TODO: remove in later commits +#![allow(dead_code)] + +use codec::{Codec, Decode}; use hash_db::{HashDB, Hasher, Prefix}; -use sp_state_machine::{DBValue, TrieBackend, TrieBackendBuilder, TrieBackendStorage}; +use sc_client_api::{backend, ExecutorProvider, StateBackend}; +use sp_core::traits::{CallContext, CodeExecutor}; +use sp_runtime::traits::{Block as BlockT, HashingFor, NumberFor}; +use sp_state_machine::backend::AsTrieBackend; +use sp_state_machine::{ + BackendTransaction, DBValue, OverlayedChanges, StateMachine, StorageChanges, TrieBackend, + TrieBackendBuilder, TrieBackendStorage, +}; use std::marker::PhantomData; +use std::sync::Arc; + +type TrieBackendStorageFor = + >>::TrieBackendStorage; + +type TrieDeltaBackendFor<'a, State, Block> = TrieBackend< + DeltaBackend<'a, TrieBackendStorageFor, HashingFor>, + HashingFor, +>; + +type TrieBackendFor = + TrieBackend, HashingFor>; /// Create a new trie backend with memory DB delta changes. /// /// This can be used to verify any extrinsic-specific execution on the combined state of `backend` /// and `delta`. -pub fn create_delta_backend<'a, S, H, DB>( +pub fn create_delta_backend<'a, S, H>( + backend: &'a TrieBackend, + delta: BackendTransaction, + post_delta_root: H::Out, +) -> TrieBackend, H> +where + S: 'a + TrieBackendStorage, + H: 'a + Hasher, + H::Out: Codec, +{ + create_delta_backend_without_delta(backend, Some(delta), post_delta_root) +} + +fn create_delta_backend_without_delta<'a, S, H>( backend: &'a TrieBackend, - delta: DB, + maybe_delta: Option>, post_delta_root: H::Out, -) -> TrieBackend, H> +) -> TrieBackend, H> where S: 'a + TrieBackendStorage, H: 'a + Hasher, H::Out: Codec, - DB: HashDB, { let essence = backend.essence(); let delta_backend = DeltaBackend { backend: essence.backend_storage(), - delta, + delta: maybe_delta, _phantom: PhantomData::, }; TrieBackendBuilder::new(delta_backend, post_delta_root).build() @@ -31,27 +65,112 @@ where /// DeltaBackend provides the TrieBackend using main backend and some delta changes /// that are not part of the main backend. -pub struct DeltaBackend<'a, S, H, DB> +pub struct DeltaBackend<'a, S, H> where S: 'a + TrieBackendStorage, H: 'a + Hasher, - DB: HashDB, { backend: &'a S, - delta: DB, + delta: Option>, _phantom: PhantomData, } -impl<'a, S, H, DB> TrieBackendStorage for DeltaBackend<'a, S, H, DB> +impl<'a, S, H> TrieBackendStorage for DeltaBackend<'a, S, H> where S: 'a + TrieBackendStorage, H: 'a + Hasher, - DB: HashDB, { fn get(&self, key: &H::Out, prefix: Prefix) -> Result, String> { - match HashDB::get(&self.delta, key, prefix) { - Some(v) => Ok(Some(v)), - None => Ok(self.backend.get(key, prefix)?), + if let Some(db) = &self.delta + && let Some(v) = HashDB::get(db, key, prefix) + { + Ok(Some(v)) + } else { + Ok(self.backend.get(key, prefix)?) } } } + +impl<'a, S, H> DeltaBackend<'a, S, H> +where + S: 'a + TrieBackendStorage, + H: 'a + Hasher, +{ + fn consolidate_delta(&mut self, db: BackendTransaction) { + let delta = if let Some(mut delta) = self.delta.take() { + delta.consolidate(db); + delta + } else { + db + }; + self.delta = Some(delta); + } +} + +pub(crate) struct TrieBackendApi { + parent_hash: Block::Hash, + parent_number: NumberFor, + client: Arc, + backend: Arc, + executor: Exec, + maybe_storage_changes: Option>>, +} + +impl TrieBackendApi +where + Block: BlockT, + Backend: backend::Backend, + Client: ExecutorProvider, + Exec: CodeExecutor, +{ + pub(crate) fn new( + parent_hash: Block::Hash, + parent_number: NumberFor, + client: Arc, + backend: Arc, + executor: Exec, + ) -> Result { + Ok(Self { + parent_hash, + parent_number, + client, + backend, + executor, + maybe_storage_changes: None, + }) + } + + fn call_function( + &mut self, + method: String, + call_data: Vec, + trie_backend: &TrieDeltaBackendFor, + overlayed_changes: &mut OverlayedChanges>, + ) -> Result { + let state = self.backend.state_at(self.parent_hash)?; + let state_runtime_code = + sp_state_machine::backend::BackendRuntimeCode::new(state.as_trie_backend()); + let runtime_code = state_runtime_code + .runtime_code() + .map_err(sp_blockchain::Error::RuntimeCode)?; + let mut extensions = self + .client + .execution_extensions() + .extensions(self.parent_hash, self.parent_number); + + let result = StateMachine::<_, _, _>::new( + trie_backend, + overlayed_changes, + &self.executor, + &method, + call_data.as_slice(), + &mut extensions, + &runtime_code, + CallContext::Onchain, + ) + .execute()?; + + R::decode(&mut result.as_slice()) + .map_err(|err| sp_blockchain::Error::CallResultDecode("failed to decode Result", err)) + } +} diff --git a/domains/client/block-builder/src/lib.rs b/domains/client/block-builder/src/lib.rs index 2df5c4f910..f37c51b7e3 100644 --- a/domains/client/block-builder/src/lib.rs +++ b/domains/client/block-builder/src/lib.rs @@ -25,6 +25,7 @@ //! initialize a block, to push extrinsics and to finalize a block. #![warn(missing_docs)] +#![feature(let_chains)] mod custom_api;