From 5a623ad2e61e62ff35e61aa691459a37e98d0415 Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Wed, 16 Oct 2019 15:12:24 +0200 Subject: [PATCH] Create opaque struct for StorageProof. Passing around Vec> everywhere is gross and confusing and breaks encapsulation. --- Cargo.lock | 1 + core/authority-discovery/src/lib.rs | 4 +- .../client/src/block_builder/block_builder.rs | 3 +- core/client/src/call_executor.rs | 8 +- core/client/src/cht.rs | 6 +- core/client/src/client.rs | 22 ++-- core/client/src/lib.rs | 2 +- core/client/src/light/call_executor.rs | 24 ++--- core/client/src/light/fetcher.rs | 36 ++++--- core/client/src/runtime_api.rs | 4 +- core/finality-grandpa/Cargo.toml | 1 + core/finality-grandpa/src/finality_proof.rs | 32 +++--- core/finality-grandpa/src/tests.rs | 32 ++++-- core/network/src/chain.rs | 21 ++-- core/network/src/protocol.rs | 12 +-- core/network/src/protocol/light_dispatch.rs | 34 +++--- core/network/src/protocol/message.rs | 11 +- core/sr-api-macros/src/impl_runtime_apis.rs | 12 ++- core/state-machine/src/lib.rs | 22 ++-- core/state-machine/src/proving_backend.rs | 100 ++++++++++++++++-- 20 files changed, 246 insertions(+), 141 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 861222cc989d7..6a28b4f4f6821 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5263,6 +5263,7 @@ dependencies = [ "substrate-keystore 2.0.0", "substrate-network 2.0.0", "substrate-primitives 2.0.0", + "substrate-state-machine 2.0.0", "substrate-telemetry 2.0.0", "substrate-test-runtime-client 2.0.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/core/authority-discovery/src/lib.rs b/core/authority-discovery/src/lib.rs index 987169ead90b1..8e2663d210a83 100644 --- a/core/authority-discovery/src/lib.rs +++ b/core/authority-discovery/src/lib.rs @@ -44,7 +44,7 @@ //! 4. Adds the retrieved external addresses as priority nodes to the peerset. use authority_discovery_primitives::{AuthorityDiscoveryApi, AuthorityId, Signature}; -use client::blockchain::HeaderBackend; +use client::{blockchain::HeaderBackend, runtime_api::StorageProof}; use error::{Error, Result}; use futures::{prelude::*, sync::mpsc::Receiver}; use log::{debug, error, log_enabled, warn}; @@ -528,7 +528,7 @@ mod tests { unimplemented!("Not required for testing!") } - fn extract_proof(&mut self) -> Option>> { + fn extract_proof(&mut self) -> Option { unimplemented!("Not required for testing!") } } diff --git a/core/client/src/block_builder/block_builder.rs b/core/client/src/block_builder/block_builder.rs index 08711469e9a1b..f5cd6a9f660b0 100644 --- a/core/client/src/block_builder/block_builder.rs +++ b/core/client/src/block_builder/block_builder.rs @@ -22,6 +22,7 @@ use sr_primitives::traits::{ Header as HeaderT, Hash, Block as BlockT, One, HashFor, ProvideRuntimeApi, ApiRef, DigestFor, }; use primitives::{H256, ExecutionContext}; +use state_machine::StorageProof; use crate::blockchain::HeaderBackend; use crate::runtime_api::{Core, ApiExt}; use crate::error; @@ -140,7 +141,7 @@ where /// /// The proof will be `Some(_)`, if proof recording was enabled while creating /// the block builder. - pub fn bake_and_extract_proof(mut self) -> error::Result<(Block, Option>>)> { + pub fn bake_and_extract_proof(mut self) -> error::Result<(Block, Option)> { self.bake_impl()?; let proof = self.api.extract_proof(); diff --git a/core/client/src/call_executor.rs b/core/client/src/call_executor.rs index 05a2a8eba1c3e..e634fcf8faa9f 100644 --- a/core/client/src/call_executor.rs +++ b/core/client/src/call_executor.rs @@ -21,7 +21,7 @@ use sr_primitives::{ }; use state_machine::{ self, OverlayedChanges, Ext, ExecutionManager, StateMachine, ExecutionStrategy, - backend::Backend as _, ChangesTrieTransaction, + backend::Backend as _, ChangesTrieTransaction, StorageProof, }; use executor::{RuntimeVersion, RuntimeInfo, NativeVersion}; use hash_db::Hasher; @@ -127,7 +127,7 @@ where overlay: &mut OverlayedChanges, method: &str, call_data: &[u8] - ) -> Result<(Vec, Vec>), error::Error> { + ) -> Result<(Vec, StorageProof), error::Error> { let trie_state = state.as_trie_backend() .ok_or_else(|| Box::new(state_machine::ExecutionError::UnableToGenerateProof) @@ -145,7 +145,7 @@ where overlay: &mut OverlayedChanges, method: &str, call_data: &[u8] - ) -> Result<(Vec, Vec>), error::Error>; + ) -> Result<(Vec, StorageProof), error::Error>; /// Get runtime version if supported. fn native_runtime_version(&self) -> Option<&NativeVersion>; @@ -377,7 +377,7 @@ where overlay: &mut OverlayedChanges, method: &str, call_data: &[u8] - ) -> Result<(Vec, Vec>), error::Error> { + ) -> Result<(Vec, StorageProof), error::Error> { state_machine::prove_execution_on_trie_backend( trie_state, overlay, diff --git a/core/client/src/cht.rs b/core/client/src/cht.rs index 63a5b39c26904..aff875032d357 100644 --- a/core/client/src/cht.rs +++ b/core/client/src/cht.rs @@ -30,7 +30,7 @@ use trie; use primitives::{H256, convert_hash}; use sr_primitives::traits::{Header as HeaderT, SimpleArithmetic, Zero, One}; use state_machine::backend::InMemory as InMemoryState; -use state_machine::{MemoryDB, TrieBackend, Backend as StateBackend, +use state_machine::{MemoryDB, TrieBackend, Backend as StateBackend, StorageProof, prove_read_on_trie_backend, read_proof_check, read_proof_check_on_proving_backend}; use crate::error::{Error as ClientError, Result as ClientResult}; @@ -88,7 +88,7 @@ pub fn build_proof( cht_num: Header::Number, blocks: BlocksI, hashes: HashesI -) -> ClientResult>> +) -> ClientResult where Header: HeaderT, Hasher: hash_db::Hasher, @@ -114,7 +114,7 @@ pub fn check_proof( local_root: Header::Hash, local_number: Header::Number, remote_hash: Header::Hash, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult<()> where Header: HeaderT, diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 25c2fab48de23..1fa0c7d6ca560 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -43,7 +43,7 @@ use state_machine::{ DBValue, Backend as StateBackend, ChangesTrieAnchorBlockId, ExecutionStrategy, ExecutionManager, prove_read, prove_child_read, ChangesTrieRootsStorage, ChangesTrieStorage, ChangesTrieTransaction, ChangesTrieConfigurationRange, key_changes, key_changes_proof, - OverlayedChanges, BackendTrustLevel, + OverlayedChanges, BackendTrustLevel, StorageProof, merge_storage_proofs, }; use executor::{RuntimeVersion, RuntimeInfo}; use consensus::{ @@ -421,7 +421,7 @@ impl Client where } /// Reads storage value at a given block + key, returning read proof. - pub fn read_proof(&self, id: &BlockId, keys: I) -> error::Result>> where + pub fn read_proof(&self, id: &BlockId, keys: I) -> error::Result where I: IntoIterator, I::Item: AsRef<[u8]>, { @@ -437,7 +437,7 @@ impl Client where id: &BlockId, storage_key: &[u8], keys: I, - ) -> error::Result>> where + ) -> error::Result where I: IntoIterator, I::Item: AsRef<[u8]>, { @@ -454,14 +454,14 @@ impl Client where id: &BlockId, method: &str, call_data: &[u8] - ) -> error::Result<(Vec, Vec>)> { + ) -> error::Result<(Vec, StorageProof)> { let state = self.state_at(id)?; let header = self.prepare_environment_block(id)?; prove_execution(state, header, &self.executor, method, call_data) } /// Reads given header and generates CHT-based header proof. - pub fn header_proof(&self, id: &BlockId) -> error::Result<(Block::Header, Vec>)> { + pub fn header_proof(&self, id: &BlockId) -> error::Result<(Block::Header, StorageProof)> { self.header_proof_with_cht_size(id, cht::size()) } @@ -477,7 +477,7 @@ impl Client where &self, id: &BlockId, cht_size: NumberFor, - ) -> error::Result<(Block::Header, Vec>)> { + ) -> error::Result<(Block::Header, StorageProof)> { let proof_error = || error::Error::Backend(format!("Failed to generate header proof for {:?}", id)); let header = self.backend.blockchain().expect_header(*id)?; let block_num = *header.number(); @@ -696,18 +696,18 @@ impl Client where &self, cht_size: NumberFor, blocks: I - ) -> error::Result>> { + ) -> error::Result { // most probably we have touched several changes tries that are parts of the single CHT // => GroupBy changes tries by CHT number and then gather proof for the whole group at once - let mut proof = HashSet::new(); + let mut proofs = Vec::new(); cht::for_each_cht_group::(cht_size, blocks, |_, cht_num, cht_blocks| { let cht_proof = self.changes_trie_roots_proof_at_cht(cht_size, cht_num, cht_blocks)?; - proof.extend(cht_proof); + proofs.push(cht_proof); Ok(()) }, ())?; - Ok(proof.into_iter().collect()) + Ok(merge_storage_proofs(proofs)) } /// Generates CHT-based proof for roots of changes tries at given blocks (that are part of single CHT). @@ -716,7 +716,7 @@ impl Client where cht_size: NumberFor, cht_num: NumberFor, blocks: Vec> - ) -> error::Result>> { + ) -> error::Result { let cht_start = cht::start_number(cht_size, cht_num); let mut current_num = cht_start; let cht_range = ::std::iter::from_fn(|| { diff --git a/core/client/src/lib.rs b/core/client/src/lib.rs index 5a2cb746f3864..57147eb18b181 100644 --- a/core/client/src/lib.rs +++ b/core/client/src/lib.rs @@ -122,7 +122,7 @@ pub use crate::client::{ #[cfg(feature = "std")] pub use crate::notifications::{StorageEventStream, StorageChangeSet}; #[cfg(feature = "std")] -pub use state_machine::ExecutionStrategy; +pub use state_machine::{ExecutionStrategy, StorageProof}; #[cfg(feature = "std")] pub use crate::leaves::LeafSet; #[cfg(feature = "std")] diff --git a/core/client/src/light/call_executor.rs b/core/client/src/light/call_executor.rs index 65776bcfe08f3..7f54004ae6722 100644 --- a/core/client/src/light/call_executor.rs +++ b/core/client/src/light/call_executor.rs @@ -16,10 +16,7 @@ //! Methods that light client could use to execute runtime calls. -use std::{ - collections::HashSet, sync::Arc, panic::UnwindSafe, result, - cell::RefCell, rc::Rc, -}; +use std::{sync::Arc, panic::UnwindSafe, result, cell::RefCell, rc::Rc}; use codec::{Encode, Decode}; use primitives::{ @@ -31,7 +28,8 @@ use sr_primitives::{ }; use state_machine::{ self, Backend as StateBackend, OverlayedChanges, ExecutionStrategy, create_proof_check_backend, - execution_proof_check_on_trie_backend, ExecutionManager, ChangesTrieTransaction, + execution_proof_check_on_trie_backend, ExecutionManager, ChangesTrieTransaction, StorageProof, + merge_storage_proofs, }; use hash_db::Hasher; @@ -179,7 +177,7 @@ impl CallExecutor for _changes: &mut OverlayedChanges, _method: &str, _call_data: &[u8] - ) -> ClientResult<(Vec, Vec>)> { + ) -> ClientResult<(Vec, StorageProof)> { Err(ClientError::NotAvailableOnLightClient) } @@ -198,7 +196,7 @@ pub fn prove_execution( executor: &E, method: &str, call_data: &[u8], -) -> ClientResult<(Vec, Vec>)> +) -> ClientResult<(Vec, StorageProof)> where Block: BlockT, S: StateBackend, @@ -218,11 +216,7 @@ pub fn prove_execution( // execute method + record execution proof let (result, exec_proof) = executor.prove_at_trie_state(&trie_state, &mut changes, method, call_data)?; - let total_proof = init_proof.into_iter() - .chain(exec_proof.into_iter()) - .collect::>() - .into_iter() - .collect(); + let total_proof = merge_storage_proofs(vec![init_proof, exec_proof]); Ok((result, total_proof)) } @@ -234,7 +228,7 @@ pub fn prove_execution( pub fn check_execution_proof( executor: &E, request: &RemoteCallRequest
, - remote_proof: Vec>, + remote_proof: StorageProof, ) -> ClientResult> where Header: HeaderT, @@ -258,7 +252,7 @@ pub fn check_execution_proof( fn check_execution_proof_with_make_header Header>( executor: &E, request: &RemoteCallRequest
, - remote_proof: Vec>, + remote_proof: StorageProof, make_next_header: MakeNextHeader, ) -> ClientResult> where @@ -382,7 +376,7 @@ mod tests { _overlay: &mut OverlayedChanges, _method: &str, _call_data: &[u8] - ) -> Result<(Vec, Vec>), ClientError> { + ) -> Result<(Vec, StorageProof), ClientError> { unreachable!() } diff --git a/core/client/src/light/fetcher.rs b/core/client/src/light/fetcher.rs index dbf6d41c38f16..6ae28b748c527 100644 --- a/core/client/src/light/fetcher.rs +++ b/core/client/src/light/fetcher.rs @@ -33,6 +33,7 @@ use state_machine::{ TrieBackend, read_proof_check, key_changes_proof_check, create_proof_check_backend_storage, read_child_proof_check, }; +pub use state_machine::StorageProof; use crate::cht; use crate::error::{Error as ClientError, Result as ClientResult}; @@ -129,7 +130,7 @@ pub struct ChangesProof { pub roots: BTreeMap, /// The proofs for all changes tries roots that have been touched AND are /// missing from the requester' node. It is a map of CHT number => proof. - pub roots_proof: Vec>, + pub roots_proof: StorageProof, } /// Remote block body request @@ -186,25 +187,25 @@ pub trait FetchChecker: Send + Sync { &self, request: &RemoteHeaderRequest, header: Option, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult; /// Check remote storage read proof. fn check_read_proof( &self, request: &RemoteReadRequest, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult, Option>>>; /// Check remote storage read proof. fn check_read_child_proof( &self, request: &RemoteReadChildRequest, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult, Option>>>; /// Check remote method execution proof. fn check_execution_proof( &self, request: &RemoteCallRequest, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult>; /// Check remote changes query proof. fn check_changes_proof( @@ -318,7 +319,7 @@ impl> LightDataChecker { &self, cht_size: NumberFor, remote_roots: &BTreeMap, B::Hash>, - remote_roots_proof: Vec>, + remote_roots_proof: StorageProof, ) -> ClientResult<()> where H: Hasher, @@ -378,7 +379,7 @@ impl FetchChecker for LightDataChecker &self, request: &RemoteHeaderRequest, remote_header: Option, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult { let remote_header = remote_header.ok_or_else(|| ClientError::from(ClientError::InvalidCHTProof))?; @@ -394,7 +395,7 @@ impl FetchChecker for LightDataChecker fn check_read_proof( &self, request: &RemoteReadRequest, - remote_proof: Vec>, + remote_proof: StorageProof, ) -> ClientResult, Option>>> { read_proof_check::( convert_hash(request.header.state_root()), @@ -406,7 +407,7 @@ impl FetchChecker for LightDataChecker fn check_read_child_proof( &self, request: &RemoteReadChildRequest, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult, Option>>> { read_child_proof_check::( convert_hash(request.header.state_root()), @@ -419,7 +420,7 @@ impl FetchChecker for LightDataChecker fn check_execution_proof( &self, request: &RemoteCallRequest, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult> { check_execution_proof::<_, _, H>(&self.executor, request, remote_proof) } @@ -572,7 +573,7 @@ pub mod tests { NativeExecutor::new(WasmExecutionMethod::Interpreted, None) } - fn prepare_for_read_proof_check() -> (TestChecker, Header, Vec>, u32) { + fn prepare_for_read_proof_check() -> (TestChecker, Header, StorageProof, u32) { // prepare remote client let remote_client = test_client::new(); let remote_block_id = BlockId::Number(0); @@ -606,7 +607,7 @@ pub mod tests { (local_checker, remote_block_header, remote_read_proof, heap_pages) } - fn prepare_for_read_child_proof_check() -> (TestChecker, Header, Vec>, Vec) { + fn prepare_for_read_child_proof_check() -> (TestChecker, Header, StorageProof, Vec) { use test_client::DefaultTestClientBuilderExt; use test_client::TestClientBuilderExt; // prepare remote client @@ -648,7 +649,7 @@ pub mod tests { (local_checker, remote_block_header, remote_read_proof, child_value) } - fn prepare_for_header_proof_check(insert_cht: bool) -> (TestChecker, Hash, Header, Vec>) { + fn prepare_for_header_proof_check(insert_cht: bool) -> (TestChecker, Hash, Header, StorageProof) { // prepare remote client let remote_client = test_client::new(); let mut local_headers_hashes = Vec::new(); @@ -899,13 +900,13 @@ pub mod tests { max_block: remote_proof.max_block, proof: remote_proof.proof.clone(), roots: vec![(begin - 1, Default::default())].into_iter().collect(), - roots_proof: vec![], + roots_proof: StorageProof::empty(), }).is_err()); assert!(local_checker.check_changes_proof(&request, ChangesProof { max_block: remote_proof.max_block, proof: remote_proof.proof.clone(), roots: vec![(end + 1, Default::default())].into_iter().collect(), - roots_proof: vec![], + roots_proof: StorageProof::empty(), }).is_err()); } @@ -945,7 +946,10 @@ pub mod tests { Arc::new(DummyBlockchain::new(local_storage)), local_executor(), ); - assert!(local_checker.check_changes_tries_proof(4, &remote_proof.roots, vec![]).is_err()); + let result = local_checker.check_changes_tries_proof( + 4, &remote_proof.roots, StorageProof::empty() + ); + assert!(result.is_err()); } #[test] diff --git a/core/client/src/runtime_api.rs b/core/client/src/runtime_api.rs index 68b49e5910b45..0fa0545daef2f 100644 --- a/core/client/src/runtime_api.rs +++ b/core/client/src/runtime_api.rs @@ -18,7 +18,7 @@ #[doc(hidden)] #[cfg(feature = "std")] -pub use state_machine::OverlayedChanges; +pub use state_machine::{OverlayedChanges, StorageProof}; #[doc(hidden)] #[cfg(feature = "std")] pub use primitives::NativeOrEncoded; @@ -106,7 +106,7 @@ pub trait ApiExt { /// Extract the recorded proof. /// This stops the proof recording. - fn extract_proof(&mut self) -> Option>>; + fn extract_proof(&mut self) -> Option; } /// Before calling any runtime api function, the runtime need to be initialized diff --git a/core/finality-grandpa/Cargo.toml b/core/finality-grandpa/Cargo.toml index 84178c8a78fd5..a4c6a0278a445 100644 --- a/core/finality-grandpa/Cargo.toml +++ b/core/finality-grandpa/Cargo.toml @@ -34,6 +34,7 @@ network = { package = "substrate-network", path = "../network", features = ["tes keyring = { package = "substrate-keyring", path = "../keyring" } test-client = { package = "substrate-test-runtime-client", path = "../test-runtime/client"} babe_primitives = { package = "substrate-consensus-babe-primitives", path = "../consensus/babe/primitives" } +state_machine = { package = "substrate-state-machine", path = "../state-machine" } env_logger = "0.7.0" tokio = "0.1.22" tempfile = "3.1.0" diff --git a/core/finality-grandpa/src/finality_proof.rs b/core/finality-grandpa/src/finality_proof.rs index da5732f2f6fc8..bd22a7bbac287 100644 --- a/core/finality-grandpa/src/finality_proof.rs +++ b/core/finality-grandpa/src/finality_proof.rs @@ -40,7 +40,7 @@ use log::{trace, warn}; use client::{ backend::Backend, blockchain::Backend as BlockchainBackend, CallExecutor, Client, error::{Error as ClientError, Result as ClientResult}, - light::fetcher::{FetchChecker, RemoteCallRequest}, ExecutionStrategy, + light::fetcher::{FetchChecker, RemoteCallRequest, StorageProof}, ExecutionStrategy, }; use codec::{Encode, Decode}; use grandpa::BlockNumberOps; @@ -62,7 +62,7 @@ pub trait AuthoritySetForFinalityProver: Send + Sync { /// Call GrandpaApi::grandpa_authorities at given block. fn authorities(&self, block: &BlockId) -> ClientResult>; /// Prove call of GrandpaApi::grandpa_authorities at given block. - fn prove_authorities(&self, block: &BlockId) -> ClientResult>>; + fn prove_authorities(&self, block: &BlockId) -> ClientResult; } /// Client-based implementation of AuthoritySetForFinalityProver. @@ -85,7 +85,7 @@ impl, RA> AuthoritySetForFinalityProver fo ))) } - fn prove_authorities(&self, block: &BlockId) -> ClientResult>> { + fn prove_authorities(&self, block: &BlockId) -> ClientResult { self.execution_proof(block, "GrandpaApi_grandpa_authorities",&[]).map(|(_, proof)| proof) } } @@ -97,7 +97,7 @@ pub trait AuthoritySetForFinalityChecker: Send + Sync { &self, hash: Block::Hash, header: Block::Header, - proof: Vec>, + proof: StorageProof, ) -> ClientResult>; } @@ -107,7 +107,7 @@ impl AuthoritySetForFinalityChecker for Arc>, + proof: StorageProof, ) -> ClientResult> { let request = RemoteCallRequest { block: hash, @@ -207,7 +207,7 @@ struct FinalityProofFragment { /// The set of headers in the range (U; F] that we believe are unknown to the caller. Ordered. pub unknown_headers: Vec
, /// Optional proof of execution of GRANDPA::authorities(). - pub authorities_proof: Option>>, + pub authorities_proof: Option, } /// Proof of finality is the ordered set of finality fragments, where: @@ -582,13 +582,13 @@ pub(crate) mod tests { impl AuthoritySetForFinalityProver for (GetAuthorities, ProveAuthorities) where GetAuthorities: Send + Sync + Fn(BlockId) -> ClientResult>, - ProveAuthorities: Send + Sync + Fn(BlockId) -> ClientResult>>, + ProveAuthorities: Send + Sync + Fn(BlockId) -> ClientResult, { fn authorities(&self, block: &BlockId) -> ClientResult> { self.0(*block) } - fn prove_authorities(&self, block: &BlockId) -> ClientResult>> { + fn prove_authorities(&self, block: &BlockId) -> ClientResult { self.1(*block) } } @@ -597,13 +597,13 @@ pub(crate) mod tests { impl AuthoritySetForFinalityChecker for ClosureAuthoritySetForFinalityChecker where - Closure: Send + Sync + Fn(H256, Header, Vec>) -> ClientResult>, + Closure: Send + Sync + Fn(H256, Header, StorageProof) -> ClientResult>, { fn check_authorities_proof( &self, hash: H256, header: Header, - proof: Vec>, + proof: StorageProof, ) -> ClientResult> { self.0(hash, header, proof) } @@ -824,8 +824,8 @@ pub(crate) mod tests { _ => unreachable!("no other authorities should be fetched: {:?}", block_id), }, |block_id| match block_id { - BlockId::Number(4) => Ok(vec![vec![40]]), - BlockId::Number(6) => Ok(vec![vec![60]]), + BlockId::Number(4) => Ok(StorageProof::new(vec![vec![40]])), + BlockId::Number(6) => Ok(StorageProof::new(vec![vec![60]])), _ => unreachable!("no other authorities should be proved: {:?}", block_id), }, ), @@ -841,14 +841,14 @@ pub(crate) mod tests { block: header(5).hash(), justification: just5, unknown_headers: Vec::new(), - authorities_proof: Some(vec![vec![40]]), + authorities_proof: Some(StorageProof::new(vec![vec![40]])), }, // last fragment provides justification for #7 && unknown#7 FinalityProofFragment { block: header(7).hash(), justification: just7, unknown_headers: vec![header(7)], - authorities_proof: Some(vec![vec![60]]), + authorities_proof: Some(StorageProof::new(vec![vec![60]])), }, ]); } @@ -895,7 +895,7 @@ pub(crate) mod tests { block: header(4).hash(), justification: TestJustification(true, vec![7]).encode(), unknown_headers: vec![header(4)], - authorities_proof: Some(vec![vec![42]]), + authorities_proof: Some(StorageProof::new(vec![vec![42]])), }, FinalityProofFragment { block: header(5).hash(), justification: TestJustification(true, vec![8]).encode(), @@ -942,7 +942,7 @@ pub(crate) mod tests { block: header(2).hash(), justification: TestJustification(true, vec![7]).encode(), unknown_headers: Vec::new(), - authorities_proof: Some(vec![vec![42]]), + authorities_proof: Some(StorageProof::new(vec![vec![42]])), }, FinalityProofFragment { block: header(4).hash(), justification: TestJustification(true, vec![8]).encode(), diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index 39173741711de..2339379a609d4 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -27,7 +27,7 @@ use tokio::runtime::current_thread; use keyring::Ed25519Keyring; use client::{ error::Result, - runtime_api::{Core, RuntimeVersion, ApiExt}, + runtime_api::{Core, RuntimeVersion, ApiExt, StorageProof}, LongestChain, }; use test_client::{self, runtime::BlockNumber}; @@ -40,6 +40,7 @@ use sr_primitives::traits::{ApiRef, ProvideRuntimeApi, Header as HeaderT}; use sr_primitives::generic::{BlockId, DigestItem}; use primitives::{NativeOrEncoded, ExecutionContext, crypto::Public}; use fg_primitives::{GRANDPA_ENGINE_ID, AuthorityId}; +use state_machine::{backend::InMemory, prove_read, read_proof_check}; use authorities::AuthoritySet; use finality_proof::{FinalityProofProvider, AuthoritySetForFinalityProver, AuthoritySetForFinalityChecker}; @@ -258,7 +259,7 @@ impl ApiExt for RuntimeApi { unimplemented!("Not required for testing!") } - fn extract_proof(&mut self) -> Option>> { + fn extract_proof(&mut self) -> Option { unimplemented!("Not required for testing!") } } @@ -285,8 +286,14 @@ impl AuthoritySetForFinalityProver for TestApi { }) } - fn prove_authorities(&self, block: &BlockId) -> Result>> { - self.authorities(block).map(|auth| vec![auth.encode()]) + fn prove_authorities(&self, block: &BlockId) -> Result { + let authorities = self.authorities(block)?; + let backend = >::from(vec![ + (None, b"authorities".to_vec(), Some(authorities.encode())) + ]); + let proof = prove_read(backend, vec![b"authorities"]) + .expect("failure proving read from in-memory storage backend"); + Ok(proof) } } @@ -294,11 +301,20 @@ impl AuthoritySetForFinalityChecker for TestApi { fn check_authorities_proof( &self, _hash: ::Hash, - _header: ::Header, - proof: Vec>, + header: ::Header, + proof: StorageProof, ) -> Result> { - Decode::decode(&mut &proof[0][..]) - .map_err(|_| unreachable!("incorrect value is passed as GRANDPA authorities proof")) + let results = read_proof_check::( + *header.state_root(), proof, vec![b"authorities"] + ) + .expect("failure checking read proof for authorities"); + let encoded = results.get(&b"authorities"[..]) + .expect("returned map must contain all proof keys") + .as_ref() + .expect("authorities in proof is None"); + let authorities = Decode::decode(&mut &encoded[..]) + .expect("failure decoding authorities read from proof"); + Ok(authorities) } } diff --git a/core/network/src/chain.rs b/core/network/src/chain.rs index f68942fd96d38..2b32c07009fc7 100644 --- a/core/network/src/chain.rs +++ b/core/network/src/chain.rs @@ -18,7 +18,7 @@ use client::{self, Client as SubstrateClient, ClientInfo, CallExecutor}; use client::error::Error; -use client::light::fetcher::ChangesProof; +use client::light::fetcher::{ChangesProof, StorageProof}; use consensus::{BlockImport, BlockStatus, Error as ConsensusError}; use sr_primitives::traits::{Block as BlockT, Header as HeaderT}; use sr_primitives::generic::{BlockId}; @@ -46,10 +46,11 @@ pub trait Client: Send + Sync { fn justification(&self, id: &BlockId) -> Result, Error>; /// Get block header proof. - fn header_proof(&self, block_number: ::Number) -> Result<(Block::Header, Vec>), Error>; + fn header_proof(&self, block_number: ::Number) + -> Result<(Block::Header, StorageProof), Error>; /// Get storage read execution proof. - fn read_proof(&self, block: &Block::Hash, keys: &[Vec]) -> Result>, Error>; + fn read_proof(&self, block: &Block::Hash, keys: &[Vec]) -> Result; /// Get child storage read execution proof. fn read_child_proof( @@ -57,10 +58,10 @@ pub trait Client: Send + Sync { block: &Block::Hash, storage_key: &[u8], keys: &[Vec], - ) -> Result>, Error>; + ) -> Result; /// Get method execution proof. - fn execution_proof(&self, block: &Block::Hash, method: &str, data: &[u8]) -> Result<(Vec, Vec>), Error>; + fn execution_proof(&self, block: &Block::Hash, method: &str, data: &[u8]) -> Result<(Vec, StorageProof), Error>; /// Get key changes proof. fn key_changes_proof( @@ -120,11 +121,13 @@ impl Client for SubstrateClient where (self as &SubstrateClient).justification(id) } - fn header_proof(&self, block_number: ::Number) -> Result<(Block::Header, Vec>), Error> { + fn header_proof(&self, block_number: ::Number) + -> Result<(Block::Header, StorageProof), Error> + { (self as &SubstrateClient).header_proof(&BlockId::Number(block_number)) } - fn read_proof(&self, block: &Block::Hash, keys: &[Vec]) -> Result>, Error> { + fn read_proof(&self, block: &Block::Hash, keys: &[Vec]) -> Result { (self as &SubstrateClient).read_proof(&BlockId::Hash(block.clone()), keys) } @@ -133,12 +136,12 @@ impl Client for SubstrateClient where block: &Block::Hash, storage_key: &[u8], keys: &[Vec], - ) -> Result>, Error> { + ) -> Result { (self as &SubstrateClient) .read_child_proof(&BlockId::Hash(block.clone()), storage_key, keys) } - fn execution_proof(&self, block: &Block::Hash, method: &str, data: &[u8]) -> Result<(Vec, Vec>), Error> { + fn execution_proof(&self, block: &Block::Hash, method: &str, data: &[u8]) -> Result<(Vec, StorageProof), Error> { (self as &SubstrateClient).execution_proof(&BlockId::Hash(block.clone()), method, data) } diff --git a/core/network/src/protocol.rs b/core/network/src/protocol.rs index 2e036cf1183f1..476113953b6a0 100644 --- a/core/network/src/protocol.rs +++ b/core/network/src/protocol.rs @@ -48,7 +48,7 @@ use std::sync::Arc; use std::{cmp, num::NonZeroUsize, time}; use log::{trace, debug, warn, error}; use crate::chain::{Client, FinalityProofProvider}; -use client::light::fetcher::{FetchChecker, ChangesProof}; +use client::light::fetcher::{FetchChecker, ChangesProof, StorageProof}; use crate::error; use util::LruHashSet; @@ -1226,7 +1226,7 @@ impl, H: ExHashT> Protocol { error ); self.peerset_handle.report_peer(who.clone(), RPC_FAILED_REPUTATION_CHANGE); - Default::default() + StorageProof::empty() } }; @@ -1343,7 +1343,7 @@ impl, H: ExHashT> Protocol { request.block, error ); - Default::default() + StorageProof::empty() } }; self.send_message( @@ -1386,7 +1386,7 @@ impl, H: ExHashT> Protocol { request.block, error ); - Default::default() + StorageProof::empty() } }; self.send_message( @@ -1426,7 +1426,7 @@ impl, H: ExHashT> Protocol { request.block, error ); - (Default::default(), Default::default()) + (Default::default(), StorageProof::empty()) } }; self.send_message( @@ -1495,7 +1495,7 @@ impl, H: ExHashT> Protocol { max_block: Zero::zero(), proof: vec![], roots: BTreeMap::new(), - roots_proof: vec![], + roots_proof: StorageProof::empty(), } } }; diff --git a/core/network/src/protocol/light_dispatch.rs b/core/network/src/protocol/light_dispatch.rs index 33ff23c909d10..3c0185da87346 100644 --- a/core/network/src/protocol/light_dispatch.rs +++ b/core/network/src/protocol/light_dispatch.rs @@ -28,7 +28,7 @@ use linked_hash_map::{Entry, LinkedHashMap}; use client::error::Error as ClientError; use client::light::fetcher::{FetchChecker, RemoteHeaderRequest, RemoteCallRequest, RemoteReadRequest, RemoteChangesRequest, ChangesProof, - RemoteReadChildRequest, RemoteBodyRequest}; + RemoteReadChildRequest, RemoteBodyRequest, StorageProof}; use crate::message::{self, BlockAttributes, Direction, FromBlock, RequestId}; use libp2p::PeerId; use crate::config::Roles; @@ -174,7 +174,7 @@ impl FetchChecker for AlwaysBadChecker { &self, _request: &RemoteHeaderRequest, _remote_header: Option, - _remote_proof: Vec> + _remote_proof: StorageProof, ) -> Result { Err(ClientError::Msg("AlwaysBadChecker".into())) } @@ -182,7 +182,7 @@ impl FetchChecker for AlwaysBadChecker { fn check_read_proof( &self, _request: &RemoteReadRequest, - _remote_proof: Vec> + _remote_proof: StorageProof, ) -> Result,Option>>, ClientError> { Err(ClientError::Msg("AlwaysBadChecker".into())) } @@ -190,7 +190,7 @@ impl FetchChecker for AlwaysBadChecker { fn check_read_child_proof( &self, _request: &RemoteReadChildRequest, - _remote_proof: Vec> + _remote_proof: StorageProof, ) -> Result, Option>>, ClientError> { Err(ClientError::Msg("AlwaysBadChecker".into())) } @@ -198,7 +198,7 @@ impl FetchChecker for AlwaysBadChecker { fn check_execution_proof( &self, _request: &RemoteCallRequest, - _remote_proof: Vec> + _remote_proof: StorageProof, ) -> Result, ClientError> { Err(ClientError::Msg("AlwaysBadChecker".into())) } @@ -684,7 +684,7 @@ pub mod tests { use crate::config::Roles; use crate::message::{self, BlockAttributes, Direction, FromBlock, RequestId}; use libp2p::PeerId; - use super::{REQUEST_TIMEOUT, LightDispatch, LightDispatchNetwork, RequestData}; + use super::{REQUEST_TIMEOUT, LightDispatch, LightDispatchNetwork, RequestData, StorageProof}; use test_client::runtime::{changes_trie_config, Block, Extrinsic, Header}; struct DummyFetchChecker { ok: bool } @@ -694,7 +694,7 @@ pub mod tests { &self, _request: &RemoteHeaderRequest
, header: Option
, - _remote_proof: Vec> + _remote_proof: StorageProof, ) -> ClientResult
{ match self.ok { true if header.is_some() => Ok(header.unwrap()), @@ -705,7 +705,7 @@ pub mod tests { fn check_read_proof( &self, request: &RemoteReadRequest
, - _: Vec>, + _: StorageProof, ) -> ClientResult, Option>>> { match self.ok { true => Ok(request.keys @@ -721,7 +721,7 @@ pub mod tests { fn check_read_child_proof( &self, request: &RemoteReadChildRequest
, - _: Vec> + _: StorageProof, ) -> ClientResult, Option>>> { match self.ok { true => Ok(request.keys @@ -734,7 +734,7 @@ pub mod tests { } } - fn check_execution_proof(&self, _: &RemoteCallRequest
, _: Vec>) -> ClientResult> { + fn check_execution_proof(&self, _: &RemoteCallRequest
, _: StorageProof) -> ClientResult> { match self.ok { true => Ok(vec![42]), false => Err(ClientError::Backend("Test error".into())), @@ -780,7 +780,7 @@ pub mod tests { ) { light_dispatch.on_remote_call_response(network_interface, peer, message::RemoteCallResponse { id: id, - proof: vec![vec![2]], + proof: StorageProof::empty(), }); } @@ -943,7 +943,7 @@ pub mod tests { light_dispatch.on_remote_read_response(&mut network_interface, peer0.clone(), message::RemoteReadResponse { id: 0, - proof: vec![vec![2]], + proof: StorageProof::empty(), }); assert_disconnected_peer(&network_interface); assert_eq!(light_dispatch.pending_requests.len(), 1); @@ -1013,7 +1013,7 @@ pub mod tests { light_dispatch.on_remote_read_response(&mut network_interface, peer0.clone(), message::RemoteReadResponse { id: 0, - proof: vec![vec![2]], + proof: StorageProof::empty(), }); assert_eq!(response.wait().unwrap().unwrap().remove(b":key".as_ref()).unwrap(), Some(vec![42])); } @@ -1037,7 +1037,7 @@ pub mod tests { light_dispatch.on_remote_read_response(&mut network_interface, peer0.clone(), message::RemoteReadResponse { id: 0, - proof: vec![vec![2]], + proof: StorageProof::empty(), }); assert_eq!(response.wait().unwrap().unwrap().remove(b":key".as_ref()).unwrap(), Some(vec![42])); } @@ -1065,7 +1065,7 @@ pub mod tests { extrinsics_root: Default::default(), digest: Default::default(), }), - proof: vec![vec![2]], + proof: StorageProof::empty(), }); assert_eq!( response.wait().unwrap().unwrap().hash(), @@ -1097,7 +1097,7 @@ pub mod tests { max: 1000, proof: vec![vec![2]], roots: vec![], - roots_proof: vec![], + roots_proof: StorageProof::empty(), }); assert_eq!(response.wait().unwrap().unwrap(), vec![(100, 2)]); } @@ -1145,7 +1145,7 @@ pub mod tests { light_dispatch.on_remote_header_response(&mut network_interface, peer1.clone(), message::RemoteHeaderResponse { id: 0, header: Some(dummy_header()), - proof: vec![], + proof: StorageProof::empty(), }); assert!(!light_dispatch.idle_peers.iter().any(|_| true)); diff --git a/core/network/src/protocol/message.rs b/core/network/src/protocol/message.rs index 6560ed0f13a52..ef5e4dbb1db0f 100644 --- a/core/network/src/protocol/message.rs +++ b/core/network/src/protocol/message.rs @@ -26,6 +26,7 @@ pub use self::generic::{ FinalityProofRequest, FinalityProofResponse, FromBlock, RemoteReadChildRequest, }; +use client::light::fetcher::StorageProof; /// A unique ID of a request. pub type RequestId = u64; @@ -122,7 +123,7 @@ pub struct RemoteCallResponse { /// Id of a request this response was made for. pub id: RequestId, /// Execution proof. - pub proof: Vec>, + pub proof: StorageProof, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] @@ -131,7 +132,7 @@ pub struct RemoteReadResponse { /// Id of a request this response was made for. pub id: RequestId, /// Read proof. - pub proof: Vec>, + pub proof: StorageProof, } /// Generic types. @@ -142,7 +143,7 @@ pub mod generic { use super::{ RemoteReadResponse, Transactions, Direction, RequestId, BlockAttributes, RemoteCallResponse, ConsensusEngineId, - BlockState, + BlockState, StorageProof, }; /// Consensus is mostly opaque to us #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] @@ -359,7 +360,7 @@ pub mod generic { /// Header. None if proof generation has failed (e.g. header is unknown). pub header: Option
, /// Header proof. - pub proof: Vec>, + pub proof: StorageProof, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] @@ -395,7 +396,7 @@ pub mod generic { /// Changes tries roots missing on the requester' node. pub roots: Vec<(N, H)>, /// Missing changes tries roots proof. - pub roots_proof: Vec>, + pub roots_proof: StorageProof, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] diff --git a/core/sr-api-macros/src/impl_runtime_apis.rs b/core/sr-api-macros/src/impl_runtime_apis.rs index 28eb5c60729ed..42d653b1abd97 100644 --- a/core/sr-api-macros/src/impl_runtime_apis.rs +++ b/core/sr-api-macros/src/impl_runtime_apis.rs @@ -300,15 +300,17 @@ fn generate_runtime_api_base_structures(impls: &[ItemImpl]) -> Result Option>> { + fn extract_proof(&mut self) -> Option<#crate_::runtime_api::StorageProof> { self.recorder .take() - .map(|r| { - r.borrow_mut() + .map(|recorder| { + let trie_nodes = recorder + .borrow_mut() .drain() .into_iter() - .map(|n| n.data.to_vec()) - .collect() + .map(|record| record.data) + .collect(); + #crate_::runtime_api::StorageProof::new(trie_nodes) }) } } diff --git a/core/state-machine/src/lib.rs b/core/state-machine/src/lib.rs index c3092367f0646..1da9cfb4e7dbe 100644 --- a/core/state-machine/src/lib.rs +++ b/core/state-machine/src/lib.rs @@ -59,8 +59,8 @@ pub use changes_trie::{ }; pub use overlayed_changes::OverlayedChanges; pub use proving_backend::{ - create_proof_check_backend, create_proof_check_backend_storage, - Recorder as ProofRecorder, ProvingBackend, + create_proof_check_backend, create_proof_check_backend_storage, merge_storage_proofs, + Recorder as ProofRecorder, ProvingBackend, StorageProof, }; pub use trie_backend_essence::{TrieBackendStorage, Storage}; pub use trie_backend::TrieBackend; @@ -463,7 +463,7 @@ pub fn prove_execution( method: &str, call_data: &[u8], keystore: Option, -) -> Result<(Vec, Vec>), Box> +) -> Result<(Vec, StorageProof), Box> where B: Backend, H: Hasher, @@ -490,7 +490,7 @@ pub fn prove_execution_on_trie_backend( method: &str, call_data: &[u8], keystore: Option, -) -> Result<(Vec, Vec>), Box> +) -> Result<(Vec, StorageProof), Box> where S: trie_backend_essence::TrieBackendStorage, H: Hasher, @@ -513,7 +513,7 @@ where /// Check execution proof, generated by `prove_execution` call. pub fn execution_proof_check( root: H::Out, - proof: Vec>, + proof: StorageProof, overlay: &mut OverlayedChanges, exec: &Exec, method: &str, @@ -557,7 +557,7 @@ where pub fn prove_read( mut backend: B, keys: I, -) -> Result>, Box> +) -> Result> where B: Backend, H: Hasher, @@ -577,7 +577,7 @@ pub fn prove_child_read( mut backend: B, storage_key: &[u8], keys: I, -) -> Result>, Box> +) -> Result> where B: Backend, H: Hasher, @@ -594,7 +594,7 @@ where pub fn prove_read_on_trie_backend( trie_backend: &TrieBackend, keys: I, -) -> Result>, Box> +) -> Result> where S: trie_backend_essence::TrieBackendStorage, H: Hasher, @@ -616,7 +616,7 @@ pub fn prove_child_read_on_trie_backend( trie_backend: &TrieBackend, storage_key: &[u8], keys: I, -) -> Result>, Box> +) -> Result> where S: trie_backend_essence::TrieBackendStorage, H: Hasher, @@ -636,7 +636,7 @@ where /// Check storage read proof, generated by `prove_read` call. pub fn read_proof_check( root: H::Out, - proof: Vec>, + proof: StorageProof, keys: I, ) -> Result, Option>>, Box> where @@ -657,7 +657,7 @@ where /// Check child storage read proof, generated by `prove_child_read` call. pub fn read_child_proof_check( root: H::Out, - proof: Vec>, + proof: StorageProof, storage_key: &[u8], keys: I, ) -> Result, Option>>, Box> diff --git a/core/state-machine/src/proving_backend.rs b/core/state-machine/src/proving_backend.rs index c6c4ef1ec8c26..14f17a3a48c47 100644 --- a/core/state-machine/src/proving_backend.rs +++ b/core/state-machine/src/proving_backend.rs @@ -16,7 +16,8 @@ //! Proving state machine backend. -use std::{cell::RefCell, rc::Rc}; +use std::{cell::RefCell, collections::HashSet, rc::Rc}; +use codec::{Decode, Encode}; use log::debug; use hash_db::{Hasher, HashDB, EMPTY_PREFIX}; use trie::{ @@ -29,6 +30,82 @@ use crate::trie_backend::TrieBackend; use crate::trie_backend_essence::{Ephemeral, TrieBackendEssence, TrieBackendStorage}; use crate::{Error, ExecutionError, Backend}; +/// A proof that some set of key-value pairs are included in the storage trie. The proof contains +/// the storage values so that the partial storage backend can be reconstructed by a verifier that +/// does not already have access to the key-value pairs. +/// +/// The proof consists of the set of serialized nodes in the storage trie accessed when looking up +/// the keys covered by the proof. Verifying the proof requires constructing the partial trie from +/// the serialized nodes and performing the key lookups. +#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] +pub struct StorageProof { + trie_nodes: Vec>, +} + +impl StorageProof { + /// Constructs a storage proof from a subset of encoded trie nodes in a storage backend. + pub fn new(trie_nodes: Vec>) -> Self { + StorageProof { trie_nodes } + } + + /// Returns a new empty proof. + /// + /// An empty proof is capable of only proving trivial statements (ie. that an empty set of + /// key-value pairs exist in storage). + pub fn empty() -> Self { + StorageProof { + trie_nodes: Vec::new(), + } + } + + /// Returns whether this is an empty proof. + pub fn is_empty(&self) -> bool { + self.trie_nodes.is_empty() + } + + /// Create an iterator over trie nodes constructed from the proof. The nodes are not guaranteed + /// to be traversed in any particular order. + pub fn iter_nodes(self) -> StorageProofNodeIterator { + StorageProofNodeIterator::new(self) + } +} + +/// An iterator over trie nodes constructed from a storage proof. The nodes are not guaranteed to +/// be traversed in any particular order. +pub struct StorageProofNodeIterator { + inner: > as IntoIterator>::IntoIter, +} + +impl StorageProofNodeIterator { + fn new(proof: StorageProof) -> Self { + StorageProofNodeIterator { + inner: proof.trie_nodes.into_iter(), + } + } +} + +impl Iterator for StorageProofNodeIterator { + type Item = Vec; + + fn next(&mut self) -> Option { + self.inner.next() + } +} + +/// Merges multiple storage proofs covering potentially different sets of keys into one proof +/// covering all keys. The merged proof output may be smaller than the aggregate size of the input +/// proofs due to deduplication of trie nodes. +pub fn merge_storage_proofs(proofs: I) -> StorageProof + where I: IntoIterator +{ + let trie_nodes = proofs.into_iter() + .flat_map(|proof| proof.iter_nodes()) + .collect::>() + .into_iter() + .collect(); + StorageProof { trie_nodes } +} + /// Patricia trie-based backend essence which also tracks all touched storage trie values. /// These can be sent to remote node and used as a proof of execution. pub struct ProvingBackendEssence<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> { @@ -129,13 +206,14 @@ impl<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> ProvingBackend<'a, S, H> } /// Consume the backend, extracting the gathered proof in lexicographical order by value. - pub fn extract_proof(&self) -> Vec> { - self.proof_recorder + pub fn extract_proof(&self) -> StorageProof { + let trie_nodes = self.proof_recorder .borrow_mut() .drain() .into_iter() - .map(|n| n.data.to_vec()) - .collect() + .map(|record| record.data) + .collect(); + StorageProof::new(trie_nodes) } } @@ -217,7 +295,7 @@ impl<'a, S, H> Backend for ProvingBackend<'a, S, H> /// Create proof check backend. pub fn create_proof_check_backend( root: H::Out, - proof: Vec> + proof: StorageProof, ) -> Result, H>, Box> where H: Hasher, @@ -233,13 +311,13 @@ where /// Create in-memory storage of proof check backend. pub fn create_proof_check_backend_storage( - proof: Vec> + proof: StorageProof, ) -> MemoryDB where H: Hasher, { let mut db = MemoryDB::default(); - for item in proof { + for item in proof.iter_nodes() { db.insert(EMPTY_PREFIX, &item); } db @@ -275,7 +353,11 @@ mod tests { #[test] fn proof_is_invalid_when_does_not_contains_root() { use primitives::H256; - assert!(create_proof_check_backend::(H256::from_low_u64_be(1), vec![]).is_err()); + let result = create_proof_check_backend::( + H256::from_low_u64_be(1), + StorageProof::empty() + ); + assert!(result.is_err()); } #[test]