Don't include :code by default in storage proofs (#5060)

* Adds test to verify that the runtime currently is always contained in
the proof

* Start passing the runtime wasm code from the outside

* Fix compilation

* More build fixes

* Make the test work as expected now :)

* Last fixes

* Fixes benchmarks

* Review feedback

* Apply suggestions from code review

Co-Authored-By: Sergei Pepyakin <sergei@parity.io>

* Review feedback

* Fix compilation

Co-authored-by: Sergei Pepyakin <s.pepyakin@gmail.com>
This commit is contained in:
Benjamin Kampmann
2020-03-04 20:26:16 +01:00
committed by GitHub
parent 67837c6233
commit 6ee39261c8
31 changed files with 480 additions and 183 deletions
@@ -231,7 +231,8 @@ impl<A, B, Block, C> ProposerInner<B, Block, C, A>
debug!("[{:?}] Pushed to the block.", pending_tx_hash);
}
Err(sp_blockchain::Error::ApplyExtrinsicFailed(sp_blockchain::ApplyExtrinsicFailed::Validity(e)))
if e.exhausted_resources() => {
if e.exhausted_resources() =>
{
if is_first {
debug!("[{:?}] Invalid transaction: FullBlock on empty block", pending_tx_hash);
unqueue_invalid.push(pending_tx_hash);
@@ -19,3 +19,7 @@ sp-core = { version = "2.0.0-alpha.2", path = "../../primitives/core" }
sp-block-builder = { version = "2.0.0-alpha.2", path = "../../primitives/block-builder" }
sc-client-api = { version = "2.0.0-alpha.2", path = "../api" }
codec = { package = "parity-scale-codec", version = "1.2.0", features = ["derive"] }
[dev-dependencies]
substrate-test-runtime-client = { path = "../../test-utils/runtime/client" }
sp-trie = { version = "2.0.0-alpha.2", path = "../../primitives/trie" }
+50 -4
View File
@@ -152,12 +152,20 @@ where
/// Push onto the block's list of extrinsics.
///
/// This will treat incoming extrinsic `xt` as trusted and skip signature check (for signed transactions).
pub fn push_trusted(&mut self, xt: <Block as BlockT>::Extrinsic) -> Result<(), ApiErrorFor<A, Block>> {
/// This will treat incoming extrinsic `xt` as trusted and skip signature check
/// (for signed transactions).
pub fn push_trusted(
&mut self,
xt: <Block as BlockT>::Extrinsic,
) -> Result<(), ApiErrorFor<A, Block>> {
self.push_internal(xt, true)
}
fn push_internal(&mut self, xt: <Block as BlockT>::Extrinsic, skip_signature: bool) -> Result<(), ApiErrorFor<A, Block>> {
fn push_internal(
&mut self,
xt: <Block as BlockT>::Extrinsic,
skip_signature: bool,
) -> Result<(), ApiErrorFor<A, Block>> {
let block_id = &self.block_id;
let extrinsics = &mut self.extrinsics;
@@ -175,7 +183,7 @@ where
ExecutionContext::BlockConstruction,
xt.clone(),
)?
} else {
} else {
api.apply_extrinsic_with_context(
block_id,
ExecutionContext::BlockConstruction,
@@ -241,3 +249,41 @@ where
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use sp_blockchain::HeaderBackend;
use sp_core::Blake2Hasher;
use sp_state_machine::Backend;
use substrate_test_runtime_client::{DefaultTestClientBuilderExt, TestClientBuilderExt};
#[test]
fn block_building_storage_proof_does_not_include_runtime_by_default() {
let builder = substrate_test_runtime_client::TestClientBuilder::new();
let backend = builder.backend();
let client = builder.build();
let block = BlockBuilder::new(
&client,
client.info().best_hash,
client.info().best_number,
RecordProof::Yes,
Default::default(),
&*backend,
).unwrap().build().unwrap();
let proof = block.proof.expect("Proof is build on request");
let backend = sp_state_machine::create_proof_check_backend::<Blake2Hasher>(
block.storage_changes.transaction_storage_root,
proof,
).unwrap();
assert!(
backend.storage(&sp_core::storage::well_known_keys::CODE)
.unwrap_err()
.contains("Database missing expected key"),
);
}
}
+6 -2
View File
@@ -110,8 +110,12 @@ pub trait RuntimeInfo {
/// Native runtime information.
fn native_version(&self) -> &NativeVersion;
/// Extract RuntimeVersion of given :code block
fn runtime_version<E: Externalities> (&self, ext: &mut E) -> error::Result<RuntimeVersion>;
/// Extract [`RuntimeVersion`](sp_version::RuntimeVersion) of the given `runtime_code`.
fn runtime_version<E: Externalities>(
&self,
ext: &mut E,
runtime_code: &sp_core::traits::RuntimeCode,
) -> error::Result<RuntimeVersion>;
}
#[cfg(test)]
@@ -20,7 +20,7 @@ use crate::{
};
use sp_version::{NativeVersion, RuntimeVersion};
use codec::{Decode, Encode};
use sp_core::{NativeOrEncoded, traits::{CodeExecutor, Externalities}};
use sp_core::{NativeOrEncoded, traits::{CodeExecutor, Externalities, RuntimeCode}};
use log::trace;
use std::{result, cell::RefCell, panic::{UnwindSafe, AssertUnwindSafe}, sync::Arc};
use sp_wasm_interface::{HostFunctions, Function};
@@ -130,6 +130,7 @@ impl<D: NativeExecutionDispatch> NativeExecutor<D> {
fn with_runtime<E, R>(
&self,
ext: &mut E,
runtime_code: &RuntimeCode,
f: impl for<'a> FnOnce(
AssertUnwindSafe<&'a mut (dyn WasmRuntime + 'static)>,
&'a RuntimeVersion,
@@ -138,8 +139,9 @@ impl<D: NativeExecutionDispatch> NativeExecutor<D> {
) -> Result<R> where E: Externalities {
RUNTIMES_CACHE.with(|cache| {
let mut cache = cache.borrow_mut();
let (runtime, version, code_hash) = cache.fetch_runtime(
let (runtime, version) = cache.fetch_runtime(
ext,
runtime_code,
self.fallback_method,
self.default_heap_pages,
&*self.host_functions,
@@ -151,7 +153,7 @@ impl<D: NativeExecutionDispatch> NativeExecutor<D> {
match f(runtime, version, ext) {
Ok(res) => res,
Err(e) => {
cache.invalidate_runtime(self.fallback_method, code_hash);
cache.invalidate_runtime(self.fallback_method, runtime_code.hash.clone());
Err(e)
}
}
@@ -179,8 +181,9 @@ impl<D: NativeExecutionDispatch> RuntimeInfo for NativeExecutor<D> {
fn runtime_version<E: Externalities>(
&self,
ext: &mut E,
runtime_code: &RuntimeCode,
) -> Result<RuntimeVersion> {
self.with_runtime(ext, |_runtime, version, _ext| Ok(Ok(version.clone())))
self.with_runtime(ext, runtime_code, |_runtime, version, _ext| Ok(Ok(version.clone())))
}
}
@@ -195,13 +198,14 @@ impl<D: NativeExecutionDispatch + 'static> CodeExecutor for NativeExecutor<D> {
>(
&self,
ext: &mut E,
runtime_code: &RuntimeCode,
method: &str,
data: &[u8],
use_native: bool,
native_call: Option<NC>,
) -> (Result<NativeOrEncoded<R>>, bool){
) -> (Result<NativeOrEncoded<R>>, bool) {
let mut used_native = false;
let result = self.with_runtime(ext, |mut runtime, onchain_version, mut ext| {
let result = self.with_runtime(ext, runtime_code, |mut runtime, onchain_version, mut ext| {
match (
use_native,
onchain_version.can_call_with(&self.native_version.runtime_version),
+21 -20
View File
@@ -22,7 +22,7 @@
use crate::error::{Error, WasmError};
use log::{trace, warn};
use codec::Decode;
use sp_core::{storage::well_known_keys, traits::Externalities};
use sp_core::traits::{Externalities, RuntimeCode};
use sp_version::RuntimeVersion;
use std::{collections::hash_map::{Entry, HashMap}, panic::AssertUnwindSafe};
use sc_executor_common::wasm_runtime::WasmRuntime;
@@ -86,8 +86,9 @@ impl RuntimesCache {
///
/// # Parameters
///
/// `ext` - Externalities to use for the runtime. This is used for setting
/// up an initial runtime instance.
/// `ext` - Externalities to use for the getting the runtime's version call.
///
/// `runtime_code` - The runtime wasm code used setup the runtime.
///
/// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution.
///
@@ -95,8 +96,8 @@ impl RuntimesCache {
///
/// # Return value
///
/// If no error occurred a tuple `(&mut WasmRuntime, H256)` is
/// returned. `H256` is the hash of the runtime code.
/// If no error occurred a tuple `(&mut WasmRuntime, RuntimeVerion)` is
/// returned.
///
/// In case of failure one of two errors can be returned:
///
@@ -107,20 +108,14 @@ impl RuntimesCache {
pub fn fetch_runtime<E: Externalities>(
&mut self,
ext: &mut E,
runtime_code: &RuntimeCode,
wasm_method: WasmExecutionMethod,
default_heap_pages: u64,
host_functions: &[&'static dyn Function],
) -> Result<(&mut (dyn WasmRuntime + 'static), &RuntimeVersion, Vec<u8>), Error> {
let code_hash = ext
.original_storage_hash(well_known_keys::CODE)
.ok_or(Error::InvalidCode("`CODE` not found in storage.".into()))?;
) -> Result<(&mut (dyn WasmRuntime + 'static), &RuntimeVersion), Error> {
let heap_pages = runtime_code.heap_pages.unwrap_or(default_heap_pages);
let heap_pages = ext
.storage(well_known_keys::HEAP_PAGES)
.and_then(|pages| u64::decode(&mut &pages[..]).ok())
.unwrap_or(default_heap_pages);
let result = match self.instances.entry((wasm_method, code_hash.clone())) {
let result = match self.instances.entry((wasm_method, runtime_code.hash.clone())) {
Entry::Occupied(o) => {
let result = o.into_mut();
if let Ok(ref mut cached_runtime) = result {
@@ -142,6 +137,7 @@ impl RuntimesCache {
*result = create_versioned_wasm_runtime(
ext,
wasm_method,
runtime_code,
heap_pages,
host_functions.into(),
);
@@ -157,6 +153,7 @@ impl RuntimesCache {
let result = create_versioned_wasm_runtime(
ext,
wasm_method,
runtime_code,
heap_pages,
host_functions.into(),
);
@@ -168,7 +165,7 @@ impl RuntimesCache {
};
result.as_mut()
.map(|entry| (entry.runtime.as_mut(), &entry.version, code_hash))
.map(|entry| (entry.runtime.as_mut(), &entry.version))
.map_err(|ref e| Error::InvalidCode(format!("{:?}", e)))
}
@@ -209,13 +206,17 @@ pub fn create_wasm_runtime_with_code(
fn create_versioned_wasm_runtime<E: Externalities>(
ext: &mut E,
wasm_method: WasmExecutionMethod,
runtime_code: &RuntimeCode,
heap_pages: u64,
host_functions: Vec<&'static dyn Function>,
) -> Result<VersionedRuntime, WasmError> {
let code = ext
.original_storage(well_known_keys::CODE)
.ok_or(WasmError::CodeNotFound)?;
let mut runtime = create_wasm_runtime_with_code(wasm_method, heap_pages, &code, host_functions, false)?;
let mut runtime = create_wasm_runtime_with_code(
wasm_method,
heap_pages,
&runtime_code.code,
host_functions,
false,
)?;
// Call to determine runtime version.
let version_result = {
+15 -7
View File
@@ -62,7 +62,12 @@ pub trait Client<Block: BlockT>: Send + Sync {
) -> Result<StorageProof, Error>;
/// Get method execution proof.
fn execution_proof(&self, block: &Block::Hash, method: &str, data: &[u8]) -> Result<(Vec<u8>, StorageProof), Error>;
fn execution_proof(
&self,
block: &Block::Hash,
method: &str,
data: &[u8],
) -> Result<(Vec<u8>, StorageProof), Error>;
/// Get key changes proof.
fn key_changes_proof(
@@ -152,11 +157,7 @@ impl<B, E, Block, RA> Client<Block> for SubstrateClient<B, E, Block, RA> where
method: &str,
data: &[u8],
) -> Result<(Vec<u8>, StorageProof), Error> {
(self as &SubstrateClient<B, E, Block, RA>).execution_proof(
&BlockId::Hash(block.clone()),
method,
data,
)
SubstrateClient::execution_proof(self, &BlockId::Hash(block.clone()), method, data)
}
fn key_changes_proof(
@@ -168,7 +169,14 @@ impl<B, E, Block, RA> Client<Block> for SubstrateClient<B, E, Block, RA> where
storage_key: Option<&StorageKey>,
key: &StorageKey,
) -> Result<ChangesProof<Block::Header>, Error> {
(self as &SubstrateClient<B, E, Block, RA>).key_changes_proof(first, last, min, max, storage_key, key)
(self as &SubstrateClient<B, E, Block, RA>).key_changes_proof(
first,
last,
min,
max,
storage_key,
key,
)
}
fn is_descendent_of(&self, base: &Block::Hash, block: &Block::Hash) -> Result<bool, Error> {
@@ -254,13 +254,12 @@ where
B: Block,
{
/// Construct a new light client handler.
pub fn new
( cfg: Config
, chain: Arc<dyn Client<B>>
, checker: Arc<dyn fetcher::FetchChecker<B>>
, peerset: sc_peerset::PeersetHandle
) -> Self
{
pub fn new(
cfg: Config,
chain: Arc<dyn Client<B>>,
checker: Arc<dyn fetcher::FetchChecker<B>>,
peerset: sc_peerset::PeersetHandle,
) -> Self {
LightClientHandler {
config: cfg,
chain,
@@ -425,7 +424,8 @@ where
log::trace!("remote call request from {} ({} at {:?})",
peer,
request.method,
request.block);
request.block,
);
let block = Decode::decode(&mut request.block.as_ref())?;
@@ -436,7 +436,8 @@ where
peer,
request.method,
request.block,
e);
e,
);
StorageProof::empty()
}
};
@@ -750,7 +750,11 @@ pub mod tests {
}
}
fn check_execution_proof(&self, _: &RemoteCallRequest<B::Header>, _: StorageProof) -> ClientResult<Vec<u8>> {
fn check_execution_proof(
&self,
_: &RemoteCallRequest<B::Header>,
_: StorageProof,
) -> ClientResult<Vec<u8>> {
match self.ok {
true => Ok(vec![42]),
false => Err(ClientError::Backend("Test error".into())),
+9 -2
View File
@@ -25,7 +25,7 @@ use sp_state_machine::{
};
use sc_executor::{RuntimeVersion, RuntimeInfo, NativeVersion};
use sp_externalities::Extensions;
use sp_core::{NativeOrEncoded, NeverNativeValue, traits::CodeExecutor};
use sp_core::{NativeOrEncoded, NeverNativeValue, traits::{CodeExecutor, RuntimeCode}};
use sp_api::{ProofRecorder, InitializeBlock, StorageTransactionCache};
use sc_client_api::{backend, call_executor::CallExecutor};
@@ -90,6 +90,7 @@ where
method,
call_data,
extensions.unwrap_or_default(),
&sp_state_machine::backend::get_runtime_code(&state)?,
).execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
strategy.get_manager(),
None,
@@ -140,6 +141,8 @@ where
// make sure to destroy state before exiting this function
let mut state = self.backend.state_at(*at)?;
let runtime_code = sp_state_machine::backend::get_runtime_code(&state)?;
let result = match recorder {
Some(recorder) => state.as_trie_backend()
.ok_or_else(||
@@ -160,6 +163,7 @@ where
method,
call_data,
extensions.unwrap_or_default(),
&runtime_code,
)
// TODO: https://github.com/paritytech/substrate/issues/4455
// .with_storage_transaction_cache(storage_transaction_cache.as_mut().map(|c| &mut **c))
@@ -173,6 +177,7 @@ where
method,
call_data,
extensions.unwrap_or_default(),
&runtime_code,
)
.with_storage_transaction_cache(storage_transaction_cache.as_mut().map(|c| &mut **c))
.execute_using_consensus_failure_handler(execution_manager, native_call)
@@ -197,7 +202,8 @@ where
changes_trie_state,
None,
);
let version = self.executor.runtime_version(&mut ext);
let wasm_code = RuntimeCode::from_externalities(&ext).map_err(|e| e.to_string().into());
let version = wasm_code.and_then(|c| self.executor.runtime_version(&mut ext, &c));
{
let _lock = self.backend.get_import_lock().read();
self.backend.destroy_state(state)?;
@@ -218,6 +224,7 @@ where
&self.executor,
method,
call_data,
&sp_state_machine::backend::get_runtime_code(trie_state)?,
)
.map_err(Into::into)
}
+13 -3
View File
@@ -41,8 +41,7 @@ use sp_runtime::{
use sp_state_machine::{
DBValue, Backend as StateBackend, ChangesTrieAnchorBlockId,
prove_read, prove_child_read, ChangesTrieRootsStorage, ChangesTrieStorage,
ChangesTrieConfigurationRange, key_changes, key_changes_proof, StorageProof,
merge_storage_proofs,
ChangesTrieConfigurationRange, key_changes, key_changes_proof,
};
use sc_executor::{RuntimeVersion, RuntimeInfo};
use sp_consensus::{
@@ -55,6 +54,7 @@ use sp_blockchain::{self as blockchain,
well_known_cache_keys::Id as CacheKeyId,
HeaderMetadata, CachedHeaderMetadata,
};
use sp_trie::StorageProof;
use sp_api::{
CallApiAt, ConstructRuntimeApi, Core as CoreApi, ApiExt, ApiRef, ProvideRuntimeApi,
@@ -482,9 +482,19 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
method: &str,
call_data: &[u8]
) -> sp_blockchain::Result<(Vec<u8>, StorageProof)> {
// Make sure we include the `:code` and `:heap_pages` in the execution proof to be
// backwards compatible.
//
// TODO: Remove when solved: https://github.com/paritytech/substrate/issues/5047
let code_proof = self.read_proof(
id,
&[well_known_keys::CODE.to_vec(), well_known_keys::HEAP_PAGES.to_vec()],
)?;
let state = self.state_at(id)?;
let header = self.prepare_environment_block(id)?;
prove_execution(state, header, &self.executor, method, call_data)
.map(|p| (p.0, StorageProof::merge(vec![p.1, code_proof])))
}
/// Reads given header and generates CHT-based header proof.
@@ -769,7 +779,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
Ok(())
}, ())?;
Ok(merge_storage_proofs(proofs))
Ok(StorageProof::merge(proofs))
}
/// Generates CHT-based proof for roots of changes tries at given blocks (that are part of single CHT).
+14
View File
@@ -89,6 +89,8 @@ mod tests {
};
let hash = header.hash();
let mut overlay = OverlayedChanges::default();
let runtime_code = sp_state_machine::backend::get_runtime_code(&backend)
.expect("Code is part of the backend");
StateMachine::new(
backend,
@@ -98,6 +100,7 @@ mod tests {
"Core_initialize_block",
&header.encode(),
Default::default(),
&runtime_code,
).execute(
ExecutionStrategy::NativeElseWasm,
).unwrap();
@@ -111,6 +114,7 @@ mod tests {
"BlockBuilder_apply_extrinsic",
&tx.encode(),
Default::default(),
&runtime_code,
).execute(
ExecutionStrategy::NativeElseWasm,
).unwrap();
@@ -124,6 +128,7 @@ mod tests {
"BlockBuilder_finalize_block",
&[],
Default::default(),
&runtime_code,
).execute(
ExecutionStrategy::NativeElseWasm,
).unwrap();
@@ -161,6 +166,8 @@ mod tests {
let backend = InMemoryBackend::from(storage);
let (b1data, _b1hash) = block1(genesis_hash, &backend);
let runtime_code = sp_state_machine::backend::get_runtime_code(&backend)
.expect("Code is part of the backend");
let mut overlay = OverlayedChanges::default();
let _ = StateMachine::new(
@@ -171,6 +178,7 @@ mod tests {
"Core_execute_block",
&b1data,
Default::default(),
&runtime_code,
).execute(
ExecutionStrategy::NativeElseWasm,
).unwrap();
@@ -189,6 +197,8 @@ mod tests {
let backend = InMemoryBackend::from(storage);
let (b1data, _b1hash) = block1(genesis_hash, &backend);
let runtime_code = sp_state_machine::backend::get_runtime_code(&backend)
.expect("Code is part of the backend");
let mut overlay = OverlayedChanges::default();
let _ = StateMachine::new(
@@ -199,6 +209,7 @@ mod tests {
"Core_execute_block",
&b1data,
Default::default(),
&runtime_code,
).execute(
ExecutionStrategy::AlwaysWasm,
).unwrap();
@@ -217,6 +228,8 @@ mod tests {
let backend = InMemoryBackend::from(storage);
let (b1data, _b1hash) = block1(genesis_hash, &backend);
let runtime_code = sp_state_machine::backend::get_runtime_code(&backend)
.expect("Code is part of the backend");
let mut overlay = OverlayedChanges::default();
let r = StateMachine::new(
@@ -227,6 +240,7 @@ mod tests {
"Core_execute_block",
&b1data,
Default::default(),
&runtime_code,
).execute(
ExecutionStrategy::NativeElseWasm,
);
+2 -2
View File
@@ -172,9 +172,9 @@ impl<S, Block> ClientBackend<Block> for Backend<S, HasherFor<Block>>
match maybe_val {
Some(val) => self.blockchain.storage().insert_aux(
&[(&key[..], &val[..])],
::std::iter::empty(),
std::iter::empty(),
)?,
None => self.blockchain.storage().insert_aux(::std::iter::empty(), &[&key[..]])?,
None => self.blockchain.storage().insert_aux(std::iter::empty(), &[&key[..]])?,
}
}
}
+9 -3
View File
@@ -29,7 +29,6 @@ use sp_externalities::Extensions;
use sp_state_machine::{
self, Backend as StateBackend, OverlayedChanges, ExecutionStrategy, create_proof_check_backend,
execution_proof_check_on_trie_backend, ExecutionManager, StorageProof,
merge_storage_proofs,
};
use hash_db::Hasher;
@@ -206,7 +205,7 @@ pub fn prove_execution<Block, S, E>(
method,
call_data,
)?;
let total_proof = merge_storage_proofs(vec![init_proof, exec_proof]);
let total_proof = StorageProof::merge(vec![init_proof, exec_proof]);
Ok((result, total_proof))
}
@@ -259,12 +258,17 @@ fn check_execution_proof_with_make_header<Header, E, H, MakeNextHeader: Fn(&Head
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 runtime_code = sp_state_machine::backend::get_runtime_code(&trie_backend)?;
execution_proof_check_on_trie_backend::<H, Header::Number, _>(
&trie_backend,
&mut changes,
executor,
"Core_initialize_block",
&next_header.encode(),
&runtime_code,
)?;
// execute method
@@ -274,7 +278,9 @@ fn check_execution_proof_with_make_header<Header, E, H, MakeNextHeader: Fn(&Head
executor,
&request.method,
&request.call_data,
).map_err(Into::into)
&runtime_code,
)
.map_err(Into::into)
}
#[cfg(test)]
+6 -5
View File
@@ -30,7 +30,7 @@ use sp_runtime::traits::{
use sp_state_machine::{
ChangesTrieRootsStorage, ChangesTrieAnchorBlockId, ChangesTrieConfigurationRange,
InMemoryChangesTrieStorage, TrieBackend, read_proof_check, key_changes_proof_check_with_db,
create_proof_check_backend_storage, read_child_proof_check,
read_child_proof_check,
};
pub use sp_state_machine::StorageProof;
use sp_blockchain::{Error as ClientError, Result as ClientResult};
@@ -155,7 +155,7 @@ impl<E, H, B: BlockT, S: BlockchainStorage<B>> LightDataChecker<E, H, B, S> {
H::Out: Ord + codec::Codec,
{
// all the checks are sharing the same storage
let storage = create_proof_check_backend_storage(remote_roots_proof);
let storage = remote_roots_proof.into_memory_db();
// remote_roots.keys() are sorted => we can use this to group changes tries roots
// that are belongs to the same CHT
@@ -187,7 +187,8 @@ impl<E, H, B: BlockT, S: BlockchainStorage<B>> LightDataChecker<E, H, B, S> {
local_cht_root,
block,
remote_changes_trie_root,
&proving_backend)?;
&proving_backend,
)?;
// and return the storage to use in following checks
storage = proving_backend.into_storage();
@@ -270,7 +271,7 @@ impl<E, Block, H, S> FetchChecker<Block> for LightDataChecker<E, H, Block, S>
body: Vec<Block::Extrinsic>
) -> ClientResult<Vec<Block::Extrinsic>> {
// TODO: #2621
let extrinsics_root = HashFor::<Block>::ordered_trie_root(
let extrinsics_root = HashFor::<Block>::ordered_trie_root(
body.iter().map(Encode::encode).collect(),
);
if *request.header.extrinsics_root() == extrinsics_root {
@@ -294,7 +295,7 @@ struct RootsStorage<'a, Number: AtLeast32Bit, Hash: 'a> {
impl<'a, H, Number, Hash> ChangesTrieRootsStorage<H, Number> for RootsStorage<'a, Number, Hash>
where
H: Hasher,
Number: ::std::fmt::Display + ::std::hash::Hash + Clone + AtLeast32Bit + Encode + Decode + Send + Sync + 'static,
Number: std::fmt::Display + std::hash::Hash + Clone + AtLeast32Bit + Encode + Decode + Send + Sync + 'static,
Hash: 'a + Send + Sync + Clone + AsRef<[u8]>,
{
fn build_anchor(