Remove requirement on Hash = H256, make Proposer return StorageChanges and Proof (#3860)

* Extend `Proposer` to optionally generate a proof of the proposal

* Something

* Refactor sr-api to not depend on client anymore

* Fix benches

* Apply suggestions from code review

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Apply suggestions from code review

* Introduce new `into_storage_changes` function

* Switch to runtime api for `execute_block` and don't require `H256`
anywhere in the code

* Put the `StorageChanges` into the `Proposal`

* Move the runtime api error to its own trait

* Adds `StorageTransactionCache` to the runtime api

This requires that we add `type NodeBlock = ` to the
`impl_runtime_apis!` macro to work around some bugs in rustc :(

* Remove `type NodeBlock` and switch to a "better" hack

* Start using the transaction cache from the runtime api

* Make it compile

* Move `InMemory` to its own file

* Make all tests work again

* Return block, storage_changes and proof from Blockbuilder::bake()

* Make sure that we use/set `storage_changes` when possible

* Add test

* Fix deadlock

* Remove accidentally added folders

* Introduce `RecordProof` as argument type to be more explicit

* Update client/src/client.rs

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Update primitives/state-machine/src/ext.rs

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Integrates review feedback

* Remove `unsafe` usage

* Update client/block-builder/src/lib.rs

Co-Authored-By: Benjamin Kampmann <ben@gnunicorn.org>

* Update client/src/call_executor.rs

* Bump versions

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
Co-authored-by: Benjamin Kampmann <ben.kampmann@googlemail.com>
This commit is contained in:
Bastian Köcher
2020-01-10 10:48:32 +01:00
committed by GitHub
parent 74d6e660c6
commit fd6b29dd2c
140 changed files with 4860 additions and 3339 deletions
+156 -32
View File
@@ -26,7 +26,7 @@
//! functionality that every runtime needs to export.
//!
//! Besides the macros and the [`Core`] runtime api, this crates provides the [`Metadata`] runtime
//! api, the [`ApiExt`] trait, the [`CallRuntimeAt`] trait and the [`ConstructRuntimeApi`] trait.
//! api, the [`ApiExt`] trait, the [`CallApiAt`] trait and the [`ConstructRuntimeApi`] trait.
#![cfg_attr(not(feature = "std"), no_std)]
@@ -35,18 +35,23 @@ extern crate self as sp_api;
#[doc(hidden)]
#[cfg(feature = "std")]
pub use sp_state_machine::{OverlayedChanges, StorageProof};
pub use sp_state_machine::{
OverlayedChanges, StorageProof, Backend as StateBackend, ChangesTrieStorage,
};
#[doc(hidden)]
#[cfg(feature = "std")]
pub use sp_core::NativeOrEncoded;
#[doc(hidden)]
#[cfg(feature = "std")]
pub use hash_db::Hasher;
#[doc(hidden)]
#[cfg(not(feature = "std"))]
pub use sp_core::to_substrate_wasm_fn_return_value;
#[doc(hidden)]
pub use sp_runtime::{
traits::{
Block as BlockT, GetNodeBlockType, GetRuntimeBlockType,
Header as HeaderT, ApiRef, RuntimeApiInfo, Hash as HashT,
Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, HasherFor, NumberFor,
Header as HeaderT, Hash as HashT,
},
generic::BlockId, transaction_validity::TransactionValidity,
};
@@ -157,8 +162,8 @@ pub use sp_api_proc_macro::decl_runtime_apis;
/// ```rust
/// use sp_version::create_runtime_str;
/// #
/// # use sp_runtime::traits::GetNodeBlockType;
/// # use sp_test_primitives::{Block, Header};
/// # use sp_runtime::traits::{GetNodeBlockType, Block as BlockT};
/// # use sp_test_primitives::Block;
/// #
/// # /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType`
/// # /// trait are done by the `construct_runtime!` macro in a real runtime.
@@ -187,7 +192,7 @@ pub use sp_api_proc_macro::decl_runtime_apis;
/// # unimplemented!()
/// # }
/// # fn execute_block(_block: Block) {}
/// # fn initialize_block(_header: &Header) {}
/// # fn initialize_block(_header: &<Block as BlockT>::Header) {}
/// # }
///
/// impl self::Balance<Block> for Runtime {
@@ -221,27 +226,60 @@ pub use sp_api_proc_macro::decl_runtime_apis;
/// ```
pub use sp_api_proc_macro::impl_runtime_apis;
#[cfg(feature = "std")]
/// A type that records all accessed trie nodes and generates a proof out of it.
#[cfg(feature = "std")]
pub type ProofRecorder<B> = sp_state_machine::ProofRecorder<
<<<B as BlockT>::Header as HeaderT>::Hashing as HashT>::Hasher
>;
/// A type that is used as cache for the storage transactions.
#[cfg(feature = "std")]
pub type StorageTransactionCache<Block, Backend> =
sp_state_machine::StorageTransactionCache<
<Backend as StateBackend<HasherFor<Block>>>::Transaction, HasherFor<Block>, NumberFor<Block>
>;
#[cfg(feature = "std")]
pub type StorageChanges<SBackend, Block> =
sp_state_machine::StorageChanges<
<SBackend as StateBackend<HasherFor<Block>>>::Transaction,
HasherFor<Block>,
NumberFor<Block>
>;
/// Extract the state backend type for a type that implements `ProvideRuntimeApi`.
#[cfg(feature = "std")]
pub type StateBackendFor<P, Block> =
<<P as ProvideRuntimeApi<Block>>::Api as ApiExt<Block>>::StateBackend;
/// Extract the state backend transaction type for a type that implements `ProvideRuntimeApi`.
#[cfg(feature = "std")]
pub type TransactionFor<P, Block> =
<StateBackendFor<P, Block> as StateBackend<HasherFor<Block>>>::Transaction;
/// Something that can be constructed to a runtime api.
#[cfg(feature = "std")]
pub trait ConstructRuntimeApi<Block: BlockT, C: CallRuntimeAt<Block>> {
pub trait ConstructRuntimeApi<Block: BlockT, C: CallApiAt<Block>> {
/// The actual runtime api that will be constructed.
type RuntimeApi;
type RuntimeApi: ApiExt<Block>;
/// Construct an instance of the runtime api.
fn construct_runtime_api<'a>(call: &'a C) -> ApiRef<'a, Self::RuntimeApi>;
}
/// An extension for the `RuntimeApi`.
/// Extends the runtime api traits with an associated error type. This trait is given as super
/// trait to every runtime api trait.
#[cfg(feature = "std")]
pub trait ApiExt<Block: BlockT> {
/// Error type used by the interface.
pub trait ApiErrorExt {
/// Error type used by the runtime apis.
type Error: std::fmt::Debug + From<String>;
}
/// Extends the runtime api implementation with some common functionality.
#[cfg(feature = "std")]
pub trait ApiExt<Block: BlockT>: ApiErrorExt {
/// The state backend that is used to store the block states.
type StateBackend: StateBackend<HasherFor<Block>>;
/// The given closure will be called with api instance. Inside the closure any api call is
/// allowed. After doing the api call, the closure is allowed to map the `Result` to a
@@ -250,15 +288,15 @@ pub trait ApiExt<Block: BlockT> {
/// On `Ok`, the structure commits the changes to an internal buffer.
fn map_api_result<F: FnOnce(&Self) -> result::Result<R, E>, R, E>(
&self,
map_call: F
map_call: F,
) -> result::Result<R, E> where Self: Sized;
/// Checks if the given api is implemented and versions match.
fn has_api<A: RuntimeApiInfo + ?Sized>(
&self,
at: &BlockId<Block>
at: &BlockId<Block>,
) -> Result<bool, Self::Error> where Self: Sized {
self.runtime_version_at(at).map(|v| v.has_api::<A>())
self.runtime_version_at(at).map(|v| v.has_api_with(&A::ID, |v| v == A::VERSION))
}
/// Check if the given api is implemented and the version passes a predicate.
@@ -267,7 +305,7 @@ pub trait ApiExt<Block: BlockT> {
at: &BlockId<Block>,
pred: P,
) -> Result<bool, Self::Error> where Self: Sized {
self.runtime_version_at(at).map(|v| v.has_api_with::<A, _>(pred))
self.runtime_version_at(at).map(|v| v.has_api_with(&A::ID, pred))
}
/// Returns the runtime version at the given block id.
@@ -277,8 +315,22 @@ pub trait ApiExt<Block: BlockT> {
fn record_proof(&mut self);
/// Extract the recorded proof.
///
/// This stops the proof recording.
///
/// If `record_proof` was not called before, this will return `None`.
fn extract_proof(&mut self) -> Option<StorageProof>;
/// Convert the api object into the storage changes that were done while executing runtime
/// api functions.
///
/// After executing this function, all collected changes are reset.
fn into_storage_changes<T: ChangesTrieStorage<HasherFor<Block>, NumberFor<Block>>>(
&self,
backend: &Self::StateBackend,
changes_trie_storage: Option<&T>,
parent_hash: Block::Hash,
) -> Result<StorageChanges<Self::StateBackend, Block>, String> where Self: Sized;
}
/// Before calling any runtime api function, the runtime need to be initialized
@@ -301,12 +353,44 @@ pub enum InitializeBlock<'a, Block: BlockT> {
Do(&'a RefCell<Option<BlockId<Block>>>),
}
/// Something that can call into the runtime at a given block.
/// Parameters for [`CallApiAt::call_api_at`].
#[cfg(feature = "std")]
pub trait CallRuntimeAt<Block: BlockT> {
/// Error type used by the interface.
pub struct CallApiAtParams<'a, Block: BlockT, C, NC, Backend: StateBackend<HasherFor<Block>>> {
/// A reference to something that implements the [`Core`] api.
pub core_api: &'a C,
/// The block id that determines the state that should be setup when calling the function.
pub at: &'a BlockId<Block>,
/// The name of the function that should be called.
pub function: &'static str,
/// An optional native call that calls the `function`. This is an optimization to call into a
/// native runtime without requiring to encode/decode the parameters. The native runtime can
/// still be called when this value is `None`, we then just fallback to encoding/decoding the
/// parameters.
pub native_call: Option<NC>,
/// The encoded arguments of the function.
pub arguments: Vec<u8>,
/// The overlayed changes that are on top of the state.
pub overlayed_changes: &'a RefCell<OverlayedChanges>,
/// The cache for storage transactions.
pub storage_transaction_cache: &'a RefCell<StorageTransactionCache<Block, Backend>>,
/// Determines if the function requires that `initialize_block` should be called before calling
/// the actual function.
pub initialize_block: InitializeBlock<'a, Block>,
/// The context this function is executed in.
pub context: ExecutionContext,
/// The optional proof recorder for recording storage accesses.
pub recorder: &'a Option<ProofRecorder<Block>>,
}
/// Something that can call into the an api at a given block.
#[cfg(feature = "std")]
pub trait CallApiAt<Block: BlockT> {
/// Error type used by the implementation.
type Error: std::fmt::Debug + From<String>;
/// The state backend that is used to store the block states.
type StateBackend: StateBackend<HasherFor<Block>>;
/// Calls the given api function with the given encoded arguments at the given block and returns
/// the encoded result.
fn call_api_at<
@@ -316,26 +400,66 @@ pub trait CallRuntimeAt<Block: BlockT> {
C: Core<Block, Error = Self::Error>,
>(
&self,
core_api: &C,
at: &BlockId<Block>,
function: &'static str,
args: Vec<u8>,
changes: &RefCell<OverlayedChanges>,
initialize_block: InitializeBlock<'a, Block>,
native_call: Option<NC>,
context: ExecutionContext,
recorder: &Option<ProofRecorder<Block>>,
params: CallApiAtParams<'a, Block, C, NC, Self::StateBackend>,
) -> Result<NativeOrEncoded<R>, Self::Error>;
/// Returns the runtime version at the given block.
fn runtime_version_at(&self, at: &BlockId<Block>) -> Result<RuntimeVersion, Self::Error>;
}
/// Auxiliary wrapper that holds an api instance and binds it to the given lifetime.
#[cfg(feature = "std")]
pub struct ApiRef<'a, T>(T, std::marker::PhantomData<&'a ()>);
#[cfg(feature = "std")]
impl<'a, T> From<T> for ApiRef<'a, T> {
fn from(api: T) -> Self {
ApiRef(api, Default::default())
}
}
#[cfg(feature = "std")]
impl<'a, T> std::ops::Deref for ApiRef<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(feature = "std")]
impl<'a, T> std::ops::DerefMut for ApiRef<'a, T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
/// Something that provides a runtime api.
#[cfg(feature = "std")]
pub trait ProvideRuntimeApi<Block: BlockT> {
/// The concrete type that provides the api.
type Api: ApiExt<Block>;
/// Returns the runtime api.
/// The returned instance will keep track of modifications to the storage. Any successful
/// call to an api function, will `commit` its changes to an internal buffer. Otherwise,
/// the modifications will be `discarded`. The modifications will not be applied to the
/// storage, even on a `commit`.
fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api>;
}
/// Something that provides information about a runtime api.
#[cfg(feature = "std")]
pub trait RuntimeApiInfo {
/// The identifier of the runtime api.
const ID: [u8; 8];
/// The version of the runtime api.
const VERSION: u32;
}
/// Extracts the `Api::Error` for a type that provides a runtime api.
#[cfg(feature = "std")]
pub type ApiErrorFor<T, Block> = <
<T as sp_runtime::traits::ProvideRuntimeApi>::Api as ApiExt<Block>
>::Error;
pub type ApiErrorFor<T, Block> = <<T as ProvideRuntimeApi<Block>>::Api as ApiErrorExt>::Error;
decl_runtime_apis! {
/// The `Core` runtime api that every Substrate runtime needs to implement.