Do not call initialize_block before any runtime api (#8953)

* Do not call `initialize_block` before any runtime api

Before this change we always called `initialize_block` before calling
into the runtime. There was already support with `skip_initialize` to skip
the initialization. Almost no runtime_api requires that
`initialize_block` is called before. Actually this only leads to higher
execution times most of the time, because all runtime modules are
initialized and this is especially expensive when the block contained a
runtime upgrade.

TLDR: Do not call `initialize_block` before calling a runtime api.

* Change `validate_transaction` interface

* Fix rpc test

* Fixes and comments

* Some docs
This commit is contained in:
Bastian Köcher
2021-07-01 17:50:42 +02:00
committed by GitHub
parent 73a6e3effc
commit d489bd70b5
23 changed files with 192 additions and 301 deletions
+39 -42
View File
@@ -17,20 +17,29 @@
//! Substrate runtime api
//!
//! The Substrate runtime api is the crucial interface between the node and the runtime.
//! Every call that goes into the runtime is done with a runtime api. The runtime apis are not fixed.
//! Every Substrate user can define its own apis with
//! [`decl_runtime_apis`](macro.decl_runtime_apis.html) and implement them in
//! the runtime with [`impl_runtime_apis`](macro.impl_runtime_apis.html).
//! The Substrate runtime api is the interface between the node and the runtime. There isn't a fixed
//! set of runtime apis, instead it is up to the user to declare and implement these runtime apis.
//! The declaration of a runtime api is normally done outside of a runtime, while the implementation
//! of it has to be done in the runtime. We provide the [`decl_runtime_apis!`] macro for declaring
//! a runtime api and the [`impl_runtime_apis!`] for implementing them. The macro docs provide more
//! information on how to use them and what kind of attributes we support.
//!
//! Every Substrate runtime needs to implement the [`Core`] runtime api. This api provides the basic
//! functionality that every runtime needs to export.
//! It is required that each runtime implements at least the [`Core`] runtime api. This runtime api
//! provides all the core functions that Substrate expects from a runtime.
//!
//! Besides the macros and the [`Core`] runtime api, this crates provides the [`Metadata`] runtime
//! api, the [`ApiExt`] trait, the [`CallApiAt`] trait and the [`ConstructRuntimeApi`] trait.
//! # Versioning
//!
//! On a meta level this implies, the client calls the generated API from the client perspective.
//! Runtime apis support versioning. Each runtime api itself has a version attached. It is also
//! supported to change function signatures or names in a non-breaking way. For more information on
//! versioning check the [`decl_runtime_apis!`] macro.
//!
//! All runtime apis and their versions are returned as part of the [`RuntimeVersion`]. This can be
//! used to check which runtime api version is currently provided by the on-chain runtime.
//!
//! # Testing
//!
//! For testing we provide the [`mock_impl_runtime_apis!`] macro that lets you implement a runtime
//! api for a mocked object to use it in tests.
//!
//! # Logging
//!
@@ -43,6 +52,17 @@
//! that this feature instructs `log` and `tracing` to disable logging at compile time by setting
//! the `max_level_off` feature for these crates. So, you should not enable this feature for a
//! native build as otherwise the node will not output any log messages.
//!
//! # How does it work?
//!
//! Each runtime api is declared as a trait with functions. When compiled to WASM, each implemented
//! runtime api function is exported as a function with the following naming scheme
//! `${TRAIT_NAME}_${FUNCTION_NAME}`. Such a function has the following signature
//! `(ptr: *u8, length: u32) -> u64`. It takes a pointer to an `u8` array and its length as an
//! argument. This `u8` array is expected to be the SCALE encoded parameters of the function as
//! defined in the trait. The return value is an `u64` that represents `length << 32 | pointer` of an
//! `u8` array. This return value `u8` array contains the SCALE encoded return value as defined by
//! the trait function. The macros take care to encode the parameters and to decode the return value.
#![cfg_attr(not(feature = "std"), no_std)]
@@ -99,7 +119,7 @@ pub const MAX_EXTRINSIC_DEPTH: u32 = 256;
/// to the client side and the runtime side. This generic parameter is usable by the user.
///
/// For implementing these macros you should use the
/// [`impl_runtime_apis!`](macro.impl_runtime_apis.html) macro.
/// [`impl_runtime_apis!`] macro.
///
/// # Example
///
@@ -461,6 +481,12 @@ pub trait ApiExt<Block: BlockT> {
pred: P,
) -> Result<bool, ApiError> where Self: Sized;
/// Returns the version of the given api.
fn api_version<A: RuntimeApiInfo + ?Sized>(
&self,
at: &BlockId<Block>,
) -> Result<Option<u32>, ApiError> where Self: Sized;
/// Start recording all accessed trie nodes for generating proofs.
fn record_proof(&mut self);
@@ -489,31 +515,9 @@ pub trait ApiExt<Block: BlockT> {
> where Self: Sized;
}
/// Before calling any runtime api function, the runtime need to be initialized
/// at the requested block. However, some functions like `execute_block` or
/// `initialize_block` itself don't require to have the runtime initialized
/// at the requested block.
///
/// `call_api_at` is instructed by this enum to do the initialization or to skip
/// it.
#[cfg(feature = "std")]
#[derive(Clone, Copy)]
pub enum InitializeBlock<'a, Block: BlockT> {
/// Skip initializing the runtime for a given block.
///
/// This is used by functions who do the initialization by themselves or don't require it.
Skip,
/// Initialize the runtime for a given block.
///
/// If the stored `BlockId` is `Some(_)`, the runtime is currently initialized at this block.
Do(&'a RefCell<Option<BlockId<Block>>>),
}
/// Parameters for [`CallApiAt::call_api_at`].
#[cfg(feature = "std")]
pub struct CallApiAtParams<'a, Block: BlockT, C, NC, Backend: StateBackend<HashFor<Block>>> {
/// A reference to something that implements the [`Core`] api.
pub core_api: &'a C,
pub struct CallApiAtParams<'a, Block: BlockT, NC, Backend: StateBackend<HashFor<Block>>> {
/// 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.
@@ -529,9 +533,6 @@ pub struct CallApiAtParams<'a, Block: BlockT, C, NC, Backend: StateBackend<HashF
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.
@@ -550,10 +551,9 @@ pub trait CallApiAt<Block: BlockT> {
'a,
R: Encode + Decode + PartialEq,
NC: FnOnce() -> result::Result<R, ApiError> + UnwindSafe,
C: Core<Block>,
>(
&self,
params: CallApiAtParams<'a, Block, C, NC, Self::StateBackend>,
params: CallApiAtParams<'a, Block, NC, Self::StateBackend>,
) -> Result<NativeOrEncoded<R>, ApiError>;
/// Returns the runtime version at the given block.
@@ -704,12 +704,9 @@ decl_runtime_apis! {
#[changed_in(3)]
fn version() -> OldRuntimeVersion;
/// Execute the given block.
#[skip_initialize_block]
fn execute_block(block: Block);
/// Initialize a block with the given header.
#[renamed("initialise_block", 2)]
#[skip_initialize_block]
#[initialize_block]
fn initialize_block(header: &<Block as BlockT>::Header);
}