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

* Do not call `initialize_block` before any runtime api

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

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

* Change `validate_transaction` interface

* Fix rpc test

* Fixes and comments

* Some docs
This commit is contained in:
Bastian Köcher
2021-07-01 17:50:42 +02:00
committed by GitHub
parent 73a6e3effc
commit d489bd70b5
23 changed files with 192 additions and 301 deletions
@@ -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<Block> for DummyCallExecutor {
}
fn contextual_call<
'a,
IB: Fn() -> ClientResult<()>,
EM: Fn(
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,
>(
&self,
_initialize_block_fn: IB,
_at: &BlockId<Block>,
_method: &str,
_call_data: &[u8],
@@ -230,7 +226,6 @@ impl CallExecutor<Block> for DummyCallExecutor {
<Self::Backend as sc_client_api::backend::Backend<Block>>::State,
>
>>,
_initialize_block: InitializeBlock<'a, Block>,
_execution_manager: ExecutionManager<EM>,
_native_call: Option<NC>,
_proof_recorder: &Option<ProofRecorder<Block>>,
@@ -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| <Header as HeaderT>::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]