-
Notifications
You must be signed in to change notification settings - Fork 248
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
140 additions
and
19 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +1,176 @@ | ||
//! 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<State, Block> = | ||
<State as StateBackend<HashingFor<Block>>>::TrieBackendStorage; | ||
|
||
type TrieDeltaBackendFor<'a, State, Block> = TrieBackend< | ||
DeltaBackend<'a, TrieBackendStorageFor<State, Block>, HashingFor<Block>>, | ||
HashingFor<Block>, | ||
>; | ||
|
||
type TrieBackendFor<State, Block> = | ||
TrieBackend<TrieBackendStorageFor<State, Block>, HashingFor<Block>>; | ||
|
||
/// 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<S, H>, | ||
delta: BackendTransaction<H>, | ||
post_delta_root: H::Out, | ||
) -> TrieBackend<DeltaBackend<'a, S, H>, H> | ||
where | ||
S: 'a + TrieBackendStorage<H>, | ||
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<S, H>, | ||
delta: DB, | ||
maybe_delta: Option<BackendTransaction<H>>, | ||
post_delta_root: H::Out, | ||
) -> TrieBackend<DeltaBackend<'a, S, H, DB>, H> | ||
) -> TrieBackend<DeltaBackend<'a, S, H>, H> | ||
where | ||
S: 'a + TrieBackendStorage<H>, | ||
H: 'a + Hasher, | ||
H::Out: Codec, | ||
DB: HashDB<H, DBValue>, | ||
{ | ||
let essence = backend.essence(); | ||
let delta_backend = DeltaBackend { | ||
backend: essence.backend_storage(), | ||
delta, | ||
delta: maybe_delta, | ||
_phantom: PhantomData::<H>, | ||
}; | ||
TrieBackendBuilder::new(delta_backend, post_delta_root).build() | ||
} | ||
|
||
/// 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>, | ||
H: 'a + Hasher, | ||
DB: HashDB<H, DBValue>, | ||
{ | ||
backend: &'a S, | ||
delta: DB, | ||
delta: Option<BackendTransaction<H>>, | ||
_phantom: PhantomData<H>, | ||
} | ||
|
||
impl<'a, S, H, DB> TrieBackendStorage<H> for DeltaBackend<'a, S, H, DB> | ||
impl<'a, S, H> TrieBackendStorage<H> for DeltaBackend<'a, S, H> | ||
where | ||
S: 'a + TrieBackendStorage<H>, | ||
H: 'a + Hasher, | ||
DB: HashDB<H, DBValue>, | ||
{ | ||
fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<DBValue>, 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>, | ||
H: 'a + Hasher, | ||
{ | ||
fn consolidate_delta(&mut self, db: BackendTransaction<H>) { | ||
let delta = if let Some(mut delta) = self.delta.take() { | ||
delta.consolidate(db); | ||
delta | ||
} else { | ||
db | ||
}; | ||
self.delta = Some(delta); | ||
} | ||
} | ||
|
||
pub(crate) struct TrieBackendApi<Client, Block: BlockT, Backend, Exec> { | ||
parent_hash: Block::Hash, | ||
parent_number: NumberFor<Block>, | ||
client: Arc<Client>, | ||
backend: Arc<Backend>, | ||
executor: Exec, | ||
maybe_storage_changes: Option<StorageChanges<HashingFor<Block>>>, | ||
} | ||
|
||
impl<Client, Block, Backend, Exec> TrieBackendApi<Client, Block, Backend, Exec> | ||
where | ||
Block: BlockT, | ||
Backend: backend::Backend<Block>, | ||
Client: ExecutorProvider<Block>, | ||
Exec: CodeExecutor, | ||
{ | ||
pub(crate) fn new( | ||
parent_hash: Block::Hash, | ||
parent_number: NumberFor<Block>, | ||
client: Arc<Client>, | ||
backend: Arc<Backend>, | ||
executor: Exec, | ||
) -> Result<Self, sp_blockchain::Error> { | ||
Ok(Self { | ||
parent_hash, | ||
parent_number, | ||
client, | ||
backend, | ||
executor, | ||
maybe_storage_changes: None, | ||
}) | ||
} | ||
|
||
fn call_function<R: Decode>( | ||
&mut self, | ||
method: String, | ||
call_data: Vec<u8>, | ||
trie_backend: &TrieDeltaBackendFor<Backend::State, Block>, | ||
overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>, | ||
) -> Result<R, sp_blockchain::Error> { | ||
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)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters