mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 01:11:10 +00:00
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:
@@ -365,8 +365,9 @@ impl_runtime_apis! {
|
|||||||
fn validate_transaction(
|
fn validate_transaction(
|
||||||
source: TransactionSource,
|
source: TransactionSource,
|
||||||
tx: <Block as BlockT>::Extrinsic,
|
tx: <Block as BlockT>::Extrinsic,
|
||||||
|
block_hash: <Block as BlockT>::Hash,
|
||||||
) -> TransactionValidity {
|
) -> TransactionValidity {
|
||||||
Executive::validate_transaction(source, tx)
|
Executive::validate_transaction(source, tx, block_hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -256,12 +256,16 @@ fn submitted_transaction_should_be_valid() {
|
|||||||
<frame_system::Account<Runtime>>::insert(&address, account);
|
<frame_system::Account<Runtime>>::insert(&address, account);
|
||||||
|
|
||||||
// check validity
|
// check validity
|
||||||
let res = Executive::validate_transaction(source, extrinsic).unwrap();
|
let res = Executive::validate_transaction(
|
||||||
|
source,
|
||||||
|
extrinsic,
|
||||||
|
frame_system::BlockHash::<Runtime>::get(0),
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
// We ignore res.priority since this number can change based on updates to weights and such.
|
// We ignore res.priority since this number can change based on updates to weights and such.
|
||||||
assert_eq!(res.requires, Vec::<TransactionTag>::new());
|
assert_eq!(res.requires, Vec::<TransactionTag>::new());
|
||||||
assert_eq!(res.provides, vec![(address, 0).encode()]);
|
assert_eq!(res.provides, vec![(address, 0).encode()]);
|
||||||
assert_eq!(res.longevity, 2048);
|
assert_eq!(res.longevity, 2047);
|
||||||
assert_eq!(res.propagate, true);
|
assert_eq!(res.propagate, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1292,8 +1292,9 @@ impl_runtime_apis! {
|
|||||||
fn validate_transaction(
|
fn validate_transaction(
|
||||||
source: TransactionSource,
|
source: TransactionSource,
|
||||||
tx: <Block as BlockT>::Extrinsic,
|
tx: <Block as BlockT>::Extrinsic,
|
||||||
|
block_hash: <Block as BlockT>::Hash,
|
||||||
) -> TransactionValidity {
|
) -> TransactionValidity {
|
||||||
Executive::validate_transaction(source, tx)
|
Executive::validate_transaction(source, tx, block_hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ use sc_executor::{RuntimeVersion, NativeVersion};
|
|||||||
use sp_externalities::Extensions;
|
use sp_externalities::Extensions;
|
||||||
use sp_core::NativeOrEncoded;
|
use sp_core::NativeOrEncoded;
|
||||||
|
|
||||||
use sp_api::{ProofRecorder, InitializeBlock, StorageTransactionCache};
|
use sp_api::{ProofRecorder, StorageTransactionCache};
|
||||||
use crate::execution_extensions::ExecutionExtensions;
|
use crate::execution_extensions::ExecutionExtensions;
|
||||||
|
|
||||||
/// Executor Provider
|
/// Executor Provider
|
||||||
@@ -71,8 +71,6 @@ pub trait CallExecutor<B: BlockT> {
|
|||||||
/// Before executing the method, passed header is installed as the current header
|
/// Before executing the method, passed header is installed as the current header
|
||||||
/// of the execution context.
|
/// of the execution context.
|
||||||
fn contextual_call<
|
fn contextual_call<
|
||||||
'a,
|
|
||||||
IB: Fn() -> sp_blockchain::Result<()>,
|
|
||||||
EM: Fn(
|
EM: Fn(
|
||||||
Result<NativeOrEncoded<R>, Self::Error>,
|
Result<NativeOrEncoded<R>, Self::Error>,
|
||||||
Result<NativeOrEncoded<R>, Self::Error>
|
Result<NativeOrEncoded<R>, Self::Error>
|
||||||
@@ -81,7 +79,6 @@ pub trait CallExecutor<B: BlockT> {
|
|||||||
NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe,
|
NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe,
|
||||||
>(
|
>(
|
||||||
&self,
|
&self,
|
||||||
initialize_block_fn: IB,
|
|
||||||
at: &BlockId<B>,
|
at: &BlockId<B>,
|
||||||
method: &str,
|
method: &str,
|
||||||
call_data: &[u8],
|
call_data: &[u8],
|
||||||
@@ -89,7 +86,6 @@ pub trait CallExecutor<B: BlockT> {
|
|||||||
storage_transaction_cache: Option<&RefCell<
|
storage_transaction_cache: Option<&RefCell<
|
||||||
StorageTransactionCache<B, <Self::Backend as crate::backend::Backend<B>>::State>,
|
StorageTransactionCache<B, <Self::Backend as crate::backend::Backend<B>>::State>,
|
||||||
>>,
|
>>,
|
||||||
initialize_block: InitializeBlock<'a, B>,
|
|
||||||
execution_manager: ExecutionManager<EM>,
|
execution_manager: ExecutionManager<EM>,
|
||||||
native_call: Option<NC>,
|
native_call: Option<NC>,
|
||||||
proof_recorder: &Option<ProofRecorder<B>>,
|
proof_recorder: &Option<ProofRecorder<B>>,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ use sp_core::{
|
|||||||
convert_hash, NativeOrEncoded, traits::{CodeExecutor, SpawnNamed},
|
convert_hash, NativeOrEncoded, traits::{CodeExecutor, SpawnNamed},
|
||||||
};
|
};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
generic::BlockId, traits::{One, Block as BlockT, Header as HeaderT, HashFor},
|
generic::BlockId, traits::{Block as BlockT, Header as HeaderT, HashFor},
|
||||||
};
|
};
|
||||||
use sp_externalities::Extensions;
|
use sp_externalities::Extensions;
|
||||||
use sp_state_machine::{
|
use sp_state_machine::{
|
||||||
@@ -36,7 +36,7 @@ use sp_state_machine::{
|
|||||||
};
|
};
|
||||||
use hash_db::Hasher;
|
use hash_db::Hasher;
|
||||||
|
|
||||||
use sp_api::{ProofRecorder, InitializeBlock, StorageTransactionCache};
|
use sp_api::{ProofRecorder, StorageTransactionCache};
|
||||||
|
|
||||||
use sp_blockchain::{Error as ClientError, Result as ClientResult};
|
use sp_blockchain::{Error as ClientError, Result as ClientResult};
|
||||||
|
|
||||||
@@ -97,8 +97,6 @@ impl<Block, B, Local> CallExecutor<Block> for
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn contextual_call<
|
fn contextual_call<
|
||||||
'a,
|
|
||||||
IB: Fn() -> ClientResult<()>,
|
|
||||||
EM: Fn(
|
EM: Fn(
|
||||||
Result<NativeOrEncoded<R>, Self::Error>,
|
Result<NativeOrEncoded<R>, Self::Error>,
|
||||||
Result<NativeOrEncoded<R>, Self::Error>
|
Result<NativeOrEncoded<R>, Self::Error>
|
||||||
@@ -107,13 +105,11 @@ impl<Block, B, Local> CallExecutor<Block> for
|
|||||||
NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe,
|
NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe,
|
||||||
>(
|
>(
|
||||||
&self,
|
&self,
|
||||||
initialize_block_fn: IB,
|
|
||||||
at: &BlockId<Block>,
|
at: &BlockId<Block>,
|
||||||
method: &str,
|
method: &str,
|
||||||
call_data: &[u8],
|
call_data: &[u8],
|
||||||
changes: &RefCell<OverlayedChanges>,
|
changes: &RefCell<OverlayedChanges>,
|
||||||
_: Option<&RefCell<StorageTransactionCache<Block, B::State>>>,
|
_: Option<&RefCell<StorageTransactionCache<Block, B::State>>>,
|
||||||
initialize_block: InitializeBlock<'a, Block>,
|
|
||||||
_manager: ExecutionManager<EM>,
|
_manager: ExecutionManager<EM>,
|
||||||
native_call: Option<NC>,
|
native_call: Option<NC>,
|
||||||
recorder: &Option<ProofRecorder<Block>>,
|
recorder: &Option<ProofRecorder<Block>>,
|
||||||
@@ -124,7 +120,6 @@ impl<Block, B, Local> CallExecutor<Block> for
|
|||||||
|
|
||||||
match self.backend.is_local_state_available(at) {
|
match self.backend.is_local_state_available(at) {
|
||||||
true => CallExecutor::contextual_call::<
|
true => CallExecutor::contextual_call::<
|
||||||
_,
|
|
||||||
fn(
|
fn(
|
||||||
Result<NativeOrEncoded<R>, Local::Error>,
|
Result<NativeOrEncoded<R>, Local::Error>,
|
||||||
Result<NativeOrEncoded<R>, Local::Error>,
|
Result<NativeOrEncoded<R>, Local::Error>,
|
||||||
@@ -133,13 +128,11 @@ impl<Block, B, Local> CallExecutor<Block> for
|
|||||||
NC
|
NC
|
||||||
>(
|
>(
|
||||||
&self.local,
|
&self.local,
|
||||||
initialize_block_fn,
|
|
||||||
at,
|
at,
|
||||||
method,
|
method,
|
||||||
call_data,
|
call_data,
|
||||||
changes,
|
changes,
|
||||||
None,
|
None,
|
||||||
initialize_block,
|
|
||||||
ExecutionManager::NativeWhenPossible,
|
ExecutionManager::NativeWhenPossible,
|
||||||
native_call,
|
native_call,
|
||||||
recorder,
|
recorder,
|
||||||
@@ -177,7 +170,6 @@ impl<Block, B, Local> CallExecutor<Block> for
|
|||||||
/// Proof includes both environment preparation proof and method execution proof.
|
/// Proof includes both environment preparation proof and method execution proof.
|
||||||
pub fn prove_execution<Block, S, E>(
|
pub fn prove_execution<Block, S, E>(
|
||||||
mut state: S,
|
mut state: S,
|
||||||
header: Block::Header,
|
|
||||||
executor: &E,
|
executor: &E,
|
||||||
method: &str,
|
method: &str,
|
||||||
call_data: &[u8],
|
call_data: &[u8],
|
||||||
@@ -193,31 +185,20 @@ pub fn prove_execution<Block, S, E>(
|
|||||||
Box<dyn sp_state_machine::Error>
|
Box<dyn sp_state_machine::Error>
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// prepare execution environment + record preparation proof
|
|
||||||
let mut changes = Default::default();
|
|
||||||
let (_, init_proof) = executor.prove_at_trie_state(
|
|
||||||
trie_state,
|
|
||||||
&mut changes,
|
|
||||||
"Core_initialize_block",
|
|
||||||
&header.encode(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// execute method + record execution proof
|
// execute method + record execution proof
|
||||||
let (result, exec_proof) = executor.prove_at_trie_state(
|
let (result, exec_proof) = executor.prove_at_trie_state(
|
||||||
&trie_state,
|
&trie_state,
|
||||||
&mut changes,
|
&mut Default::default(),
|
||||||
method,
|
method,
|
||||||
call_data,
|
call_data,
|
||||||
)?;
|
)?;
|
||||||
let total_proof = StorageProof::merge(vec![init_proof, exec_proof]);
|
|
||||||
|
|
||||||
Ok((result, total_proof))
|
Ok((result, exec_proof))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check remote contextual execution proof using given backend.
|
/// Check remote contextual execution proof using given backend.
|
||||||
///
|
///
|
||||||
/// Method is executed using passed header as environment' current block.
|
/// Proof should include the method execution proof.
|
||||||
/// Proof should include both environment preparation proof and method execution proof.
|
|
||||||
pub fn check_execution_proof<Header, E, H>(
|
pub fn check_execution_proof<Header, E, H>(
|
||||||
executor: &E,
|
executor: &E,
|
||||||
spawn_handle: Box<dyn SpawnNamed>,
|
spawn_handle: Box<dyn SpawnNamed>,
|
||||||
@@ -229,63 +210,19 @@ pub fn check_execution_proof<Header, E, H>(
|
|||||||
E: CodeExecutor + Clone + 'static,
|
E: CodeExecutor + Clone + 'static,
|
||||||
H: Hasher,
|
H: Hasher,
|
||||||
H::Out: Ord + codec::Codec + 'static,
|
H::Out: Ord + codec::Codec + 'static,
|
||||||
{
|
|
||||||
check_execution_proof_with_make_header::<Header, E, H, _>(
|
|
||||||
executor,
|
|
||||||
spawn_handle,
|
|
||||||
request,
|
|
||||||
remote_proof,
|
|
||||||
|header| <Header as HeaderT>::new(
|
|
||||||
*header.number() + One::one(),
|
|
||||||
Default::default(),
|
|
||||||
Default::default(),
|
|
||||||
header.hash(),
|
|
||||||
Default::default(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check remote contextual execution proof using given backend and header factory.
|
|
||||||
///
|
|
||||||
/// Method is executed using passed header as environment' current block.
|
|
||||||
/// Proof should include both environment preparation proof and method execution proof.
|
|
||||||
pub fn check_execution_proof_with_make_header<Header, E, H, MakeNextHeader>(
|
|
||||||
executor: &E,
|
|
||||||
spawn_handle: Box<dyn SpawnNamed>,
|
|
||||||
request: &RemoteCallRequest<Header>,
|
|
||||||
remote_proof: StorageProof,
|
|
||||||
make_next_header: MakeNextHeader,
|
|
||||||
) -> ClientResult<Vec<u8>>
|
|
||||||
where
|
|
||||||
E: CodeExecutor + Clone + 'static,
|
|
||||||
H: Hasher,
|
|
||||||
Header: HeaderT,
|
|
||||||
H::Out: Ord + codec::Codec + 'static,
|
|
||||||
MakeNextHeader: Fn(&Header) -> Header,
|
|
||||||
{
|
{
|
||||||
let local_state_root = request.header.state_root();
|
let local_state_root = request.header.state_root();
|
||||||
let root: H::Out = convert_hash(&local_state_root);
|
let root: H::Out = convert_hash(&local_state_root);
|
||||||
|
|
||||||
// prepare execution environment + check preparation proof
|
// prepare execution environment
|
||||||
let mut changes = OverlayedChanges::default();
|
let mut changes = OverlayedChanges::default();
|
||||||
let trie_backend = create_proof_check_backend(root, remote_proof)?;
|
let trie_backend = create_proof_check_backend(root, remote_proof)?;
|
||||||
let next_header = make_next_header(&request.header);
|
|
||||||
|
|
||||||
// TODO: Remove when solved: https://github.com/paritytech/substrate/issues/5047
|
// TODO: Remove when solved: https://github.com/paritytech/substrate/issues/5047
|
||||||
let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&trie_backend);
|
let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&trie_backend);
|
||||||
let runtime_code = backend_runtime_code.runtime_code()
|
let runtime_code = backend_runtime_code.runtime_code()
|
||||||
.map_err(|_e| ClientError::RuntimeCodeMissing)?;
|
.map_err(|_e| ClientError::RuntimeCodeMissing)?;
|
||||||
|
|
||||||
execution_proof_check_on_trie_backend::<H, Header::Number, _, _>(
|
|
||||||
&trie_backend,
|
|
||||||
&mut changes,
|
|
||||||
executor,
|
|
||||||
spawn_handle.clone(),
|
|
||||||
"Core_initialize_block",
|
|
||||||
&next_header.encode(),
|
|
||||||
&runtime_code,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// execute method
|
// execute method
|
||||||
execution_proof_check_on_trie_backend::<H, Header::Number, _, _>(
|
execution_proof_check_on_trie_backend::<H, Header::Number, _, _>(
|
||||||
&trie_backend,
|
&trie_backend,
|
||||||
|
|||||||
@@ -474,7 +474,7 @@ fn should_return_runtime_version() {
|
|||||||
|
|
||||||
let result = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\
|
let result = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\
|
||||||
\"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",3],\
|
\"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",3],\
|
||||||
[\"0x37e397fc7c91f5e4\",1],[\"0xd2bc9897eed08f15\",2],[\"0x40fe3ad401f8959a\",5],\
|
[\"0x37e397fc7c91f5e4\",1],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",5],\
|
||||||
[\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",2],\
|
[\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",2],\
|
||||||
[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]],\
|
[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]],\
|
||||||
\"transactionVersion\":1}";
|
\"transactionVersion\":1}";
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ use sp_externalities::Extensions;
|
|||||||
use sp_core::{
|
use sp_core::{
|
||||||
NativeOrEncoded, NeverNativeValue, traits::{CodeExecutor, SpawnNamed, RuntimeCode},
|
NativeOrEncoded, NeverNativeValue, traits::{CodeExecutor, SpawnNamed, RuntimeCode},
|
||||||
};
|
};
|
||||||
use sp_api::{ProofRecorder, InitializeBlock, StorageTransactionCache};
|
use sp_api::{ProofRecorder, StorageTransactionCache};
|
||||||
use sc_client_api::{backend, call_executor::CallExecutor};
|
use sc_client_api::{backend, call_executor::CallExecutor};
|
||||||
use super::{client::ClientConfig, wasm_override::WasmOverride, wasm_substitutes::WasmSubstitutes};
|
use super::{client::ClientConfig, wasm_override::WasmOverride, wasm_substitutes::WasmSubstitutes};
|
||||||
|
|
||||||
@@ -173,8 +173,6 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn contextual_call<
|
fn contextual_call<
|
||||||
'a,
|
|
||||||
IB: Fn() -> sp_blockchain::Result<()>,
|
|
||||||
EM: Fn(
|
EM: Fn(
|
||||||
Result<NativeOrEncoded<R>, Self::Error>,
|
Result<NativeOrEncoded<R>, Self::Error>,
|
||||||
Result<NativeOrEncoded<R>, Self::Error>
|
Result<NativeOrEncoded<R>, Self::Error>
|
||||||
@@ -183,7 +181,6 @@ where
|
|||||||
NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe,
|
NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe,
|
||||||
>(
|
>(
|
||||||
&self,
|
&self,
|
||||||
initialize_block_fn: IB,
|
|
||||||
at: &BlockId<Block>,
|
at: &BlockId<Block>,
|
||||||
method: &str,
|
method: &str,
|
||||||
call_data: &[u8],
|
call_data: &[u8],
|
||||||
@@ -191,21 +188,11 @@ where
|
|||||||
storage_transaction_cache: Option<&RefCell<
|
storage_transaction_cache: Option<&RefCell<
|
||||||
StorageTransactionCache<Block, B::State>
|
StorageTransactionCache<Block, B::State>
|
||||||
>>,
|
>>,
|
||||||
initialize_block: InitializeBlock<'a, Block>,
|
|
||||||
execution_manager: ExecutionManager<EM>,
|
execution_manager: ExecutionManager<EM>,
|
||||||
native_call: Option<NC>,
|
native_call: Option<NC>,
|
||||||
recorder: &Option<ProofRecorder<Block>>,
|
recorder: &Option<ProofRecorder<Block>>,
|
||||||
extensions: Option<Extensions>,
|
extensions: Option<Extensions>,
|
||||||
) -> Result<NativeOrEncoded<R>, sp_blockchain::Error> where ExecutionManager<EM>: Clone {
|
) -> Result<NativeOrEncoded<R>, sp_blockchain::Error> where ExecutionManager<EM>: Clone {
|
||||||
match initialize_block {
|
|
||||||
InitializeBlock::Do(ref init_block)
|
|
||||||
if init_block.borrow().as_ref().map(|id| id != at).unwrap_or(true) => {
|
|
||||||
initialize_block_fn()?;
|
|
||||||
},
|
|
||||||
// We don't need to initialize the runtime at a block.
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
|
|
||||||
let changes_trie_state = backend::changes_tries_state_at_block(at, self.backend.changes_trie_storage())?;
|
let changes_trie_state = backend::changes_tries_state_at_block(at, self.backend.changes_trie_storage())?;
|
||||||
let mut storage_transaction_cache = storage_transaction_cache.map(|c| c.borrow_mut());
|
let mut storage_transaction_cache = storage_transaction_cache.map(|c| c.borrow_mut());
|
||||||
|
|
||||||
|
|||||||
@@ -1243,18 +1243,6 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
|||||||
trace!("Collected {} uncles", uncles.len());
|
trace!("Collected {} uncles", uncles.len());
|
||||||
Ok(uncles)
|
Ok(uncles)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare in-memory header that is used in execution environment.
|
|
||||||
fn prepare_environment_block(&self, parent: &BlockId<Block>) -> sp_blockchain::Result<Block::Header> {
|
|
||||||
let parent_hash = self.backend.blockchain().expect_block_hash_from_id(parent)?;
|
|
||||||
Ok(<<Block as BlockT>::Header as HeaderT>::new(
|
|
||||||
self.backend.blockchain().expect_block_number_from_id(parent)? + One::one(),
|
|
||||||
Default::default(),
|
|
||||||
Default::default(),
|
|
||||||
parent_hash,
|
|
||||||
Default::default(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, E, Block, RA> UsageProvider<Block> for Client<B, E, Block, RA> where
|
impl<B, E, Block, RA> UsageProvider<Block> for Client<B, E, Block, RA> where
|
||||||
@@ -1313,10 +1301,8 @@ impl<B, E, Block, RA> ProofProvider<Block> for Client<B, E, Block, RA> where
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
let state = self.state_at(id)?;
|
let state = self.state_at(id)?;
|
||||||
let header = self.prepare_environment_block(id)?;
|
|
||||||
prove_execution(
|
prove_execution(
|
||||||
state,
|
state,
|
||||||
header,
|
|
||||||
&self.executor,
|
&self.executor,
|
||||||
method,
|
method,
|
||||||
call_data,
|
call_data,
|
||||||
@@ -1782,12 +1768,10 @@ impl<B, E, Block, RA> CallApiAt<Block> for Client<B, E, Block, RA> where
|
|||||||
'a,
|
'a,
|
||||||
R: Encode + Decode + PartialEq,
|
R: Encode + Decode + PartialEq,
|
||||||
NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe,
|
NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe,
|
||||||
C: CoreApi<Block>,
|
|
||||||
>(
|
>(
|
||||||
&self,
|
&self,
|
||||||
params: CallApiAtParams<'a, Block, C, NC, B::State>,
|
params: CallApiAtParams<'a, Block, NC, B::State>,
|
||||||
) -> Result<NativeOrEncoded<R>, sp_api::ApiError> {
|
) -> Result<NativeOrEncoded<R>, sp_api::ApiError> {
|
||||||
let core_api = params.core_api;
|
|
||||||
let at = params.at;
|
let at = params.at;
|
||||||
|
|
||||||
let (manager, extensions) = self.execution_extensions.manager_and_extensions(
|
let (manager, extensions) = self.execution_extensions.manager_and_extensions(
|
||||||
@@ -1795,16 +1779,12 @@ impl<B, E, Block, RA> CallApiAt<Block> for Client<B, E, Block, RA> where
|
|||||||
params.context,
|
params.context,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.executor.contextual_call::<_, fn(_,_) -> _,_,_>(
|
self.executor.contextual_call::<fn(_,_) -> _, _, _>(
|
||||||
|| core_api
|
|
||||||
.initialize_block(at, &self.prepare_environment_block(at)?)
|
|
||||||
.map_err(Error::RuntimeApiError),
|
|
||||||
at,
|
at,
|
||||||
params.function,
|
params.function,
|
||||||
¶ms.arguments,
|
¶ms.arguments,
|
||||||
params.overlayed_changes,
|
params.overlayed_changes,
|
||||||
Some(params.storage_transaction_cache),
|
Some(params.storage_transaction_cache),
|
||||||
params.initialize_block,
|
|
||||||
manager,
|
manager,
|
||||||
params.native_call,
|
params.native_call,
|
||||||
params.recorder,
|
params.recorder,
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ use sc_light::{
|
|||||||
call_executor::{
|
call_executor::{
|
||||||
GenesisCallExecutor,
|
GenesisCallExecutor,
|
||||||
check_execution_proof,
|
check_execution_proof,
|
||||||
check_execution_proof_with_make_header,
|
|
||||||
},
|
},
|
||||||
fetcher::LightDataChecker,
|
fetcher::LightDataChecker,
|
||||||
blockchain::{BlockchainCache, Blockchain},
|
blockchain::{BlockchainCache, Blockchain},
|
||||||
@@ -37,7 +36,7 @@ use parking_lot::Mutex;
|
|||||||
use substrate_test_runtime_client::{
|
use substrate_test_runtime_client::{
|
||||||
runtime::{Hash, Block, Header}, TestClient, ClientBlockImportExt,
|
runtime::{Hash, Block, Header}, TestClient, ClientBlockImportExt,
|
||||||
};
|
};
|
||||||
use sp_api::{InitializeBlock, StorageTransactionCache, ProofRecorder};
|
use sp_api::{StorageTransactionCache, ProofRecorder};
|
||||||
use sp_consensus::BlockOrigin;
|
use sp_consensus::BlockOrigin;
|
||||||
use sc_executor::{NativeExecutor, WasmExecutionMethod, RuntimeVersion, NativeVersion};
|
use sc_executor::{NativeExecutor, WasmExecutionMethod, RuntimeVersion, NativeVersion};
|
||||||
use sp_core::{H256, NativeOrEncoded, testing::TaskExecutor};
|
use sp_core::{H256, NativeOrEncoded, testing::TaskExecutor};
|
||||||
@@ -209,8 +208,6 @@ impl CallExecutor<Block> for DummyCallExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn contextual_call<
|
fn contextual_call<
|
||||||
'a,
|
|
||||||
IB: Fn() -> ClientResult<()>,
|
|
||||||
EM: Fn(
|
EM: Fn(
|
||||||
Result<NativeOrEncoded<R>, Self::Error>,
|
Result<NativeOrEncoded<R>, Self::Error>,
|
||||||
Result<NativeOrEncoded<R>, Self::Error>
|
Result<NativeOrEncoded<R>, Self::Error>
|
||||||
@@ -219,7 +216,6 @@ impl CallExecutor<Block> for DummyCallExecutor {
|
|||||||
NC: FnOnce() -> Result<R, sp_api::ApiError> + UnwindSafe,
|
NC: FnOnce() -> Result<R, sp_api::ApiError> + UnwindSafe,
|
||||||
>(
|
>(
|
||||||
&self,
|
&self,
|
||||||
_initialize_block_fn: IB,
|
|
||||||
_at: &BlockId<Block>,
|
_at: &BlockId<Block>,
|
||||||
_method: &str,
|
_method: &str,
|
||||||
_call_data: &[u8],
|
_call_data: &[u8],
|
||||||
@@ -230,7 +226,6 @@ impl CallExecutor<Block> for DummyCallExecutor {
|
|||||||
<Self::Backend as sc_client_api::backend::Backend<Block>>::State,
|
<Self::Backend as sc_client_api::backend::Backend<Block>>::State,
|
||||||
>
|
>
|
||||||
>>,
|
>>,
|
||||||
_initialize_block: InitializeBlock<'a, Block>,
|
|
||||||
_execution_manager: ExecutionManager<EM>,
|
_execution_manager: ExecutionManager<EM>,
|
||||||
_native_call: Option<NC>,
|
_native_call: Option<NC>,
|
||||||
_proof_recorder: &Option<ProofRecorder<Block>>,
|
_proof_recorder: &Option<ProofRecorder<Block>>,
|
||||||
@@ -333,36 +328,41 @@ fn execution_proof_is_generated_and_checked() {
|
|||||||
(remote_result, local_result)
|
(remote_result, local_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_with_proof_failure(remote_client: &TestClient, at: u64, method: &'static str) {
|
fn execute_with_proof_failure(remote_client: &TestClient, at: u64) {
|
||||||
let remote_block_id = BlockId::Number(at);
|
let remote_block_id = BlockId::Number(at);
|
||||||
let remote_header = remote_client.header(&remote_block_id).unwrap().unwrap();
|
let remote_header = remote_client.header(&remote_block_id).unwrap().unwrap();
|
||||||
|
|
||||||
// 'fetch' execution proof from remote node
|
// 'fetch' execution proof from remote node
|
||||||
let (_, remote_execution_proof) = remote_client.execution_proof(
|
let (_, remote_execution_proof) = remote_client.execution_proof(
|
||||||
&remote_block_id,
|
&remote_block_id,
|
||||||
method,
|
"Core_initialize_block",
|
||||||
&[]
|
&Header::new(
|
||||||
|
at,
|
||||||
|
Default::default(),
|
||||||
|
Default::default(),
|
||||||
|
Default::default(),
|
||||||
|
Default::default(),
|
||||||
|
).encode(),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
// check remote execution proof locally
|
// check remote execution proof locally
|
||||||
let execution_result = check_execution_proof_with_make_header::<_, _, BlakeTwo256, _>(
|
let execution_result = check_execution_proof::<_, _, BlakeTwo256>(
|
||||||
&local_executor(),
|
&local_executor(),
|
||||||
Box::new(TaskExecutor::new()),
|
Box::new(TaskExecutor::new()),
|
||||||
&RemoteCallRequest {
|
&RemoteCallRequest {
|
||||||
block: substrate_test_runtime_client::runtime::Hash::default(),
|
block: substrate_test_runtime_client::runtime::Hash::default(),
|
||||||
header: remote_header,
|
header: remote_header.clone(),
|
||||||
method: method.into(),
|
method: "Core_initialize_block".into(),
|
||||||
call_data: vec![],
|
call_data: Header::new(
|
||||||
|
at + 1,
|
||||||
|
Default::default(),
|
||||||
|
Default::default(),
|
||||||
|
remote_header.hash(),
|
||||||
|
remote_header.digest().clone(), // this makes next header wrong
|
||||||
|
).encode(),
|
||||||
retry_count: None,
|
retry_count: None,
|
||||||
},
|
},
|
||||||
remote_execution_proof,
|
remote_execution_proof,
|
||||||
|header| <Header as HeaderT>::new(
|
|
||||||
at + 1,
|
|
||||||
Default::default(),
|
|
||||||
Default::default(),
|
|
||||||
header.hash(),
|
|
||||||
header.digest().clone(), // this makes next header wrong
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
match execution_result {
|
match execution_result {
|
||||||
Err(sp_blockchain::Error::Execution(_)) => (),
|
Err(sp_blockchain::Error::Execution(_)) => (),
|
||||||
@@ -389,21 +389,12 @@ fn execution_proof_is_generated_and_checked() {
|
|||||||
let (remote, local) = execute(&remote_client, 2, "Core_version");
|
let (remote, local) = execute(&remote_client, 2, "Core_version");
|
||||||
assert_eq!(remote, local);
|
assert_eq!(remote, local);
|
||||||
|
|
||||||
// check method that requires environment
|
|
||||||
let (_, block) = execute(&remote_client, 0, "BlockBuilder_finalize_block");
|
|
||||||
let local_block: Header = Decode::decode(&mut &block[..]).unwrap();
|
|
||||||
assert_eq!(local_block.number, 1);
|
|
||||||
|
|
||||||
let (_, block) = execute(&remote_client, 2, "BlockBuilder_finalize_block");
|
|
||||||
let local_block: Header = Decode::decode(&mut &block[..]).unwrap();
|
|
||||||
assert_eq!(local_block.number, 3);
|
|
||||||
|
|
||||||
// check that proof check doesn't panic even if proof is incorrect AND no panic handler is set
|
// check that proof check doesn't panic even if proof is incorrect AND no panic handler is set
|
||||||
execute_with_proof_failure(&remote_client, 2, "Core_version");
|
execute_with_proof_failure(&remote_client, 2);
|
||||||
|
|
||||||
// check that proof check doesn't panic even if proof is incorrect AND panic handler is set
|
// check that proof check doesn't panic even if proof is incorrect AND panic handler is set
|
||||||
sp_panic_handler::set("TEST", "1.2.3");
|
sp_panic_handler::set("TEST", "1.2.3");
|
||||||
execute_with_proof_failure(&remote_client, 2, "Core_version");
|
execute_with_proof_failure(&remote_client, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -203,24 +203,54 @@ where
|
|||||||
sp_tracing::within_span!(sp_tracing::Level::TRACE, "validate_transaction";
|
sp_tracing::within_span!(sp_tracing::Level::TRACE, "validate_transaction";
|
||||||
{
|
{
|
||||||
let runtime_api = client.runtime_api();
|
let runtime_api = client.runtime_api();
|
||||||
let has_v2 = sp_tracing::within_span! { sp_tracing::Level::TRACE, "check_version";
|
let api_version = sp_tracing::within_span! { sp_tracing::Level::TRACE, "check_version";
|
||||||
runtime_api
|
runtime_api
|
||||||
.has_api_with::<dyn TaggedTransactionQueue<Block>, _>(&at, |v| v >= 2)
|
.api_version::<dyn TaggedTransactionQueue<Block>>(&at)
|
||||||
.unwrap_or_default()
|
.map_err(|e| Error::RuntimeApi(e.to_string()))?
|
||||||
};
|
.ok_or_else(|| Error::RuntimeApi(
|
||||||
|
format!("Could not find `TaggedTransactionQueue` api for block `{:?}`.", at)
|
||||||
|
))
|
||||||
|
}?;
|
||||||
|
|
||||||
let res = sp_tracing::within_span!(
|
let block_hash = client.to_hash(at)
|
||||||
|
.map_err(|e| Error::RuntimeApi(format!("{:?}", e)))?
|
||||||
|
.ok_or_else(|| Error::RuntimeApi(format!("Could not get hash for block `{:?}`.", at)))?;
|
||||||
|
|
||||||
|
use sp_api::Core;
|
||||||
|
|
||||||
|
sp_tracing::within_span!(
|
||||||
sp_tracing::Level::TRACE, "runtime::validate_transaction";
|
sp_tracing::Level::TRACE, "runtime::validate_transaction";
|
||||||
{
|
{
|
||||||
if has_v2 {
|
if api_version >= 3 {
|
||||||
runtime_api.validate_transaction(&at, source, uxt)
|
runtime_api.validate_transaction(&at, source, uxt, block_hash)
|
||||||
|
.map_err(|e| Error::RuntimeApi(e.to_string()))
|
||||||
} else {
|
} else {
|
||||||
#[allow(deprecated)] // old validate_transaction
|
let block_number = client.to_number(at)
|
||||||
runtime_api.validate_transaction_before_version_2(&at, uxt)
|
.map_err(|e| Error::RuntimeApi(format!("{:?}", e)))?
|
||||||
}
|
.ok_or_else(||
|
||||||
});
|
Error::RuntimeApi(format!("Could not get number for block `{:?}`.", at))
|
||||||
|
)?;
|
||||||
|
|
||||||
res.map_err(|e| Error::RuntimeApi(e.to_string()))
|
// The old versions require us to call `initialize_block` before.
|
||||||
|
runtime_api.initialize_block(at, &sp_runtime::traits::Header::new(
|
||||||
|
block_number + sp_runtime::traits::One::one(),
|
||||||
|
Default::default(),
|
||||||
|
Default::default(),
|
||||||
|
block_hash,
|
||||||
|
Default::default()),
|
||||||
|
).map_err(|e| Error::RuntimeApi(e.to_string()))?;
|
||||||
|
|
||||||
|
if api_version == 2 {
|
||||||
|
#[allow(deprecated)] // old validate_transaction
|
||||||
|
runtime_api.validate_transaction_before_version_3(&at, source, uxt)
|
||||||
|
.map_err(|e| Error::RuntimeApi(e.to_string()))
|
||||||
|
} else {
|
||||||
|
#[allow(deprecated)] // old validate_transaction
|
||||||
|
runtime_api.validate_transaction_before_version_2(&at, uxt)
|
||||||
|
.map_err(|e| Error::RuntimeApi(e.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -474,10 +474,18 @@ where
|
|||||||
pub fn validate_transaction(
|
pub fn validate_transaction(
|
||||||
source: TransactionSource,
|
source: TransactionSource,
|
||||||
uxt: Block::Extrinsic,
|
uxt: Block::Extrinsic,
|
||||||
|
block_hash: Block::Hash,
|
||||||
) -> TransactionValidity {
|
) -> TransactionValidity {
|
||||||
sp_io::init_tracing();
|
sp_io::init_tracing();
|
||||||
use sp_tracing::{enter_span, within_span};
|
use sp_tracing::{enter_span, within_span};
|
||||||
|
|
||||||
|
<frame_system::Pallet<System>>::initialize(
|
||||||
|
&(frame_system::Pallet::<System>::block_number() + One::one()),
|
||||||
|
&block_hash,
|
||||||
|
&Default::default(),
|
||||||
|
frame_system::InitKind::Inspection,
|
||||||
|
);
|
||||||
|
|
||||||
enter_span!{ sp_tracing::Level::TRACE, "validate_transaction" };
|
enter_span!{ sp_tracing::Level::TRACE, "validate_transaction" };
|
||||||
|
|
||||||
let encoded_len = within_span!{ sp_tracing::Level::TRACE, "using_encoded";
|
let encoded_len = within_span!{ sp_tracing::Level::TRACE, "using_encoded";
|
||||||
@@ -1006,11 +1014,19 @@ mod tests {
|
|||||||
default_with_prio_3.priority = 3;
|
default_with_prio_3.priority = 3;
|
||||||
t.execute_with(|| {
|
t.execute_with(|| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Executive::validate_transaction(TransactionSource::InBlock, valid.clone()),
|
Executive::validate_transaction(
|
||||||
|
TransactionSource::InBlock,
|
||||||
|
valid.clone(),
|
||||||
|
Default::default(),
|
||||||
|
),
|
||||||
Ok(default_with_prio_3),
|
Ok(default_with_prio_3),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Executive::validate_transaction(TransactionSource::InBlock, invalid.clone()),
|
Executive::validate_transaction(
|
||||||
|
TransactionSource::InBlock,
|
||||||
|
invalid.clone(),
|
||||||
|
Default::default(),
|
||||||
|
),
|
||||||
Err(TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator)),
|
Err(TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator)),
|
||||||
);
|
);
|
||||||
assert_eq!(Executive::apply_extrinsic(valid), Ok(Err(DispatchError::BadOrigin)));
|
assert_eq!(Executive::apply_extrinsic(valid), Ok(Err(DispatchError::BadOrigin)));
|
||||||
|
|||||||
@@ -406,7 +406,6 @@ sp_api::decl_runtime_apis! {
|
|||||||
/// API to interact with MMR pallet.
|
/// API to interact with MMR pallet.
|
||||||
pub trait MmrApi<Hash: codec::Codec> {
|
pub trait MmrApi<Hash: codec::Codec> {
|
||||||
/// Generate MMR proof for a leaf under given index.
|
/// Generate MMR proof for a leaf under given index.
|
||||||
#[skip_initialize_block]
|
|
||||||
fn generate_proof(leaf_index: u64) -> Result<(EncodableOpaqueLeaf, Proof<Hash>), Error>;
|
fn generate_proof(leaf_index: u64) -> Result<(EncodableOpaqueLeaf, Proof<Hash>), Error>;
|
||||||
|
|
||||||
/// Verify MMR proof against on-chain MMR.
|
/// Verify MMR proof against on-chain MMR.
|
||||||
@@ -414,7 +413,6 @@ sp_api::decl_runtime_apis! {
|
|||||||
/// Note this function will use on-chain MMR root hash and check if the proof
|
/// Note this function will use on-chain MMR root hash and check if the proof
|
||||||
/// matches the hash.
|
/// matches the hash.
|
||||||
/// See [Self::verify_proof_stateless] for a stateless verifier.
|
/// See [Self::verify_proof_stateless] for a stateless verifier.
|
||||||
#[skip_initialize_block]
|
|
||||||
fn verify_proof(leaf: EncodableOpaqueLeaf, proof: Proof<Hash>) -> Result<(), Error>;
|
fn verify_proof(leaf: EncodableOpaqueLeaf, proof: Proof<Hash>) -> Result<(), Error>;
|
||||||
|
|
||||||
/// Verify MMR proof against given root hash.
|
/// Verify MMR proof against given root hash.
|
||||||
@@ -423,7 +421,6 @@ sp_api::decl_runtime_apis! {
|
|||||||
/// proof is verified against given MMR root hash.
|
/// proof is verified against given MMR root hash.
|
||||||
///
|
///
|
||||||
/// The leaf data is expected to be encoded in it's compact form.
|
/// The leaf data is expected to be encoded in it's compact form.
|
||||||
#[skip_initialize_block]
|
|
||||||
fn verify_proof_stateless(root: Hash, leaf: EncodableOpaqueLeaf, proof: Proof<Hash>)
|
fn verify_proof_stateless(root: Hash, leaf: EncodableOpaqueLeaf, proof: Proof<Hash>)
|
||||||
-> Result<(), Error>;
|
-> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,21 +58,9 @@ const CHANGED_IN_ATTRIBUTE: &str = "changed_in";
|
|||||||
///
|
///
|
||||||
/// Is used when a trait method was renamed.
|
/// Is used when a trait method was renamed.
|
||||||
const RENAMED_ATTRIBUTE: &str = "renamed";
|
const RENAMED_ATTRIBUTE: &str = "renamed";
|
||||||
/// The `skip_initialize_block` attribute.
|
|
||||||
///
|
|
||||||
/// Is used when a trait method does not require that the block is initialized
|
|
||||||
/// before being called.
|
|
||||||
const SKIP_INITIALIZE_BLOCK_ATTRIBUTE: &str = "skip_initialize_block";
|
|
||||||
/// The `initialize_block` attribute.
|
|
||||||
///
|
|
||||||
/// A trait method tagged with this attribute, initializes the runtime at
|
|
||||||
/// certain block.
|
|
||||||
const INITIALIZE_BLOCK_ATTRIBUTE: &str = "initialize_block";
|
|
||||||
/// All attributes that we support in the declaration of a runtime api trait.
|
/// All attributes that we support in the declaration of a runtime api trait.
|
||||||
const SUPPORTED_ATTRIBUTE_NAMES: &[&str] = &[
|
const SUPPORTED_ATTRIBUTE_NAMES: &[&str] = &[
|
||||||
CORE_TRAIT_ATTRIBUTE, API_VERSION_ATTRIBUTE, CHANGED_IN_ATTRIBUTE,
|
CORE_TRAIT_ATTRIBUTE, API_VERSION_ATTRIBUTE, CHANGED_IN_ATTRIBUTE, RENAMED_ATTRIBUTE,
|
||||||
RENAMED_ATTRIBUTE, SKIP_INITIALIZE_BLOCK_ATTRIBUTE,
|
|
||||||
INITIALIZE_BLOCK_ATTRIBUTE,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/// The structure used for parsing the runtime api declarations.
|
/// The structure used for parsing the runtime api declarations.
|
||||||
@@ -376,15 +364,6 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result<TokenStream> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let skip_initialize_block = attrs.contains_key(SKIP_INITIALIZE_BLOCK_ATTRIBUTE);
|
|
||||||
let update_initialized_block = if attrs.contains_key(INITIALIZE_BLOCK_ATTRIBUTE) {
|
|
||||||
quote!(
|
|
||||||
|| *initialized_block.borrow_mut() = Some(*at)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
quote!(|| ())
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse the renamed attributes.
|
// Parse the renamed attributes.
|
||||||
let mut renames = Vec::new();
|
let mut renames = Vec::new();
|
||||||
if let Some((_, a)) = attrs
|
if let Some((_, a)) = attrs
|
||||||
@@ -413,72 +392,54 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result<TokenStream> {
|
|||||||
NC: FnOnce() -> std::result::Result<R, #crate_::ApiError> + std::panic::UnwindSafe,
|
NC: FnOnce() -> std::result::Result<R, #crate_::ApiError> + std::panic::UnwindSafe,
|
||||||
Block: #crate_::BlockT,
|
Block: #crate_::BlockT,
|
||||||
T: #crate_::CallApiAt<Block>,
|
T: #crate_::CallApiAt<Block>,
|
||||||
C: #crate_::Core<Block>,
|
|
||||||
>(
|
>(
|
||||||
call_runtime_at: &T,
|
call_runtime_at: &T,
|
||||||
core_api: &C,
|
|
||||||
at: &#crate_::BlockId<Block>,
|
at: &#crate_::BlockId<Block>,
|
||||||
args: Vec<u8>,
|
args: Vec<u8>,
|
||||||
changes: &std::cell::RefCell<#crate_::OverlayedChanges>,
|
changes: &std::cell::RefCell<#crate_::OverlayedChanges>,
|
||||||
storage_transaction_cache: &std::cell::RefCell<
|
storage_transaction_cache: &std::cell::RefCell<
|
||||||
#crate_::StorageTransactionCache<Block, T::StateBackend>
|
#crate_::StorageTransactionCache<Block, T::StateBackend>
|
||||||
>,
|
>,
|
||||||
initialized_block: &std::cell::RefCell<Option<#crate_::BlockId<Block>>>,
|
|
||||||
native_call: Option<NC>,
|
native_call: Option<NC>,
|
||||||
context: #crate_::ExecutionContext,
|
context: #crate_::ExecutionContext,
|
||||||
recorder: &Option<#crate_::ProofRecorder<Block>>,
|
recorder: &Option<#crate_::ProofRecorder<Block>>,
|
||||||
) -> std::result::Result<#crate_::NativeOrEncoded<R>, #crate_::ApiError> {
|
) -> std::result::Result<#crate_::NativeOrEncoded<R>, #crate_::ApiError> {
|
||||||
let version = call_runtime_at.runtime_version_at(at)?;
|
let version = call_runtime_at.runtime_version_at(at)?;
|
||||||
use #crate_::InitializeBlock;
|
|
||||||
let initialize_block = if #skip_initialize_block {
|
|
||||||
InitializeBlock::Skip
|
|
||||||
} else {
|
|
||||||
InitializeBlock::Do(&initialized_block)
|
|
||||||
};
|
|
||||||
let update_initialized_block = #update_initialized_block;
|
|
||||||
|
|
||||||
#(
|
#(
|
||||||
// Check if we need to call the function by an old name.
|
// Check if we need to call the function by an old name.
|
||||||
if version.apis.iter().any(|(s, v)| {
|
if version.apis.iter().any(|(s, v)| {
|
||||||
s == &ID && *v < #versions
|
s == &ID && *v < #versions
|
||||||
}) {
|
}) {
|
||||||
let params = #crate_::CallApiAtParams::<_, _, fn() -> _, _> {
|
let params = #crate_::CallApiAtParams::<_, fn() -> _, _> {
|
||||||
core_api,
|
|
||||||
at,
|
at,
|
||||||
function: #old_names,
|
function: #old_names,
|
||||||
native_call: None,
|
native_call: None,
|
||||||
arguments: args,
|
arguments: args,
|
||||||
overlayed_changes: changes,
|
overlayed_changes: changes,
|
||||||
storage_transaction_cache,
|
storage_transaction_cache,
|
||||||
initialize_block,
|
|
||||||
context,
|
context,
|
||||||
recorder,
|
recorder,
|
||||||
};
|
};
|
||||||
|
|
||||||
let ret = call_runtime_at.call_api_at(params)?;
|
let ret = call_runtime_at.call_api_at(params)?;
|
||||||
|
|
||||||
update_initialized_block();
|
|
||||||
return Ok(ret)
|
return Ok(ret)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
|
||||||
let params = #crate_::CallApiAtParams {
|
let params = #crate_::CallApiAtParams {
|
||||||
core_api,
|
|
||||||
at,
|
at,
|
||||||
function: #trait_fn_name,
|
function: #trait_fn_name,
|
||||||
native_call,
|
native_call,
|
||||||
arguments: args,
|
arguments: args,
|
||||||
overlayed_changes: changes,
|
overlayed_changes: changes,
|
||||||
storage_transaction_cache,
|
storage_transaction_cache,
|
||||||
initialize_block,
|
|
||||||
context,
|
context,
|
||||||
recorder,
|
recorder,
|
||||||
};
|
};
|
||||||
|
|
||||||
let ret = call_runtime_at.call_api_at(params)?;
|
call_runtime_at.call_api_at(params)
|
||||||
|
|
||||||
update_initialized_block();
|
|
||||||
Ok(ret)
|
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,9 +122,9 @@ fn generate_impl_calls(
|
|||||||
|
|
||||||
impl_calls.push((
|
impl_calls.push((
|
||||||
impl_trait_ident.clone(),
|
impl_trait_ident.clone(),
|
||||||
method.sig.ident.clone(),
|
method.sig.ident.clone(),
|
||||||
impl_call,
|
impl_call,
|
||||||
filter_cfg_attrs(&impl_.attrs),
|
filter_cfg_attrs(&impl_.attrs),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,7 +186,7 @@ fn generate_wasm_interface(impls: &[ItemImpl]) -> Result<TokenStream> {
|
|||||||
|
|
||||||
#c::init_runtime_logger();
|
#c::init_runtime_logger();
|
||||||
|
|
||||||
let output = { #impl_ };
|
let output = (move || { #impl_ })();
|
||||||
#c::to_substrate_wasm_fn_return_value(&output)
|
#c::to_substrate_wasm_fn_return_value(&output)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -205,7 +205,6 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
|||||||
pub struct RuntimeApiImpl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block> + 'static> {
|
pub struct RuntimeApiImpl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block> + 'static> {
|
||||||
call: &'static C,
|
call: &'static C,
|
||||||
commit_on_success: std::cell::RefCell<bool>,
|
commit_on_success: std::cell::RefCell<bool>,
|
||||||
initialized_block: std::cell::RefCell<Option<#crate_::BlockId<Block>>>,
|
|
||||||
changes: std::cell::RefCell<#crate_::OverlayedChanges>,
|
changes: std::cell::RefCell<#crate_::OverlayedChanges>,
|
||||||
storage_transaction_cache: std::cell::RefCell<
|
storage_transaction_cache: std::cell::RefCell<
|
||||||
#crate_::StorageTransactionCache<Block, C::StateBackend>
|
#crate_::StorageTransactionCache<Block, C::StateBackend>
|
||||||
@@ -265,6 +264,15 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
|||||||
.map(|v| v.has_api_with(&A::ID, pred))
|
.map(|v| v.has_api_with(&A::ID, pred))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn api_version<A: #crate_::RuntimeApiInfo + ?Sized>(
|
||||||
|
&self,
|
||||||
|
at: &#crate_::BlockId<Block>,
|
||||||
|
) -> std::result::Result<Option<u32>, #crate_::ApiError> where Self: Sized {
|
||||||
|
self.call
|
||||||
|
.runtime_version_at(at)
|
||||||
|
.map(|v| v.api_version(&A::ID))
|
||||||
|
}
|
||||||
|
|
||||||
fn record_proof(&mut self) {
|
fn record_proof(&mut self) {
|
||||||
self.recorder = Some(Default::default());
|
self.recorder = Some(Default::default());
|
||||||
}
|
}
|
||||||
@@ -291,7 +299,6 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
|||||||
#crate_::StorageChanges<C::StateBackend, Block>,
|
#crate_::StorageChanges<C::StateBackend, Block>,
|
||||||
String
|
String
|
||||||
> where Self: Sized {
|
> where Self: Sized {
|
||||||
self.initialized_block.borrow_mut().take();
|
|
||||||
self.changes.replace(Default::default()).into_storage_changes(
|
self.changes.replace(Default::default()).into_storage_changes(
|
||||||
backend,
|
backend,
|
||||||
changes_trie_state,
|
changes_trie_state,
|
||||||
@@ -315,7 +322,6 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
|||||||
RuntimeApiImpl {
|
RuntimeApiImpl {
|
||||||
call: unsafe { std::mem::transmute(call) },
|
call: unsafe { std::mem::transmute(call) },
|
||||||
commit_on_success: true.into(),
|
commit_on_success: true.into(),
|
||||||
initialized_block: None.into(),
|
|
||||||
changes: Default::default(),
|
changes: Default::default(),
|
||||||
recorder: Default::default(),
|
recorder: Default::default(),
|
||||||
storage_transaction_cache: Default::default(),
|
storage_transaction_cache: Default::default(),
|
||||||
@@ -329,10 +335,8 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
|||||||
R: #crate_::Encode + #crate_::Decode + PartialEq,
|
R: #crate_::Encode + #crate_::Decode + PartialEq,
|
||||||
F: FnOnce(
|
F: FnOnce(
|
||||||
&C,
|
&C,
|
||||||
&Self,
|
|
||||||
&std::cell::RefCell<#crate_::OverlayedChanges>,
|
&std::cell::RefCell<#crate_::OverlayedChanges>,
|
||||||
&std::cell::RefCell<#crate_::StorageTransactionCache<Block, C::StateBackend>>,
|
&std::cell::RefCell<#crate_::StorageTransactionCache<Block, C::StateBackend>>,
|
||||||
&std::cell::RefCell<Option<#crate_::BlockId<Block>>>,
|
|
||||||
&Option<#crate_::ProofRecorder<Block>>,
|
&Option<#crate_::ProofRecorder<Block>>,
|
||||||
) -> std::result::Result<#crate_::NativeOrEncoded<R>, E>,
|
) -> std::result::Result<#crate_::NativeOrEncoded<R>, E>,
|
||||||
E,
|
E,
|
||||||
@@ -345,10 +349,8 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
|||||||
}
|
}
|
||||||
let res = call_api_at(
|
let res = call_api_at(
|
||||||
&self.call,
|
&self.call,
|
||||||
self,
|
|
||||||
&self.changes,
|
&self.changes,
|
||||||
&self.storage_transaction_cache,
|
&self.storage_transaction_cache,
|
||||||
&self.initialized_block,
|
|
||||||
&self.recorder,
|
&self.recorder,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -501,20 +503,16 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
|
|||||||
self.call_api_at(
|
self.call_api_at(
|
||||||
|
|
|
|
||||||
call_runtime_at,
|
call_runtime_at,
|
||||||
core_api,
|
|
||||||
changes,
|
changes,
|
||||||
storage_transaction_cache,
|
storage_transaction_cache,
|
||||||
initialized_block,
|
|
||||||
recorder
|
recorder
|
||||||
| {
|
| {
|
||||||
#runtime_mod_path #call_api_at_call(
|
#runtime_mod_path #call_api_at_call(
|
||||||
call_runtime_at,
|
call_runtime_at,
|
||||||
core_api,
|
|
||||||
at,
|
at,
|
||||||
params_encoded,
|
params_encoded,
|
||||||
changes,
|
changes,
|
||||||
storage_transaction_cache,
|
storage_transaction_cache,
|
||||||
initialized_block,
|
|
||||||
params.map(|p| {
|
params.map(|p| {
|
||||||
#runtime_mod_path #native_call_generator_ident ::
|
#runtime_mod_path #native_call_generator_ident ::
|
||||||
<#runtime, __SR_API_BLOCK__ #(, #trait_generic_arguments )*> (
|
<#runtime, __SR_API_BLOCK__ #(, #trait_generic_arguments )*> (
|
||||||
|
|||||||
@@ -94,6 +94,13 @@ fn implement_common_api_traits(
|
|||||||
Ok(pred(A::VERSION))
|
Ok(pred(A::VERSION))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn api_version<A: #crate_::RuntimeApiInfo + ?Sized>(
|
||||||
|
&self,
|
||||||
|
_: &#crate_::BlockId<#block_type>,
|
||||||
|
) -> std::result::Result<Option<u32>, #crate_::ApiError> where Self: Sized {
|
||||||
|
Ok(Some(A::VERSION))
|
||||||
|
}
|
||||||
|
|
||||||
fn record_proof(&mut self) {
|
fn record_proof(&mut self) {
|
||||||
unimplemented!("`record_proof` not implemented for runtime api mocks")
|
unimplemented!("`record_proof` not implemented for runtime api mocks")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,20 +17,29 @@
|
|||||||
|
|
||||||
//! Substrate runtime api
|
//! Substrate runtime api
|
||||||
//!
|
//!
|
||||||
//! The Substrate runtime api is the crucial interface between the node and the runtime.
|
//! The Substrate runtime api is the interface between the node and the runtime. There isn't a fixed
|
||||||
//! Every call that goes into the runtime is done with a runtime api. The runtime apis are not fixed.
|
//! set of runtime apis, instead it is up to the user to declare and implement these runtime apis.
|
||||||
//! Every Substrate user can define its own apis with
|
//! The declaration of a runtime api is normally done outside of a runtime, while the implementation
|
||||||
//! [`decl_runtime_apis`](macro.decl_runtime_apis.html) and implement them in
|
//! of it has to be done in the runtime. We provide the [`decl_runtime_apis!`] macro for declaring
|
||||||
//! the runtime with [`impl_runtime_apis`](macro.impl_runtime_apis.html).
|
//! 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
|
//! It is required that each runtime implements at least the [`Core`] runtime api. This runtime api
|
||||||
//! functionality that every runtime needs to export.
|
//! 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
|
//! # Versioning
|
||||||
//! api, the [`ApiExt`] trait, the [`CallApiAt`] trait and the [`ConstructRuntimeApi`] trait.
|
|
||||||
//!
|
//!
|
||||||
//! 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
|
//! # Logging
|
||||||
//!
|
//!
|
||||||
@@ -43,6 +52,17 @@
|
|||||||
//! that this feature instructs `log` and `tracing` to disable logging at compile time by setting
|
//! 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
|
//! 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.
|
//! 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)]
|
#![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.
|
/// to the client side and the runtime side. This generic parameter is usable by the user.
|
||||||
///
|
///
|
||||||
/// For implementing these macros you should use the
|
/// For implementing these macros you should use the
|
||||||
/// [`impl_runtime_apis!`](macro.impl_runtime_apis.html) macro.
|
/// [`impl_runtime_apis!`] macro.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
@@ -461,6 +481,12 @@ pub trait ApiExt<Block: BlockT> {
|
|||||||
pred: P,
|
pred: P,
|
||||||
) -> Result<bool, ApiError> where Self: Sized;
|
) -> 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.
|
/// Start recording all accessed trie nodes for generating proofs.
|
||||||
fn record_proof(&mut self);
|
fn record_proof(&mut self);
|
||||||
|
|
||||||
@@ -489,31 +515,9 @@ pub trait ApiExt<Block: BlockT> {
|
|||||||
> where Self: Sized;
|
> 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`].
|
/// Parameters for [`CallApiAt::call_api_at`].
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub struct CallApiAtParams<'a, Block: BlockT, C, NC, Backend: StateBackend<HashFor<Block>>> {
|
pub struct CallApiAtParams<'a, Block: BlockT, NC, Backend: StateBackend<HashFor<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.
|
/// The block id that determines the state that should be setup when calling the function.
|
||||||
pub at: &'a BlockId<Block>,
|
pub at: &'a BlockId<Block>,
|
||||||
/// The name of the function that should be called.
|
/// 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>,
|
pub overlayed_changes: &'a RefCell<OverlayedChanges>,
|
||||||
/// The cache for storage transactions.
|
/// The cache for storage transactions.
|
||||||
pub storage_transaction_cache: &'a RefCell<StorageTransactionCache<Block, Backend>>,
|
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.
|
/// The context this function is executed in.
|
||||||
pub context: ExecutionContext,
|
pub context: ExecutionContext,
|
||||||
/// The optional proof recorder for recording storage accesses.
|
/// The optional proof recorder for recording storage accesses.
|
||||||
@@ -550,10 +551,9 @@ pub trait CallApiAt<Block: BlockT> {
|
|||||||
'a,
|
'a,
|
||||||
R: Encode + Decode + PartialEq,
|
R: Encode + Decode + PartialEq,
|
||||||
NC: FnOnce() -> result::Result<R, ApiError> + UnwindSafe,
|
NC: FnOnce() -> result::Result<R, ApiError> + UnwindSafe,
|
||||||
C: Core<Block>,
|
|
||||||
>(
|
>(
|
||||||
&self,
|
&self,
|
||||||
params: CallApiAtParams<'a, Block, C, NC, Self::StateBackend>,
|
params: CallApiAtParams<'a, Block, NC, Self::StateBackend>,
|
||||||
) -> Result<NativeOrEncoded<R>, ApiError>;
|
) -> Result<NativeOrEncoded<R>, ApiError>;
|
||||||
|
|
||||||
/// Returns the runtime version at the given block.
|
/// Returns the runtime version at the given block.
|
||||||
@@ -704,12 +704,9 @@ decl_runtime_apis! {
|
|||||||
#[changed_in(3)]
|
#[changed_in(3)]
|
||||||
fn version() -> OldRuntimeVersion;
|
fn version() -> OldRuntimeVersion;
|
||||||
/// Execute the given block.
|
/// Execute the given block.
|
||||||
#[skip_initialize_block]
|
|
||||||
fn execute_block(block: Block);
|
fn execute_block(block: Block);
|
||||||
/// Initialize a block with the given header.
|
/// Initialize a block with the given header.
|
||||||
#[renamed("initialise_block", 2)]
|
#[renamed("initialise_block", 2)]
|
||||||
#[skip_initialize_block]
|
|
||||||
#[initialize_block]
|
|
||||||
fn initialize_block(header: &<Block as BlockT>::Header);
|
fn initialize_block(header: &<Block as BlockT>::Header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,11 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use sp_api::ProvideRuntimeApi;
|
use sp_api::{ProvideRuntimeApi, Core};
|
||||||
use substrate_test_runtime_client::{
|
use substrate_test_runtime_client::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
DefaultTestClientBuilderExt, TestClientBuilder,
|
DefaultTestClientBuilderExt, TestClientBuilder,
|
||||||
runtime::{TestAPI, DecodeFails, Transfer, Block},
|
runtime::{TestAPI, DecodeFails, Transfer, Block, Header},
|
||||||
};
|
};
|
||||||
use sp_runtime::{generic::BlockId, traits::{Header as HeaderT, HashFor}};
|
use sp_runtime::{generic::BlockId, traits::{Header as HeaderT, HashFor}};
|
||||||
use sp_state_machine::{
|
use sp_state_machine::{
|
||||||
@@ -133,26 +133,13 @@ fn initialize_block_works() {
|
|||||||
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build();
|
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build();
|
||||||
let runtime_api = client.runtime_api();
|
let runtime_api = client.runtime_api();
|
||||||
let block_id = BlockId::Number(client.chain_info().best_number);
|
let block_id = BlockId::Number(client.chain_info().best_number);
|
||||||
|
runtime_api.initialize_block(
|
||||||
|
&block_id,
|
||||||
|
&Header::new(1, Default::default(), Default::default(), Default::default(), Default::default()),
|
||||||
|
).unwrap();
|
||||||
assert_eq!(runtime_api.get_block_number(&block_id).unwrap(), 1);
|
assert_eq!(runtime_api.get_block_number(&block_id).unwrap(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn initialize_block_is_called_only_once() {
|
|
||||||
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build();
|
|
||||||
let runtime_api = client.runtime_api();
|
|
||||||
let block_id = BlockId::Number(client.chain_info().best_number);
|
|
||||||
assert_eq!(runtime_api.take_block_number(&block_id).unwrap(), Some(1));
|
|
||||||
assert_eq!(runtime_api.take_block_number(&block_id).unwrap(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn initialize_block_is_skipped() {
|
|
||||||
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build();
|
|
||||||
let runtime_api = client.runtime_api();
|
|
||||||
let block_id = BlockId::Number(client.chain_info().best_number);
|
|
||||||
assert!(runtime_api.without_initialize_block(&block_id).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn record_proof_works() {
|
fn record_proof_works() {
|
||||||
let (client, longest_chain) = TestClientBuilder::new()
|
let (client, longest_chain) = TestClientBuilder::new()
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ sp_api::decl_runtime_apis! {
|
|||||||
fn slot_duration() -> SlotDuration;
|
fn slot_duration() -> SlotDuration;
|
||||||
|
|
||||||
// Return the current set of authorities.
|
// Return the current set of authorities.
|
||||||
#[skip_initialize_block]
|
|
||||||
fn authorities() -> Vec<AuthorityId>;
|
fn authorities() -> Vec<AuthorityId>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,12 +28,10 @@ sp_api::decl_runtime_apis! {
|
|||||||
#[api_version(2)]
|
#[api_version(2)]
|
||||||
pub trait OffchainWorkerApi {
|
pub trait OffchainWorkerApi {
|
||||||
/// Starts the off-chain task for given block number.
|
/// Starts the off-chain task for given block number.
|
||||||
#[skip_initialize_block]
|
|
||||||
#[changed_in(2)]
|
#[changed_in(2)]
|
||||||
fn offchain_worker(number: sp_runtime::traits::NumberFor<Block>);
|
fn offchain_worker(number: sp_runtime::traits::NumberFor<Block>);
|
||||||
|
|
||||||
/// Starts the off-chain task for given block header.
|
/// Starts the off-chain task for given block header.
|
||||||
#[skip_initialize_block]
|
|
||||||
fn offchain_worker(header: &Block::Header);
|
fn offchain_worker(header: &Block::Header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,22 +22,32 @@ use sp_runtime::traits::Block as BlockT;
|
|||||||
|
|
||||||
sp_api::decl_runtime_apis! {
|
sp_api::decl_runtime_apis! {
|
||||||
/// The `TaggedTransactionQueue` api trait for interfering with the transaction queue.
|
/// The `TaggedTransactionQueue` api trait for interfering with the transaction queue.
|
||||||
#[api_version(2)]
|
#[api_version(3)]
|
||||||
pub trait TaggedTransactionQueue {
|
pub trait TaggedTransactionQueue {
|
||||||
/// Validate the transaction.
|
/// Validate the transaction.
|
||||||
#[changed_in(2)]
|
#[changed_in(2)]
|
||||||
fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity;
|
fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity;
|
||||||
|
|
||||||
|
/// Validate the transaction.
|
||||||
|
#[changed_in(3)]
|
||||||
|
fn validate_transaction(
|
||||||
|
source: TransactionSource,
|
||||||
|
tx: <Block as BlockT>::Extrinsic,
|
||||||
|
) -> TransactionValidity;
|
||||||
|
|
||||||
/// Validate the transaction.
|
/// Validate the transaction.
|
||||||
///
|
///
|
||||||
/// This method is invoked by the transaction pool to learn details about given transaction.
|
/// This method is invoked by the transaction pool to learn details about given transaction.
|
||||||
/// The implementation should make sure to verify the correctness of the transaction
|
/// The implementation should make sure to verify the correctness of the transaction
|
||||||
/// against current state.
|
/// against current state. The given `block_hash` corresponds to the hash of the block
|
||||||
|
/// that is used as current state.
|
||||||
|
///
|
||||||
/// Note that this call may be performed by the pool multiple times and transactions
|
/// Note that this call may be performed by the pool multiple times and transactions
|
||||||
/// might be verified in any possible order.
|
/// might be verified in any possible order.
|
||||||
fn validate_transaction(
|
fn validate_transaction(
|
||||||
source: TransactionSource,
|
source: TransactionSource,
|
||||||
tx: <Block as BlockT>::Extrinsic,
|
tx: <Block as BlockT>::Extrinsic,
|
||||||
|
block_hash: Block::Hash,
|
||||||
) -> TransactionValidity;
|
) -> TransactionValidity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,6 +198,11 @@ impl RuntimeVersion {
|
|||||||
) -> bool {
|
) -> bool {
|
||||||
self.apis.iter().any(|(s, v)| s == id && predicate(*v))
|
self.apis.iter().any(|(s, v)| s == id && predicate(*v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the api version found for api with `id`.
|
||||||
|
pub fn api_version(&self, id: &ApiId) -> Option<u32> {
|
||||||
|
self.apis.iter().find_map(|a| (a.0 == *id).then(|| a.1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
|||||||
@@ -343,9 +343,6 @@ cfg_if! {
|
|||||||
fn get_block_number() -> u64;
|
fn get_block_number() -> u64;
|
||||||
/// Takes and returns the initialized block number.
|
/// Takes and returns the initialized block number.
|
||||||
fn take_block_number() -> Option<u64>;
|
fn take_block_number() -> Option<u64>;
|
||||||
/// Returns if no block was initialized.
|
|
||||||
#[skip_initialize_block]
|
|
||||||
fn without_initialize_block() -> bool;
|
|
||||||
/// Test that `ed25519` crypto works in the runtime.
|
/// Test that `ed25519` crypto works in the runtime.
|
||||||
///
|
///
|
||||||
/// Returns the signature generated for the message `ed25519` and the public key.
|
/// Returns the signature generated for the message `ed25519` and the public key.
|
||||||
@@ -396,9 +393,6 @@ cfg_if! {
|
|||||||
fn get_block_number() -> u64;
|
fn get_block_number() -> u64;
|
||||||
/// Takes and returns the initialized block number.
|
/// Takes and returns the initialized block number.
|
||||||
fn take_block_number() -> Option<u64>;
|
fn take_block_number() -> Option<u64>;
|
||||||
/// Returns if no block was initialized.
|
|
||||||
#[skip_initialize_block]
|
|
||||||
fn without_initialize_block() -> bool;
|
|
||||||
/// Test that `ed25519` crypto works in the runtime.
|
/// Test that `ed25519` crypto works in the runtime.
|
||||||
///
|
///
|
||||||
/// Returns the signature generated for the message `ed25519` and the public key.
|
/// Returns the signature generated for the message `ed25519` and the public key.
|
||||||
@@ -635,6 +629,7 @@ cfg_if! {
|
|||||||
fn validate_transaction(
|
fn validate_transaction(
|
||||||
_source: TransactionSource,
|
_source: TransactionSource,
|
||||||
utx: <Block as BlockT>::Extrinsic,
|
utx: <Block as BlockT>::Extrinsic,
|
||||||
|
_: <Block as BlockT>::Hash,
|
||||||
) -> TransactionValidity {
|
) -> TransactionValidity {
|
||||||
if let Extrinsic::IncludeData(data) = utx {
|
if let Extrinsic::IncludeData(data) = utx {
|
||||||
return Ok(ValidTransaction {
|
return Ok(ValidTransaction {
|
||||||
@@ -720,10 +715,6 @@ cfg_if! {
|
|||||||
system::get_block_number().expect("Block number is initialized")
|
system::get_block_number().expect("Block number is initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn without_initialize_block() -> bool {
|
|
||||||
system::get_block_number().is_none()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_block_number() -> Option<u64> {
|
fn take_block_number() -> Option<u64> {
|
||||||
system::take_block_number()
|
system::take_block_number()
|
||||||
}
|
}
|
||||||
@@ -888,6 +879,7 @@ cfg_if! {
|
|||||||
fn validate_transaction(
|
fn validate_transaction(
|
||||||
_source: TransactionSource,
|
_source: TransactionSource,
|
||||||
utx: <Block as BlockT>::Extrinsic,
|
utx: <Block as BlockT>::Extrinsic,
|
||||||
|
_: <Block as BlockT>::Hash,
|
||||||
) -> TransactionValidity {
|
) -> TransactionValidity {
|
||||||
if let Extrinsic::IncludeData(data) = utx {
|
if let Extrinsic::IncludeData(data) = utx {
|
||||||
return Ok(ValidTransaction{
|
return Ok(ValidTransaction{
|
||||||
@@ -977,10 +969,6 @@ cfg_if! {
|
|||||||
system::get_block_number().expect("Block number is initialized")
|
system::get_block_number().expect("Block number is initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn without_initialize_block() -> bool {
|
|
||||||
system::get_block_number().is_none()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_block_number() -> Option<u64> {
|
fn take_block_number() -> Option<u64> {
|
||||||
system::take_block_number()
|
system::take_block_number()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,7 +193,8 @@ pub fn validate_transaction(utx: Extrinsic) -> TransactionValidity {
|
|||||||
/// Execute a transaction outside of the block execution function.
|
/// Execute a transaction outside of the block execution function.
|
||||||
/// This doesn't attempt to validate anything regarding the block.
|
/// This doesn't attempt to validate anything regarding the block.
|
||||||
pub fn execute_transaction(utx: Extrinsic) -> ApplyExtrinsicResult {
|
pub fn execute_transaction(utx: Extrinsic) -> ApplyExtrinsicResult {
|
||||||
let extrinsic_index: u32 = storage::unhashed::get(well_known_keys::EXTRINSIC_INDEX).unwrap();
|
let extrinsic_index: u32 = storage::unhashed::get(well_known_keys::EXTRINSIC_INDEX)
|
||||||
|
.unwrap_or_default();
|
||||||
let result = execute_transaction_backend(&utx, extrinsic_index);
|
let result = execute_transaction_backend(&utx, extrinsic_index);
|
||||||
ExtrinsicData::insert(extrinsic_index, utx.encode());
|
ExtrinsicData::insert(extrinsic_index, utx.encode());
|
||||||
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &(extrinsic_index + 1));
|
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &(extrinsic_index + 1));
|
||||||
|
|||||||
Reference in New Issue
Block a user