From d489bd70b5eaec33e49e4a5e126ce99f29f557e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 1 Jul 2021 17:50:42 +0200 Subject: [PATCH] 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 --- .../bin/node-template/runtime/src/lib.rs | 3 +- .../node/executor/tests/submit_transaction.rs | 8 +- substrate/bin/node/runtime/src/lib.rs | 3 +- substrate/client/api/src/call_executor.rs | 6 +- substrate/client/light/src/call_executor.rs | 75 ++--------------- substrate/client/rpc/src/state/tests.rs | 2 +- .../service/src/client/call_executor.rs | 15 +--- substrate/client/service/src/client/client.rs | 24 +----- .../client/service/test/src/client/light.rs | 53 +++++------- substrate/client/transaction-pool/src/api.rs | 54 ++++++++++--- substrate/frame/executive/src/lib.rs | 20 ++++- .../primitives/src/lib.rs | 3 - .../api/proc-macro/src/decl_runtime_apis.rs | 45 +---------- .../api/proc-macro/src/impl_runtime_apis.rs | 28 +++---- .../proc-macro/src/mock_impl_runtime_apis.rs | 7 ++ substrate/primitives/api/src/lib.rs | 81 +++++++++---------- .../api/test/tests/runtime_calls.rs | 25 ++---- .../primitives/consensus/aura/src/lib.rs | 1 - substrate/primitives/offchain/src/lib.rs | 2 - .../transaction-pool/src/runtime_api.rs | 14 +++- substrate/primitives/version/src/lib.rs | 5 ++ substrate/test-utils/runtime/src/lib.rs | 16 +--- substrate/test-utils/runtime/src/system.rs | 3 +- 23 files changed, 192 insertions(+), 301 deletions(-) diff --git a/substrate/bin/node-template/runtime/src/lib.rs b/substrate/bin/node-template/runtime/src/lib.rs index e89d7f28be..940eb2379b 100644 --- a/substrate/bin/node-template/runtime/src/lib.rs +++ b/substrate/bin/node-template/runtime/src/lib.rs @@ -365,8 +365,9 @@ impl_runtime_apis! { fn validate_transaction( source: TransactionSource, tx: ::Extrinsic, + block_hash: ::Hash, ) -> TransactionValidity { - Executive::validate_transaction(source, tx) + Executive::validate_transaction(source, tx, block_hash) } } diff --git a/substrate/bin/node/executor/tests/submit_transaction.rs b/substrate/bin/node/executor/tests/submit_transaction.rs index 3de0758d81..590bdac4db 100644 --- a/substrate/bin/node/executor/tests/submit_transaction.rs +++ b/substrate/bin/node/executor/tests/submit_transaction.rs @@ -256,12 +256,16 @@ fn submitted_transaction_should_be_valid() { >::insert(&address, account); // check validity - let res = Executive::validate_transaction(source, extrinsic).unwrap(); + let res = Executive::validate_transaction( + source, + extrinsic, + frame_system::BlockHash::::get(0), + ).unwrap(); // We ignore res.priority since this number can change based on updates to weights and such. assert_eq!(res.requires, Vec::::new()); assert_eq!(res.provides, vec![(address, 0).encode()]); - assert_eq!(res.longevity, 2048); + assert_eq!(res.longevity, 2047); assert_eq!(res.propagate, true); }); } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index fd7fd42133..109a492e2c 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -1292,8 +1292,9 @@ impl_runtime_apis! { fn validate_transaction( source: TransactionSource, tx: ::Extrinsic, + block_hash: ::Hash, ) -> TransactionValidity { - Executive::validate_transaction(source, tx) + Executive::validate_transaction(source, tx, block_hash) } } diff --git a/substrate/client/api/src/call_executor.rs b/substrate/client/api/src/call_executor.rs index 3b725bf877..621cc292a7 100644 --- a/substrate/client/api/src/call_executor.rs +++ b/substrate/client/api/src/call_executor.rs @@ -30,7 +30,7 @@ use sc_executor::{RuntimeVersion, NativeVersion}; use sp_externalities::Extensions; use sp_core::NativeOrEncoded; -use sp_api::{ProofRecorder, InitializeBlock, StorageTransactionCache}; +use sp_api::{ProofRecorder, StorageTransactionCache}; use crate::execution_extensions::ExecutionExtensions; /// Executor Provider @@ -71,8 +71,6 @@ pub trait CallExecutor { /// Before executing the method, passed header is installed as the current header /// of the execution context. fn contextual_call< - 'a, - IB: Fn() -> sp_blockchain::Result<()>, EM: Fn( Result, Self::Error>, Result, Self::Error> @@ -81,7 +79,6 @@ pub trait CallExecutor { NC: FnOnce() -> result::Result + UnwindSafe, >( &self, - initialize_block_fn: IB, at: &BlockId, method: &str, call_data: &[u8], @@ -89,7 +86,6 @@ pub trait CallExecutor { storage_transaction_cache: Option<&RefCell< StorageTransactionCache>::State>, >>, - initialize_block: InitializeBlock<'a, B>, execution_manager: ExecutionManager, native_call: Option, proof_recorder: &Option>, diff --git a/substrate/client/light/src/call_executor.rs b/substrate/client/light/src/call_executor.rs index ae83807dc9..c9ca3bab37 100644 --- a/substrate/client/light/src/call_executor.rs +++ b/substrate/client/light/src/call_executor.rs @@ -27,7 +27,7 @@ use sp_core::{ convert_hash, NativeOrEncoded, traits::{CodeExecutor, SpawnNamed}, }; 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_state_machine::{ @@ -36,7 +36,7 @@ use sp_state_machine::{ }; use hash_db::Hasher; -use sp_api::{ProofRecorder, InitializeBlock, StorageTransactionCache}; +use sp_api::{ProofRecorder, StorageTransactionCache}; use sp_blockchain::{Error as ClientError, Result as ClientResult}; @@ -97,8 +97,6 @@ impl CallExecutor for } fn contextual_call< - 'a, - IB: Fn() -> ClientResult<()>, EM: Fn( Result, Self::Error>, Result, Self::Error> @@ -107,13 +105,11 @@ impl CallExecutor for NC: FnOnce() -> result::Result + UnwindSafe, >( &self, - initialize_block_fn: IB, at: &BlockId, method: &str, call_data: &[u8], changes: &RefCell, _: Option<&RefCell>>, - initialize_block: InitializeBlock<'a, Block>, _manager: ExecutionManager, native_call: Option, recorder: &Option>, @@ -124,7 +120,6 @@ impl CallExecutor for match self.backend.is_local_state_available(at) { true => CallExecutor::contextual_call::< - _, fn( Result, Local::Error>, Result, Local::Error>, @@ -133,13 +128,11 @@ impl CallExecutor for NC >( &self.local, - initialize_block_fn, at, method, call_data, changes, None, - initialize_block, ExecutionManager::NativeWhenPossible, native_call, recorder, @@ -177,7 +170,6 @@ impl CallExecutor for /// Proof includes both environment preparation proof and method execution proof. pub fn prove_execution( mut state: S, - header: Block::Header, executor: &E, method: &str, call_data: &[u8], @@ -193,31 +185,20 @@ pub fn prove_execution( Box )?; - // 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 let (result, exec_proof) = executor.prove_at_trie_state( &trie_state, - &mut changes, + &mut Default::default(), method, 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. /// -/// Method is executed using passed header as environment' current block. -/// Proof should include both environment preparation proof and method execution proof. +/// Proof should include the method execution proof. pub fn check_execution_proof( executor: &E, spawn_handle: Box, @@ -229,63 +210,19 @@ pub fn check_execution_proof( E: CodeExecutor + Clone + 'static, H: Hasher, H::Out: Ord + codec::Codec + 'static, -{ - check_execution_proof_with_make_header::( - executor, - spawn_handle, - request, - remote_proof, - |header|
::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( - executor: &E, - spawn_handle: Box, - request: &RemoteCallRequest
, - remote_proof: StorageProof, - make_next_header: MakeNextHeader, -) -> ClientResult> - 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 root: H::Out = convert_hash(&local_state_root); - // prepare execution environment + check preparation proof + // prepare execution environment let mut changes = OverlayedChanges::default(); 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 let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&trie_backend); let runtime_code = backend_runtime_code.runtime_code() .map_err(|_e| ClientError::RuntimeCodeMissing)?; - execution_proof_check_on_trie_backend::( - &trie_backend, - &mut changes, - executor, - spawn_handle.clone(), - "Core_initialize_block", - &next_header.encode(), - &runtime_code, - )?; - // execute method execution_proof_check_on_trie_backend::( &trie_backend, diff --git a/substrate/client/rpc/src/state/tests.rs b/substrate/client/rpc/src/state/tests.rs index e413827552..c9cb0bde89 100644 --- a/substrate/client/rpc/src/state/tests.rs +++ b/substrate/client/rpc/src/state/tests.rs @@ -474,7 +474,7 @@ fn should_return_runtime_version() { let result = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\ \"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],\ [\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]],\ \"transactionVersion\":1}"; diff --git a/substrate/client/service/src/client/call_executor.rs b/substrate/client/service/src/client/call_executor.rs index c8c1fee545..a444819947 100644 --- a/substrate/client/service/src/client/call_executor.rs +++ b/substrate/client/service/src/client/call_executor.rs @@ -30,7 +30,7 @@ use sp_externalities::Extensions; use sp_core::{ 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 super::{client::ClientConfig, wasm_override::WasmOverride, wasm_substitutes::WasmSubstitutes}; @@ -173,8 +173,6 @@ where } fn contextual_call< - 'a, - IB: Fn() -> sp_blockchain::Result<()>, EM: Fn( Result, Self::Error>, Result, Self::Error> @@ -183,7 +181,6 @@ where NC: FnOnce() -> result::Result + UnwindSafe, >( &self, - initialize_block_fn: IB, at: &BlockId, method: &str, call_data: &[u8], @@ -191,21 +188,11 @@ where storage_transaction_cache: Option<&RefCell< StorageTransactionCache >>, - initialize_block: InitializeBlock<'a, Block>, execution_manager: ExecutionManager, native_call: Option, recorder: &Option>, extensions: Option, ) -> Result, sp_blockchain::Error> where ExecutionManager: 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 mut storage_transaction_cache = storage_transaction_cache.map(|c| c.borrow_mut()); diff --git a/substrate/client/service/src/client/client.rs b/substrate/client/service/src/client/client.rs index 4a998a12d2..ab5a0d9394 100644 --- a/substrate/client/service/src/client/client.rs +++ b/substrate/client/service/src/client/client.rs @@ -1243,18 +1243,6 @@ impl Client where trace!("Collected {} uncles", uncles.len()); Ok(uncles) } - - /// Prepare in-memory header that is used in execution environment. - fn prepare_environment_block(&self, parent: &BlockId) -> sp_blockchain::Result { - let parent_hash = self.backend.blockchain().expect_block_hash_from_id(parent)?; - Ok(<::Header as HeaderT>::new( - self.backend.blockchain().expect_block_number_from_id(parent)? + One::one(), - Default::default(), - Default::default(), - parent_hash, - Default::default(), - )) - } } impl UsageProvider for Client where @@ -1313,10 +1301,8 @@ impl ProofProvider for Client where )?; let state = self.state_at(id)?; - let header = self.prepare_environment_block(id)?; prove_execution( state, - header, &self.executor, method, call_data, @@ -1782,12 +1768,10 @@ impl CallApiAt for Client where 'a, R: Encode + Decode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, - C: CoreApi, >( &self, - params: CallApiAtParams<'a, Block, C, NC, B::State>, + params: CallApiAtParams<'a, Block, NC, B::State>, ) -> Result, sp_api::ApiError> { - let core_api = params.core_api; let at = params.at; let (manager, extensions) = self.execution_extensions.manager_and_extensions( @@ -1795,16 +1779,12 @@ impl CallApiAt for Client where params.context, ); - self.executor.contextual_call::<_, fn(_,_) -> _,_,_>( - || core_api - .initialize_block(at, &self.prepare_environment_block(at)?) - .map_err(Error::RuntimeApiError), + self.executor.contextual_call:: _, _, _>( at, params.function, ¶ms.arguments, params.overlayed_changes, Some(params.storage_transaction_cache), - params.initialize_block, manager, params.native_call, params.recorder, diff --git a/substrate/client/service/test/src/client/light.rs b/substrate/client/service/test/src/client/light.rs index 8841d498ec..440e0b4dd0 100644 --- a/substrate/client/service/test/src/client/light.rs +++ b/substrate/client/service/test/src/client/light.rs @@ -20,7 +20,6 @@ use sc_light::{ call_executor::{ GenesisCallExecutor, check_execution_proof, - check_execution_proof_with_make_header, }, fetcher::LightDataChecker, blockchain::{BlockchainCache, Blockchain}, @@ -37,7 +36,7 @@ use parking_lot::Mutex; use substrate_test_runtime_client::{ runtime::{Hash, Block, Header}, TestClient, ClientBlockImportExt, }; -use sp_api::{InitializeBlock, StorageTransactionCache, ProofRecorder}; +use sp_api::{StorageTransactionCache, ProofRecorder}; use sp_consensus::BlockOrigin; use sc_executor::{NativeExecutor, WasmExecutionMethod, RuntimeVersion, NativeVersion}; use sp_core::{H256, NativeOrEncoded, testing::TaskExecutor}; @@ -209,8 +208,6 @@ impl CallExecutor for DummyCallExecutor { } fn contextual_call< - 'a, - IB: Fn() -> ClientResult<()>, EM: Fn( Result, Self::Error>, Result, Self::Error> @@ -219,7 +216,6 @@ impl CallExecutor for DummyCallExecutor { NC: FnOnce() -> Result + UnwindSafe, >( &self, - _initialize_block_fn: IB, _at: &BlockId, _method: &str, _call_data: &[u8], @@ -230,7 +226,6 @@ impl CallExecutor for DummyCallExecutor { >::State, > >>, - _initialize_block: InitializeBlock<'a, Block>, _execution_manager: ExecutionManager, _native_call: Option, _proof_recorder: &Option>, @@ -333,36 +328,41 @@ fn execution_proof_is_generated_and_checked() { (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_header = remote_client.header(&remote_block_id).unwrap().unwrap(); // 'fetch' execution proof from remote node let (_, remote_execution_proof) = remote_client.execution_proof( &remote_block_id, - method, - &[] + "Core_initialize_block", + &Header::new( + at, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + ).encode(), ).unwrap(); // check remote execution proof locally - let execution_result = check_execution_proof_with_make_header::<_, _, BlakeTwo256, _>( + let execution_result = check_execution_proof::<_, _, BlakeTwo256>( &local_executor(), Box::new(TaskExecutor::new()), &RemoteCallRequest { block: substrate_test_runtime_client::runtime::Hash::default(), - header: remote_header, - method: method.into(), - call_data: vec![], + header: remote_header.clone(), + method: "Core_initialize_block".into(), + 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, }, remote_execution_proof, - |header|
::new( - at + 1, - Default::default(), - Default::default(), - header.hash(), - header.digest().clone(), // this makes next header wrong - ), ); match execution_result { 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"); 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 - 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 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] diff --git a/substrate/client/transaction-pool/src/api.rs b/substrate/client/transaction-pool/src/api.rs index 74e08c3aa0..dd54e8e769 100644 --- a/substrate/client/transaction-pool/src/api.rs +++ b/substrate/client/transaction-pool/src/api.rs @@ -203,24 +203,54 @@ where sp_tracing::within_span!(sp_tracing::Level::TRACE, "validate_transaction"; { 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 - .has_api_with::, _>(&at, |v| v >= 2) - .unwrap_or_default() - }; + .api_version::>(&at) + .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"; { - if has_v2 { - runtime_api.validate_transaction(&at, source, uxt) + if api_version >= 3 { + runtime_api.validate_transaction(&at, source, uxt, block_hash) + .map_err(|e| Error::RuntimeApi(e.to_string())) } else { - #[allow(deprecated)] // old validate_transaction - runtime_api.validate_transaction_before_version_2(&at, uxt) - } - }); + let block_number = client.to_number(at) + .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())) + } + } + }) }) } diff --git a/substrate/frame/executive/src/lib.rs b/substrate/frame/executive/src/lib.rs index 1d2ad069f0..c5f39e14f5 100644 --- a/substrate/frame/executive/src/lib.rs +++ b/substrate/frame/executive/src/lib.rs @@ -474,10 +474,18 @@ where pub fn validate_transaction( source: TransactionSource, uxt: Block::Extrinsic, + block_hash: Block::Hash, ) -> TransactionValidity { sp_io::init_tracing(); use sp_tracing::{enter_span, within_span}; + >::initialize( + &(frame_system::Pallet::::block_number() + One::one()), + &block_hash, + &Default::default(), + frame_system::InitKind::Inspection, + ); + enter_span!{ sp_tracing::Level::TRACE, "validate_transaction" }; let encoded_len = within_span!{ sp_tracing::Level::TRACE, "using_encoded"; @@ -1006,11 +1014,19 @@ mod tests { default_with_prio_3.priority = 3; t.execute_with(|| { assert_eq!( - Executive::validate_transaction(TransactionSource::InBlock, valid.clone()), + Executive::validate_transaction( + TransactionSource::InBlock, + valid.clone(), + Default::default(), + ), Ok(default_with_prio_3), ); assert_eq!( - Executive::validate_transaction(TransactionSource::InBlock, invalid.clone()), + Executive::validate_transaction( + TransactionSource::InBlock, + invalid.clone(), + Default::default(), + ), Err(TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator)), ); assert_eq!(Executive::apply_extrinsic(valid), Ok(Err(DispatchError::BadOrigin))); diff --git a/substrate/frame/merkle-mountain-range/primitives/src/lib.rs b/substrate/frame/merkle-mountain-range/primitives/src/lib.rs index 73d4d3ecc1..7b562656a1 100644 --- a/substrate/frame/merkle-mountain-range/primitives/src/lib.rs +++ b/substrate/frame/merkle-mountain-range/primitives/src/lib.rs @@ -406,7 +406,6 @@ sp_api::decl_runtime_apis! { /// API to interact with MMR pallet. pub trait MmrApi { /// Generate MMR proof for a leaf under given index. - #[skip_initialize_block] fn generate_proof(leaf_index: u64) -> Result<(EncodableOpaqueLeaf, Proof), Error>; /// 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 /// matches the hash. /// See [Self::verify_proof_stateless] for a stateless verifier. - #[skip_initialize_block] fn verify_proof(leaf: EncodableOpaqueLeaf, proof: Proof) -> Result<(), Error>; /// Verify MMR proof against given root hash. @@ -423,7 +421,6 @@ sp_api::decl_runtime_apis! { /// proof is verified against given MMR root hash. /// /// 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) -> Result<(), Error>; } diff --git a/substrate/primitives/api/proc-macro/src/decl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/decl_runtime_apis.rs index 9fd5baba87..4a8b49049e 100644 --- a/substrate/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -58,21 +58,9 @@ const CHANGED_IN_ATTRIBUTE: &str = "changed_in"; /// /// Is used when a trait method was 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. const SUPPORTED_ATTRIBUTE_NAMES: &[&str] = &[ - CORE_TRAIT_ATTRIBUTE, API_VERSION_ATTRIBUTE, CHANGED_IN_ATTRIBUTE, - RENAMED_ATTRIBUTE, SKIP_INITIALIZE_BLOCK_ATTRIBUTE, - INITIALIZE_BLOCK_ATTRIBUTE, + CORE_TRAIT_ATTRIBUTE, API_VERSION_ATTRIBUTE, CHANGED_IN_ATTRIBUTE, RENAMED_ATTRIBUTE, ]; /// The structure used for parsing the runtime api declarations. @@ -376,15 +364,6 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result { 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. let mut renames = Vec::new(); if let Some((_, a)) = attrs @@ -413,72 +392,54 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result { NC: FnOnce() -> std::result::Result + std::panic::UnwindSafe, Block: #crate_::BlockT, T: #crate_::CallApiAt, - C: #crate_::Core, >( call_runtime_at: &T, - core_api: &C, at: &#crate_::BlockId, args: Vec, changes: &std::cell::RefCell<#crate_::OverlayedChanges>, storage_transaction_cache: &std::cell::RefCell< #crate_::StorageTransactionCache >, - initialized_block: &std::cell::RefCell>>, native_call: Option, context: #crate_::ExecutionContext, recorder: &Option<#crate_::ProofRecorder>, ) -> std::result::Result<#crate_::NativeOrEncoded, #crate_::ApiError> { 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. if version.apis.iter().any(|(s, v)| { s == &ID && *v < #versions }) { - let params = #crate_::CallApiAtParams::<_, _, fn() -> _, _> { - core_api, + let params = #crate_::CallApiAtParams::<_, fn() -> _, _> { at, function: #old_names, native_call: None, arguments: args, overlayed_changes: changes, storage_transaction_cache, - initialize_block, context, recorder, }; let ret = call_runtime_at.call_api_at(params)?; - update_initialized_block(); return Ok(ret) } )* let params = #crate_::CallApiAtParams { - core_api, at, function: #trait_fn_name, native_call, arguments: args, overlayed_changes: changes, storage_transaction_cache, - initialize_block, context, recorder, }; - let ret = call_runtime_at.call_api_at(params)?; - - update_initialized_block(); - Ok(ret) + call_runtime_at.call_api_at(params) } )); } diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index cf1265fdb0..e81c52bbb0 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -122,9 +122,9 @@ fn generate_impl_calls( impl_calls.push(( impl_trait_ident.clone(), - method.sig.ident.clone(), - impl_call, - filter_cfg_attrs(&impl_.attrs), + method.sig.ident.clone(), + impl_call, + filter_cfg_attrs(&impl_.attrs), )); } } @@ -186,7 +186,7 @@ fn generate_wasm_interface(impls: &[ItemImpl]) -> Result { #c::init_runtime_logger(); - let output = { #impl_ }; + let output = (move || { #impl_ })(); #c::to_substrate_wasm_fn_return_value(&output) } ) @@ -205,7 +205,6 @@ fn generate_runtime_api_base_structures() -> Result { pub struct RuntimeApiImpl + 'static> { call: &'static C, commit_on_success: std::cell::RefCell, - initialized_block: std::cell::RefCell>>, changes: std::cell::RefCell<#crate_::OverlayedChanges>, storage_transaction_cache: std::cell::RefCell< #crate_::StorageTransactionCache @@ -265,6 +264,15 @@ fn generate_runtime_api_base_structures() -> Result { .map(|v| v.has_api_with(&A::ID, pred)) } + fn api_version( + &self, + at: &#crate_::BlockId, + ) -> std::result::Result, #crate_::ApiError> where Self: Sized { + self.call + .runtime_version_at(at) + .map(|v| v.api_version(&A::ID)) + } + fn record_proof(&mut self) { self.recorder = Some(Default::default()); } @@ -291,7 +299,6 @@ fn generate_runtime_api_base_structures() -> Result { #crate_::StorageChanges, String > where Self: Sized { - self.initialized_block.borrow_mut().take(); self.changes.replace(Default::default()).into_storage_changes( backend, changes_trie_state, @@ -315,7 +322,6 @@ fn generate_runtime_api_base_structures() -> Result { RuntimeApiImpl { call: unsafe { std::mem::transmute(call) }, commit_on_success: true.into(), - initialized_block: None.into(), changes: Default::default(), recorder: Default::default(), storage_transaction_cache: Default::default(), @@ -329,10 +335,8 @@ fn generate_runtime_api_base_structures() -> Result { R: #crate_::Encode + #crate_::Decode + PartialEq, F: FnOnce( &C, - &Self, &std::cell::RefCell<#crate_::OverlayedChanges>, &std::cell::RefCell<#crate_::StorageTransactionCache>, - &std::cell::RefCell>>, &Option<#crate_::ProofRecorder>, ) -> std::result::Result<#crate_::NativeOrEncoded, E>, E, @@ -345,10 +349,8 @@ fn generate_runtime_api_base_structures() -> Result { } let res = call_api_at( &self.call, - self, &self.changes, &self.storage_transaction_cache, - &self.initialized_block, &self.recorder, ); @@ -501,20 +503,16 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { self.call_api_at( | call_runtime_at, - core_api, changes, storage_transaction_cache, - initialized_block, recorder | { #runtime_mod_path #call_api_at_call( call_runtime_at, - core_api, at, params_encoded, changes, storage_transaction_cache, - initialized_block, params.map(|p| { #runtime_mod_path #native_call_generator_ident :: <#runtime, __SR_API_BLOCK__ #(, #trait_generic_arguments )*> ( diff --git a/substrate/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs index 383cd4f635..738420615b 100644 --- a/substrate/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs @@ -94,6 +94,13 @@ fn implement_common_api_traits( Ok(pred(A::VERSION)) } + fn api_version( + &self, + _: &#crate_::BlockId<#block_type>, + ) -> std::result::Result, #crate_::ApiError> where Self: Sized { + Ok(Some(A::VERSION)) + } + fn record_proof(&mut self) { unimplemented!("`record_proof` not implemented for runtime api mocks") } diff --git a/substrate/primitives/api/src/lib.rs b/substrate/primitives/api/src/lib.rs index 97342377a7..ea023677ad 100644 --- a/substrate/primitives/api/src/lib.rs +++ b/substrate/primitives/api/src/lib.rs @@ -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 { pred: P, ) -> Result where Self: Sized; + /// Returns the version of the given api. + fn api_version( + &self, + at: &BlockId, + ) -> Result, 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 { > 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>>), -} - /// Parameters for [`CallApiAt::call_api_at`]. #[cfg(feature = "std")] -pub struct CallApiAtParams<'a, Block: BlockT, C, NC, Backend: StateBackend>> { - /// A reference to something that implements the [`Core`] api. - pub core_api: &'a C, +pub struct CallApiAtParams<'a, Block: BlockT, NC, Backend: StateBackend>> { /// The block id that determines the state that should be setup when calling the function. pub at: &'a BlockId, /// The name of the function that should be called. @@ -529,9 +533,6 @@ pub struct CallApiAtParams<'a, Block: BlockT, C, NC, Backend: StateBackend, /// The cache for storage transactions. pub storage_transaction_cache: &'a RefCell>, - /// 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 { 'a, R: Encode + Decode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, - C: Core, >( &self, - params: CallApiAtParams<'a, Block, C, NC, Self::StateBackend>, + params: CallApiAtParams<'a, Block, NC, Self::StateBackend>, ) -> Result, 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: &::Header); } diff --git a/substrate/primitives/api/test/tests/runtime_calls.rs b/substrate/primitives/api/test/tests/runtime_calls.rs index 562735834d..b60c7a09cb 100644 --- a/substrate/primitives/api/test/tests/runtime_calls.rs +++ b/substrate/primitives/api/test/tests/runtime_calls.rs @@ -15,11 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use sp_api::ProvideRuntimeApi; +use sp_api::{ProvideRuntimeApi, Core}; use substrate_test_runtime_client::{ prelude::*, 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_state_machine::{ @@ -133,26 +133,13 @@ fn initialize_block_works() { 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); + 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); } -#[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] fn record_proof_works() { let (client, longest_chain) = TestClientBuilder::new() diff --git a/substrate/primitives/consensus/aura/src/lib.rs b/substrate/primitives/consensus/aura/src/lib.rs index ef888a2ab8..a28e681fda 100644 --- a/substrate/primitives/consensus/aura/src/lib.rs +++ b/substrate/primitives/consensus/aura/src/lib.rs @@ -90,7 +90,6 @@ sp_api::decl_runtime_apis! { fn slot_duration() -> SlotDuration; // Return the current set of authorities. - #[skip_initialize_block] fn authorities() -> Vec; } } diff --git a/substrate/primitives/offchain/src/lib.rs b/substrate/primitives/offchain/src/lib.rs index ffdc2bfcc3..72ceca80cf 100644 --- a/substrate/primitives/offchain/src/lib.rs +++ b/substrate/primitives/offchain/src/lib.rs @@ -28,12 +28,10 @@ sp_api::decl_runtime_apis! { #[api_version(2)] pub trait OffchainWorkerApi { /// Starts the off-chain task for given block number. - #[skip_initialize_block] #[changed_in(2)] fn offchain_worker(number: sp_runtime::traits::NumberFor); /// Starts the off-chain task for given block header. - #[skip_initialize_block] fn offchain_worker(header: &Block::Header); } } diff --git a/substrate/primitives/transaction-pool/src/runtime_api.rs b/substrate/primitives/transaction-pool/src/runtime_api.rs index e1c3280ca2..42542d9f3c 100644 --- a/substrate/primitives/transaction-pool/src/runtime_api.rs +++ b/substrate/primitives/transaction-pool/src/runtime_api.rs @@ -22,22 +22,32 @@ use sp_runtime::traits::Block as BlockT; sp_api::decl_runtime_apis! { /// The `TaggedTransactionQueue` api trait for interfering with the transaction queue. - #[api_version(2)] + #[api_version(3)] pub trait TaggedTransactionQueue { /// Validate the transaction. #[changed_in(2)] fn validate_transaction(tx: ::Extrinsic) -> TransactionValidity; + /// Validate the transaction. + #[changed_in(3)] + fn validate_transaction( + source: TransactionSource, + tx: ::Extrinsic, + ) -> TransactionValidity; + /// Validate the 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 - /// 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 /// might be verified in any possible order. fn validate_transaction( source: TransactionSource, tx: ::Extrinsic, + block_hash: Block::Hash, ) -> TransactionValidity; } } diff --git a/substrate/primitives/version/src/lib.rs b/substrate/primitives/version/src/lib.rs index 8940e85f68..15b4a12892 100644 --- a/substrate/primitives/version/src/lib.rs +++ b/substrate/primitives/version/src/lib.rs @@ -198,6 +198,11 @@ impl RuntimeVersion { ) -> bool { 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 { + self.apis.iter().find_map(|a| (a.0 == *id).then(|| a.1)) + } } #[cfg(feature = "std")] diff --git a/substrate/test-utils/runtime/src/lib.rs b/substrate/test-utils/runtime/src/lib.rs index 7ee1072a7b..084f1338cd 100644 --- a/substrate/test-utils/runtime/src/lib.rs +++ b/substrate/test-utils/runtime/src/lib.rs @@ -343,9 +343,6 @@ cfg_if! { fn get_block_number() -> u64; /// Takes and returns the initialized block number. fn take_block_number() -> Option; - /// Returns if no block was initialized. - #[skip_initialize_block] - fn without_initialize_block() -> bool; /// Test that `ed25519` crypto works in the runtime. /// /// Returns the signature generated for the message `ed25519` and the public key. @@ -396,9 +393,6 @@ cfg_if! { fn get_block_number() -> u64; /// Takes and returns the initialized block number. fn take_block_number() -> Option; - /// Returns if no block was initialized. - #[skip_initialize_block] - fn without_initialize_block() -> bool; /// Test that `ed25519` crypto works in the runtime. /// /// Returns the signature generated for the message `ed25519` and the public key. @@ -635,6 +629,7 @@ cfg_if! { fn validate_transaction( _source: TransactionSource, utx: ::Extrinsic, + _: ::Hash, ) -> TransactionValidity { if let Extrinsic::IncludeData(data) = utx { return Ok(ValidTransaction { @@ -720,10 +715,6 @@ cfg_if! { 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 { system::take_block_number() } @@ -888,6 +879,7 @@ cfg_if! { fn validate_transaction( _source: TransactionSource, utx: ::Extrinsic, + _: ::Hash, ) -> TransactionValidity { if let Extrinsic::IncludeData(data) = utx { return Ok(ValidTransaction{ @@ -977,10 +969,6 @@ cfg_if! { 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 { system::take_block_number() } diff --git a/substrate/test-utils/runtime/src/system.rs b/substrate/test-utils/runtime/src/system.rs index 33ef7b12d8..ae35ded83b 100644 --- a/substrate/test-utils/runtime/src/system.rs +++ b/substrate/test-utils/runtime/src/system.rs @@ -193,7 +193,8 @@ pub fn validate_transaction(utx: Extrinsic) -> TransactionValidity { /// Execute a transaction outside of the block execution function. /// This doesn't attempt to validate anything regarding the block. 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); ExtrinsicData::insert(extrinsic_index, utx.encode()); storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &(extrinsic_index + 1));