From c6ebffb48862ead9904ca647204463560b2b6935 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 30 Jul 2018 11:05:22 +0300 Subject: [PATCH 1/3] storage proofs --- Cargo.lock | 1 + substrate/client/src/client.rs | 13 +++- substrate/client/src/light/backend.rs | 55 ++++++++++++-- substrate/client/src/light/fetcher.rs | 51 +++++++++++-- substrate/network/Cargo.toml | 1 + substrate/network/src/chain.rs | 7 ++ substrate/network/src/lib.rs | 3 +- substrate/network/src/message.rs | 81 ++++++++++++++++++++- substrate/network/src/on_demand.rs | 73 +++++++++++++++---- substrate/network/src/protocol.rs | 23 ++++++ substrate/service/src/components.rs | 5 +- substrate/state-machine/src/lib.rs | 37 ++++++++++ substrate/state-machine/src/trie_backend.rs | 3 + 13 files changed, 321 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 17895bf28deb0..92be9f69c4d9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2787,6 +2787,7 @@ dependencies = [ "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-client 0.1.0", "substrate-codec 0.1.0", "substrate-keyring 0.1.0", diff --git a/substrate/client/src/client.rs b/substrate/client/src/client.rs index c125a1aa4919b..781f3aaab0147 100644 --- a/substrate/client/src/client.rs +++ b/substrate/client/src/client.rs @@ -25,7 +25,10 @@ use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, One, use runtime_primitives::BuildStorage; use primitives::storage::{StorageKey, StorageData}; use codec::Decode; -use state_machine::{Ext, OverlayedChanges, Backend as StateBackend, CodeExecutor, ExecutionStrategy, ExecutionManager}; +use state_machine::{ + Ext, OverlayedChanges, Backend as StateBackend, CodeExecutor, + ExecutionStrategy, ExecutionManager, prove_read +}; use backend::{self, BlockImportOperation}; use blockchain::{self, Info as ChainInfo, Backend as ChainBackend, HeaderBackend as ChainHeaderBackend}; @@ -233,6 +236,14 @@ impl Client where &self.executor } + /// Reads storage value at a given block + key, returning read proof. + pub fn read_proof(&self, id: &BlockId, key: &[u8]) -> error::Result>> { + self.state_at(id) + .and_then(|state| prove_read(state, key) + .map(|(_, proof)| proof) + .map_err(Into::into)) + } + /// Execute a call to a contract on top of state in a block of given hash /// AND returning execution proof. /// diff --git a/substrate/client/src/light/backend.rs b/substrate/client/src/light/backend.rs index d06aef80bf5ab..6851b54d1a62b 100644 --- a/substrate/client/src/light/backend.rs +++ b/substrate/client/src/light/backend.rs @@ -18,6 +18,7 @@ //! Everything else is requested from full nodes on demand. use std::sync::{Arc, Weak}; +use futures::{Future, IntoFuture}; use primitives::AuthorityId; use runtime_primitives::{bft::Justification, generic::BlockId}; @@ -29,7 +30,7 @@ use backend::{Backend as ClientBackend, BlockImportOperation, RemoteBackend}; use blockchain::HeaderBackend as BlockchainHeaderBackend; use error::{Error as ClientError, ErrorKind as ClientErrorKind, Result as ClientResult}; use light::blockchain::{Blockchain, Storage as BlockchainStorage}; -use light::fetcher::Fetcher; +use light::fetcher::{Fetcher, RemoteReadRequest}; /// Light client backend. pub struct Backend { @@ -152,8 +153,13 @@ impl StateBackend for OnDemandState where Block: BlockT, F: type Error = ClientError; type Transaction = (); - fn storage(&self, _key: &[u8]) -> ClientResult>> { - Err(ClientErrorKind::NotAvailableOnLightClient.into()) // TODO: fetch from remote node + fn storage(&self, key: &[u8]) -> ClientResult>> { + self.fetcher.upgrade().ok_or(ClientErrorKind::NotAvailableOnLightClient)? + .remote_read(RemoteReadRequest { + block: self.block, + key: key.to_vec(), + }) + .into_future().wait() } fn for_keys_with_prefix(&self, _prefix: &[u8], _action: A) { @@ -179,20 +185,57 @@ impl TryIntoStateTrieBackend for OnDemandState where Block: #[cfg(test)] pub mod tests { - use futures::future::{ok, FutureResult}; + use futures::future::{ok, err, FutureResult}; use parking_lot::Mutex; use call_executor::CallResult; + use executor::{self, NativeExecutionDispatch}; use error::Error as ClientError; - use test_client::runtime::{Hash, Block}; - use light::fetcher::{Fetcher, RemoteCallRequest}; + use test_client::{self, runtime::{Hash, Block}}; + use in_mem::{Blockchain as InMemoryBlockchain}; + use light::{new_fetch_checker, new_light_blockchain}; + use light::fetcher::{Fetcher, FetchChecker, LightDataChecker, RemoteCallRequest}; + use super::*; pub type OkCallFetcher = Mutex; impl Fetcher for OkCallFetcher { + type RemoteReadResult = FutureResult>, ClientError>; type RemoteCallResult = FutureResult; + fn remote_read(&self, _request: RemoteReadRequest) -> Self::RemoteReadResult { + err("Not implemented on test node".into()) + } + fn remote_call(&self, _request: RemoteCallRequest) -> Self::RemoteCallResult { ok((*self.lock()).clone()) } } + + #[test] + fn storage_read_proof_is_generated_and_checked() { + // prepare remote client + let remote_client = test_client::new(); + let remote_block_id = BlockId::Number(0); + let remote_block_hash = remote_client.block_hash(0).unwrap().unwrap(); + let mut remote_block_header = remote_client.header(&remote_block_id).unwrap().unwrap(); + remote_block_header.state_root = remote_client.state_at(&remote_block_id).unwrap().storage_root(::std::iter::empty()).0.into(); + + // 'fetch' read proof from remote node + let authorities_len = remote_client.authorities_at(&remote_block_id).unwrap().len(); + let remote_read_proof = remote_client.read_proof(&remote_block_id, b":auth:len").unwrap(); + + // check remote read proof locally + let local_storage = InMemoryBlockchain::::new(); + local_storage.insert(remote_block_hash, remote_block_header, None, None, true); + let local_executor = test_client::LocalExecutor::with_heap_pages(8, 8); + let local_checker: LightDataChecker< + InMemoryBlockchain, + executor::NativeExecutor, + OkCallFetcher + > = new_fetch_checker(new_light_blockchain(local_storage), local_executor); + assert_eq!(local_checker.check_read_proof(&RemoteReadRequest { + block: remote_block_hash, + key: b":auth:len".to_vec(), + }, remote_read_proof).unwrap().unwrap()[0], authorities_len as u8); + } } diff --git a/substrate/client/src/light/fetcher.rs b/substrate/client/src/light/fetcher.rs index 90622bf6fc008..5cda7d766e8f2 100644 --- a/substrate/client/src/light/fetcher.rs +++ b/substrate/client/src/light/fetcher.rs @@ -19,13 +19,15 @@ use std::sync::Arc; use futures::IntoFuture; -use runtime_primitives::traits::{Block as BlockT}; -use state_machine::CodeExecutor; +use runtime_primitives::generic::BlockId; +use runtime_primitives::traits::{Block as BlockT, Header as HeaderT}; +use state_machine::{CodeExecutor, read_proof_check}; use call_executor::CallResult; -use error::{Error as ClientError, Result as ClientResult}; +use error::{Error as ClientError, ErrorKind as ClientErrorKind, Result as ClientResult}; use light::blockchain::{Blockchain, Storage as BlockchainStorage}; use light::call_executor::check_execution_proof; +use blockchain::HeaderBackend as BlockchainHeaderBackend; /// Remote call request. #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -38,20 +40,43 @@ pub struct RemoteCallRequest { pub call_data: Vec, } +/// Remote storage read request. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct RemoteReadRequest { + /// Read at state of given block. + pub block: Hash, + /// Storage key to read. + pub key: Vec, +} + /// Light client data fetcher. Implementations of this trait must check if remote data /// is correct (see FetchedDataChecker) and return already checked data. pub trait Fetcher: Send + Sync { + /// Remote storage read future. + type RemoteReadResult: IntoFuture>, Error=ClientError>; /// Remote call result future. type RemoteCallResult: IntoFuture; + /// Fetch remote storage value. + fn remote_read(&self, request: RemoteReadRequest) -> Self::RemoteReadResult; /// Fetch remote call result. fn remote_call(&self, request: RemoteCallRequest) -> Self::RemoteCallResult; } /// Light client remote data checker. pub trait FetchChecker: Send + Sync { + /// Check remote storage read proof. + fn check_read_proof( + &self, + request: &RemoteReadRequest, + remote_proof: Vec> + ) -> ClientResult>>; /// Check remote method execution proof. - fn check_execution_proof(&self, request: &RemoteCallRequest, remote_proof: Vec>) -> ClientResult; + fn check_execution_proof( + &self, + request: &RemoteCallRequest, + remote_proof: Vec> + ) -> ClientResult; } /// Remote data checker. @@ -78,11 +103,27 @@ impl LightDataChecker { impl FetchChecker for LightDataChecker where Block: BlockT, + Block::Hash: Into<[u8; 32]>, S: BlockchainStorage, E: CodeExecutor, F: Fetcher, { - fn check_execution_proof(&self, request: &RemoteCallRequest, remote_proof: Vec>) -> ClientResult { + fn check_read_proof( + &self, + request: &RemoteReadRequest, + remote_proof: Vec> + ) -> ClientResult>> { + let local_header = self.blockchain.header(BlockId::Hash(request.block))?; + let local_header = local_header.ok_or_else(|| ClientErrorKind::UnknownBlock(format!("{}", request.block)))?; + let local_state_root = *local_header.state_root(); + read_proof_check(local_state_root.into(), remote_proof, &request.key).map_err(Into::into) + } + + fn check_execution_proof( + &self, + request: &RemoteCallRequest, + remote_proof: Vec> + ) -> ClientResult { check_execution_proof(&*self.blockchain, &self.executor, request, remote_proof) } } diff --git a/substrate/network/Cargo.toml b/substrate/network/Cargo.toml index 0185cf49f2216..7362911ee532f 100644 --- a/substrate/network/Cargo.toml +++ b/substrate/network/Cargo.toml @@ -14,6 +14,7 @@ error-chain = "0.12" bitflags = "1.0" futures = "0.1.17" linked-hash-map = "0.5" +rustc-hex = "1.0" ethcore-io = { git = "https://github.com/paritytech/parity.git" } ed25519 = { path = "../../substrate/ed25519" } substrate-primitives = { path = "../../substrate/primitives" } diff --git a/substrate/network/src/chain.rs b/substrate/network/src/chain.rs index f20b7e2b5e688..d698ab0900aa7 100644 --- a/substrate/network/src/chain.rs +++ b/substrate/network/src/chain.rs @@ -45,6 +45,9 @@ pub trait Client: Send + Sync { /// Get block justification. fn justification(&self, id: &BlockId) -> Result>, Error>; + /// Get storage read execution proof. + fn read_proof(&self, block: &Block::Hash, key: &[u8]) -> Result>, Error>; + /// Get method execution proof. fn execution_proof(&self, block: &Block::Hash, method: &str, data: &[u8]) -> Result<(Vec, Vec>), Error>; } @@ -84,6 +87,10 @@ impl Client for SubstrateClient where (self as &SubstrateClient).justification(id) } + fn read_proof(&self, block: &Block::Hash, key: &[u8]) -> Result>, Error> { + (self as &SubstrateClient).read_proof(&BlockId::Hash(block.clone()), key) + } + fn execution_proof(&self, block: &Block::Hash, method: &str, data: &[u8]) -> Result<(Vec, Vec>), Error> { (self as &SubstrateClient).execution_proof(&BlockId::Hash(block.clone()), method, data) } diff --git a/substrate/network/src/lib.rs b/substrate/network/src/lib.rs index 2c6b880013b31..8d5f2bc5ffd49 100644 --- a/substrate/network/src/lib.rs +++ b/substrate/network/src/lib.rs @@ -30,6 +30,7 @@ extern crate substrate_network_libp2p as network_libp2p; extern crate substrate_codec as codec; extern crate futures; extern crate ed25519; +extern crate rustc_hex; #[macro_use] extern crate log; #[macro_use] extern crate bitflags; #[macro_use] extern crate error_chain; @@ -63,4 +64,4 @@ pub use network_libp2p::{NonReservedPeerMode, NetworkConfiguration, NodeIndex, P pub use message::{generic as generic_message, RequestId, BftMessage, LocalizedBftMessage, ConsensusVote, SignedConsensusVote, SignedConsensusMessage, SignedConsensusProposal, Status as StatusMessage}; pub use error::Error; pub use config::{Roles, ProtocolConfig}; -pub use on_demand::{OnDemand, OnDemandService, RemoteCallResponse}; +pub use on_demand::{OnDemand, OnDemandService, RemoteResponse}; diff --git a/substrate/network/src/message.rs b/substrate/network/src/message.rs index e7e6addc39d9f..d2bbcdf3e7581 100644 --- a/substrate/network/src/message.rs +++ b/substrate/network/src/message.rs @@ -18,7 +18,10 @@ use runtime_primitives::traits::{Block as BlockT, Header as HeaderT}; use codec::{Encode, Decode, Input, Output}; -pub use self::generic::{BlockAnnounce, RemoteCallRequest, ConsensusVote, SignedConsensusVote, FromBlock}; +pub use self::generic::{ + BlockAnnounce, RemoteCallRequest, RemoteReadRequest, + ConsensusVote, SignedConsensusVote, FromBlock +}; /// A unique ID of a request. pub type RequestId = u64; @@ -135,7 +138,32 @@ impl Decode for RemoteCallResponse { }) } } - + +#[derive(Debug, PartialEq, Eq, Clone)] +/// Remote read response. +pub struct RemoteReadResponse { + /// Id of a request this response was made for. + pub id: RequestId, + /// Read proof. + pub proof: Vec>, +} + +impl Encode for RemoteReadResponse { + fn encode_to(&self, dest: &mut T) { + dest.push(&self.id); + dest.push(&self.proof); + } +} + +impl Decode for RemoteReadResponse { + fn decode(input: &mut I) -> Option { + Some(RemoteReadResponse { + id: Decode::decode(input)?, + proof: Decode::decode(input)?, + }) + } +} + /// Generic types. pub mod generic { use primitives::AuthorityId; @@ -143,8 +171,10 @@ pub mod generic { use runtime_primitives::bft::Justification; use ed25519; use service::Roles; - use super::{BlockAttributes, RemoteCallResponse, RequestId, Transactions, Direction}; - + use super::{ + BlockAttributes, RemoteCallResponse, RemoteReadResponse, + RequestId, Transactions, Direction + }; /// Block data sent in the response. #[derive(Debug, PartialEq, Eq, Clone)] @@ -446,6 +476,10 @@ pub mod generic { RemoteCallRequest(RemoteCallRequest), /// Remote method call response. RemoteCallResponse(RemoteCallResponse), + /// Remote storage read request. + RemoteReadRequest(RemoteReadRequest), + /// Remote storage read response. + RemoteReadResponse(RemoteReadResponse), /// Chain-specific message ChainSpecific(Vec), } @@ -487,6 +521,14 @@ pub mod generic { dest.push_byte(7); dest.push(m); } + Message::RemoteReadRequest(ref m) => { + dest.push_byte(8); + dest.push(m); + } + Message::RemoteReadResponse(ref m) => { + dest.push_byte(9); + dest.push(m); + } Message::ChainSpecific(ref m) => { dest.push_byte(255); dest.push(m); @@ -508,6 +550,8 @@ pub mod generic { 5 => Some(Message::BftMessage(Decode::decode(input)?)), 6 => Some(Message::RemoteCallRequest(Decode::decode(input)?)), 7 => Some(Message::RemoteCallResponse(Decode::decode(input)?)), + 8 => Some(Message::RemoteReadRequest(Decode::decode(input)?)), + 9 => Some(Message::RemoteReadResponse(Decode::decode(input)?)), 255 => Some(Message::ChainSpecific(Decode::decode(input)?)), _ => None, } @@ -678,4 +722,33 @@ pub mod generic { }) } } + + #[derive(Debug, PartialEq, Eq, Clone)] + /// Remote storage read request. + pub struct RemoteReadRequest { + /// Unique request id. + pub id: RequestId, + /// Block at which to perform call. + pub block: H, + /// Storage key. + pub key: Vec, + } + + impl Encode for RemoteReadRequest { + fn encode_to(&self, dest: &mut T) { + dest.push(&self.id); + dest.push(&self.block); + dest.push(&self.key); + } + } + + impl Decode for RemoteReadRequest { + fn decode(input: &mut I) -> Option { + Some(RemoteReadRequest { + id: Decode::decode(input)?, + block: Decode::decode(input)?, + key: Decode::decode(input)?, + }) + } + } } diff --git a/substrate/network/src/on_demand.rs b/substrate/network/src/on_demand.rs index 8a8e76a3d0bbf..069cd84c5c658 100644 --- a/substrate/network/src/on_demand.rs +++ b/substrate/network/src/on_demand.rs @@ -25,7 +25,7 @@ use linked_hash_map::LinkedHashMap; use linked_hash_map::Entry; use parking_lot::Mutex; use client; -use client::light::fetcher::{Fetcher, FetchChecker, RemoteCallRequest}; +use client::light::fetcher::{Fetcher, FetchChecker, RemoteCallRequest, RemoteReadRequest}; use io::SyncIo; use message; use network_libp2p::{Severity, NodeIndex}; @@ -46,6 +46,9 @@ pub trait OnDemandService: Send + Sync { /// Maintain peers requests. fn maintain_peers(&self, io: &mut SyncIo); + /// When read response is received from remote node. + fn on_remote_read_response(&self, io: &mut SyncIo, peer: NodeIndex, response: message::RemoteReadResponse); + /// When call response is received from remote node. fn on_remote_call_response(&self, io: &mut SyncIo, peer: NodeIndex, response: message::RemoteCallResponse); } @@ -57,8 +60,8 @@ pub struct OnDemand> { } /// On-demand remote call response. -pub struct RemoteCallResponse { - receiver: Receiver>, +pub struct RemoteResponse { + receiver: Receiver>, } #[derive(Default)] @@ -77,16 +80,18 @@ struct Request { } enum RequestData { + RemoteRead(RemoteReadRequest, Sender>, client::error::Error>>), RemoteCall(RemoteCallRequest, Sender>), } enum Accept { Ok, CheckFailed(client::error::Error, RequestData), + Unexpected(RequestData), } -impl Future for RemoteCallResponse { - type Item = client::CallResult; +impl Future for RemoteResponse { + type Item = T; type Error = client::error::Error; fn poll(&mut self) -> Poll { @@ -150,6 +155,10 @@ impl OnDemand where core.remove_peer(peer); Some(retry_request_data) }, + Accept::Unexpected(retry_request_data) => { + trace!(target: "sync", "Unexpected response to remote {} from peer {}", rtype, peer); + Some(retry_request_data) + }, }; if let Some(request_data) = retry_request_data { @@ -189,6 +198,20 @@ impl OnDemandService for OnDemand where core.dispatch(); } + fn on_remote_read_response(&self, io: &mut SyncIo, peer: NodeIndex, response: message::RemoteReadResponse) { + self.accept_response("read", io, peer, response.id, |request| match request.data { + RequestData::RemoteRead(request, sender) => match self.checker.check_read_proof(&request, response.proof) { + Ok(response) => { + // we do not bother if receiver has been dropped already + let _ = sender.send(Ok(response)); + Accept::Ok + }, + Err(error) => Accept::CheckFailed(error, RequestData::RemoteRead(request, sender)), + }, + data @ _ => Accept::Unexpected(data), + }) + } + fn on_remote_call_response(&self, io: &mut SyncIo, peer: NodeIndex, response: message::RemoteCallResponse) { self.accept_response("call", io, peer, response.id, |request| match request.data { RequestData::RemoteCall(request, sender) => match self.checker.check_execution_proof(&request, response.proof) { @@ -199,6 +222,7 @@ impl OnDemandService for OnDemand where }, Err(error) => Accept::CheckFailed(error, RequestData::RemoteCall(request, sender)), }, + data @ _ => Accept::Unexpected(data), }) } } @@ -208,12 +232,19 @@ impl Fetcher for OnDemand where E: service::ExecuteInContext, B::Header: HeaderT, { - type RemoteCallResult = RemoteCallResponse; + type RemoteReadResult = RemoteResponse>>; + type RemoteCallResult = RemoteResponse; + + fn remote_read(&self, request: RemoteReadRequest) -> Self::RemoteReadResult { + let (sender, receiver) = channel(); + self.schedule_request(RequestData::RemoteRead(request, sender), + RemoteResponse { receiver }) + } fn remote_call(&self, request: RemoteCallRequest) -> Self::RemoteCallResult { let (sender, receiver) = channel(); self.schedule_request(RequestData::RemoteCall(request, sender), - RemoteCallResponse { receiver }) + RemoteResponse { receiver }) } } @@ -301,12 +332,19 @@ impl OnDemandCore where impl Request { pub fn message(&self) -> message::Message { match self.data { - RequestData::RemoteCall(ref data, _) => message::generic::Message::RemoteCallRequest(message::RemoteCallRequest { - id: self.id, - block: data.block, - method: data.method.clone(), - data: data.call_data.clone(), - }), + RequestData::RemoteRead(ref data, _) => message::generic::Message::RemoteReadRequest( + message::RemoteReadRequest { + id: self.id, + block: data.block, + key: data.key.clone(), + }), + RequestData::RemoteCall(ref data, _) => message::generic::Message::RemoteCallRequest( + message::RemoteCallRequest { + id: self.id, + block: data.block, + method: data.method.clone(), + data: data.call_data.clone(), + }), } } } @@ -319,7 +357,7 @@ pub mod tests { use futures::Future; use parking_lot::RwLock; use client; - use client::light::fetcher::{Fetcher, FetchChecker, RemoteCallRequest}; + use client::light::fetcher::{Fetcher, FetchChecker, RemoteCallRequest, RemoteReadRequest}; use message; use network_libp2p::NodeIndex; use service::{Roles, ExecuteInContext}; @@ -335,6 +373,13 @@ pub mod tests { } impl FetchChecker for DummyFetchChecker { + fn check_read_proof(&self, _request: &RemoteReadRequest, _remote_proof: Vec>) -> client::error::Result>> { + match self.ok { + true => Ok(Some(vec![42])), + false => Err(client::error::ErrorKind::Backend("Test error".into()).into()), + } + } + fn check_execution_proof(&self, _request: &RemoteCallRequest, _remote_proof: Vec>) -> client::error::Result { match self.ok { true => Ok(client::CallResult { diff --git a/substrate/network/src/protocol.rs b/substrate/network/src/protocol.rs index e8de0f218b580..545fcc06bc934 100644 --- a/substrate/network/src/protocol.rs +++ b/substrate/network/src/protocol.rs @@ -19,6 +19,7 @@ use std::{mem, cmp}; use std::sync::Arc; use std::time; use parking_lot::RwLock; +use rustc_hex::ToHex; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Hash, HashFor, As}; use runtime_primitives::generic::BlockId; use network_libp2p::{NodeIndex, Severity}; @@ -268,6 +269,8 @@ impl> Protocol { GenericMessage::Transactions(m) => self.on_extrinsics(io, who, m), GenericMessage::RemoteCallRequest(request) => self.on_remote_call_request(io, who, request), GenericMessage::RemoteCallResponse(response) => self.on_remote_call_response(io, who, response), + GenericMessage::RemoteReadRequest(request) => self.on_remote_read_request(io, who, request), + GenericMessage::RemoteReadResponse(response) => self.on_remote_read_response(io, who, response), other => self.specialization.write().on_message(&mut ProtocolContext::new(&self.context_data, io), who, other), } } @@ -602,6 +605,26 @@ impl> Protocol { self.on_demand.as_ref().map(|s| s.on_remote_call_response(io, who, response)); } + fn on_remote_read_request(&self, io: &mut SyncIo, who: NodeIndex, request: message::RemoteReadRequest) { + trace!(target: "sync", "Remote read request {} from {} ({} at {})", + request.id, who, request.key.to_hex(), request.block); + let proof = match self.context_data.chain.read_proof(&request.block, &request.key) { + Ok(proof) => proof, + Err(error) => { + trace!(target: "sync", "Remote read request {} from {} ({} at {}) failed with: {}", + request.id, who, request.key.to_hex(), request.block, error); + Default::default() + }, + }; + self.send_message(io, who, GenericMessage::RemoteReadResponse(message::RemoteReadResponse { + id: request.id, proof, + })); + } + fn on_remote_read_response(&self, io: &mut SyncIo, who: NodeIndex, response: message::RemoteReadResponse) { + trace!(target: "sync", "Remote read response {} from {}", response.id, who); + self.on_demand.as_ref().map(|s| s.on_remote_read_response(io, who, response)); + } + /// Execute a closure with access to a network context and specialization. pub fn with_spec(&self, io: &mut SyncIo, f: F) -> U where F: FnOnce(&mut S, &mut Context) -> U diff --git a/substrate/service/src/components.rs b/substrate/service/src/components.rs index fd96dc7c31688..058ea13dc7b84 100644 --- a/substrate/service/src/components.rs +++ b/substrate/service/src/components.rs @@ -213,7 +213,10 @@ pub struct LightComponents { _factory: PhantomData, } -impl Components for LightComponents { +impl Components for LightComponents + where + <::Block as BlockT>::Hash: Into<[u8; 32]>, +{ type Factory = Factory; type Executor = LightExecutor; type Backend = LightBackend; diff --git a/substrate/state-machine/src/lib.rs b/substrate/state-machine/src/lib.rs index 17fd85852b6ac..ab8d5b575d7ef 100644 --- a/substrate/state-machine/src/lib.rs +++ b/substrate/state-machine/src/lib.rs @@ -414,6 +414,29 @@ pub fn execution_proof_check( execute(&backend, overlay, exec, method, call_data, ExecutionStrategy::NativeWhenPossible) } +/// Generate storage read proof. +pub fn prove_read( + backend: B, + key: &[u8], +) -> Result<(Option>, Vec>), Box> +{ + let trie_backend = backend.try_into_trie_backend() + .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; + let proving_backend = proving_backend::ProvingBackend::new(trie_backend); + let result = proving_backend.storage(key).map_err(|e| Box::new(e) as Box)?; + Ok((result, proving_backend.extract_proof())) +} + /// Check storage read proof, generated by `prove` call. +pub fn read_proof_check( + root: [u8; 32], + proof: Vec>, + key: &[u8], +) -> Result>, Box> +{ + let backend = proving_backend::create_proof_check_backend(root.into(), proof)?; + backend.storage(key).map_err(|e| Box::new(e) as Box) +} + #[cfg(test)] mod tests { use super::*; @@ -607,4 +630,18 @@ mod tests { ], ); } + + #[test] + fn prove_read_and_proof_check_works() { + // fetch read proof from 'remote' full node + let remote_backend = trie_backend::tests::test_trie(); + let remote_root = remote_backend.storage_root(::std::iter::empty()).0; + let remote_proof = prove_read(remote_backend, b"value2").unwrap().1; + // check proof locally + let local_result1 = read_proof_check(remote_root, remote_proof.clone(), b"value2").unwrap(); + let local_result2 = read_proof_check(remote_root, remote_proof.clone(), &[0xff]).is_ok(); + // check that results are correct + assert_eq!(local_result1, Some(vec![24])); + assert_eq!(local_result2, false); + } } diff --git a/substrate/state-machine/src/trie_backend.rs b/substrate/state-machine/src/trie_backend.rs index 098d0f6df338c..629dd3ddb3a9c 100644 --- a/substrate/state-machine/src/trie_backend.rs +++ b/substrate/state-machine/src/trie_backend.rs @@ -282,6 +282,9 @@ pub mod tests { trie.insert(b"value1", &[42]).unwrap(); trie.insert(b"value2", &[24]).unwrap(); trie.insert(b":code", b"return 42").unwrap(); + for i in 128u8..255u8 { + trie.insert(&[i], &[i]).unwrap(); + } } (mdb, root) } From 0c55d1063c50fa2b36f9d61c199c27cb55e7b6e0 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 9 Aug 2018 11:07:47 +0300 Subject: [PATCH 2/3] fixed grumbles --- substrate/client/src/blockchain.rs | 13 +++- substrate/client/src/light/backend.rs | 86 ++++++++++++--------- substrate/client/src/light/call_executor.rs | 38 ++++----- substrate/client/src/light/fetcher.rs | 56 ++++++-------- substrate/client/src/light/mod.rs | 9 +-- substrate/network/src/on_demand.rs | 52 ++++++++++--- substrate/service/src/components.rs | 2 +- substrate/state-machine/src/lib.rs | 2 +- 8 files changed, 144 insertions(+), 114 deletions(-) diff --git a/substrate/client/src/blockchain.rs b/substrate/client/src/blockchain.rs index 333bc8f72e156..71b054cbb301e 100644 --- a/substrate/client/src/blockchain.rs +++ b/substrate/client/src/blockchain.rs @@ -17,22 +17,27 @@ //! Polkadot blockchain trait use primitives::AuthorityId; -use runtime_primitives::traits::{Block as BlockT, Header as HeaderT}; +use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use runtime_primitives::generic::BlockId; use runtime_primitives::bft::Justification; -use error::Result; +use error::{ErrorKind, Result}; /// Blockchain database header backend. Does not perform any validation. pub trait HeaderBackend: Send + Sync { /// Get block header. Returns `None` if block is not found. - fn header(&self, id: BlockId) -> Result::Header>>; + fn header(&self, id: BlockId) -> Result>; /// Get blockchain info. fn info(&self) -> Result>; /// Get block status. fn status(&self, id: BlockId) -> Result; /// Get block hash by number. Returns `None` if the header is not in the chain. - fn hash(&self, number: <::Header as HeaderT>::Number) -> Result::Header as HeaderT>::Hash>>; + fn hash(&self, number: NumberFor) -> Result>; + + /// Get block header. Returns `UnknownBlock` error if block is not found. + fn expect_header(&self, id: BlockId) -> Result { + self.header(id)?.ok_or_else(|| ErrorKind::UnknownBlock(format!("{}", id)).into()) + } } /// Blockchain database backend. Does not perform any validation. diff --git a/substrate/client/src/light/backend.rs b/substrate/client/src/light/backend.rs index 6851b54d1a62b..b3d4540ed6003 100644 --- a/substrate/client/src/light/backend.rs +++ b/substrate/client/src/light/backend.rs @@ -19,6 +19,7 @@ use std::sync::{Arc, Weak}; use futures::{Future, IntoFuture}; +use parking_lot::RwLock; use primitives::AuthorityId; use runtime_primitives::{bft::Justification, generic::BlockId}; @@ -38,17 +39,19 @@ pub struct Backend { } /// Light block (header and justification) import operation. -pub struct ImportOperation { +pub struct ImportOperation { is_new_best: bool, header: Option, authorities: Option>, - _phantom: ::std::marker::PhantomData, + _phantom: ::std::marker::PhantomData<(S, F)>, } /// On-demand state. -pub struct OnDemandState { +pub struct OnDemandState { fetcher: Weak, + blockchain: Weak>, block: Block::Hash, + cached_header: RwLock>, } impl Backend { @@ -64,9 +67,9 @@ impl Backend { } impl ClientBackend for Backend where Block: BlockT, S: BlockchainStorage, F: Fetcher { - type BlockImportOperation = ImportOperation; + type BlockImportOperation = ImportOperation; type Blockchain = Blockchain; - type State = OnDemandState; + type State = OnDemandState; fn begin_operation(&self, _block: BlockId) -> ClientResult { Ok(ImportOperation { @@ -93,8 +96,10 @@ impl ClientBackend for Backend where Block: BlockT, S: }; Ok(OnDemandState { - block: block_hash.ok_or_else(|| ClientErrorKind::UnknownBlock(format!("{}", block)))?, fetcher: self.blockchain.fetcher(), + blockchain: Arc::downgrade(&self.blockchain), + block: block_hash.ok_or_else(|| ClientErrorKind::UnknownBlock(format!("{}", block)))?, + cached_header: RwLock::new(None), }) } @@ -105,8 +110,13 @@ impl ClientBackend for Backend where Block: BlockT, S: impl RemoteBackend for Backend where Block: BlockT, S: BlockchainStorage, F: Fetcher {} -impl BlockImportOperation for ImportOperation where Block: BlockT, F: Fetcher { - type State = OnDemandState; +impl BlockImportOperation for ImportOperation + where + Block: BlockT, + S: BlockchainStorage, + F: Fetcher, +{ + type State = OnDemandState; fn state(&self) -> ClientResult> { // None means 'locally-stateless' backend @@ -140,23 +150,29 @@ impl BlockImportOperation for ImportOperation where B } } -impl Clone for OnDemandState { - fn clone(&self) -> Self { - OnDemandState { - fetcher: self.fetcher.clone(), - block: self.block, - } - } -} - -impl StateBackend for OnDemandState where Block: BlockT, F: Fetcher { +impl StateBackend for OnDemandState + where + Block: BlockT, + S: BlockchainStorage, + F: Fetcher, +{ type Error = ClientError; type Transaction = (); fn storage(&self, key: &[u8]) -> ClientResult>> { + let mut header = self.cached_header.read().clone(); + if header.is_none() { + let cached_header = self.blockchain.upgrade() + .ok_or_else(|| ClientErrorKind::UnknownBlock(format!("{}", self.block)).into()) + .and_then(|blockchain| blockchain.expect_header(BlockId::Hash(self.block)))?; + header = Some(cached_header.clone()); + *self.cached_header.write() = Some(cached_header); + } + self.fetcher.upgrade().ok_or(ClientErrorKind::NotAvailableOnLightClient)? .remote_read(RemoteReadRequest { block: self.block, + header: header.expect("if block above guarantees that header is_some(); qed"), key: key.to_vec(), }) .into_future().wait() @@ -177,7 +193,7 @@ impl StateBackend for OnDemandState where Block: BlockT, F: } } -impl TryIntoStateTrieBackend for OnDemandState where Block: BlockT, F: Fetcher { +impl TryIntoStateTrieBackend for OnDemandState where Block: BlockT, F: Fetcher { fn try_into_trie_backend(self) -> Option { None } @@ -188,12 +204,11 @@ pub mod tests { use futures::future::{ok, err, FutureResult}; use parking_lot::Mutex; use call_executor::CallResult; - use executor::{self, NativeExecutionDispatch}; + use executor::NativeExecutionDispatch; use error::Error as ClientError; - use test_client::{self, runtime::{Hash, Block}}; - use in_mem::{Blockchain as InMemoryBlockchain}; - use light::{new_fetch_checker, new_light_blockchain}; - use light::fetcher::{Fetcher, FetchChecker, LightDataChecker, RemoteCallRequest}; + use test_client::{self, runtime::{Header, Block}}; + use light::new_fetch_checker; + use light::fetcher::{Fetcher, FetchChecker, RemoteCallRequest}; use super::*; pub type OkCallFetcher = Mutex; @@ -202,11 +217,11 @@ pub mod tests { type RemoteReadResult = FutureResult>, ClientError>; type RemoteCallResult = FutureResult; - fn remote_read(&self, _request: RemoteReadRequest) -> Self::RemoteReadResult { + fn remote_read(&self, _request: RemoteReadRequest
) -> Self::RemoteReadResult { err("Not implemented on test node".into()) } - fn remote_call(&self, _request: RemoteCallRequest) -> Self::RemoteCallResult { + fn remote_call(&self, _request: RemoteCallRequest
) -> Self::RemoteCallResult { ok((*self.lock()).clone()) } } @@ -218,24 +233,23 @@ pub mod tests { let remote_block_id = BlockId::Number(0); let remote_block_hash = remote_client.block_hash(0).unwrap().unwrap(); let mut remote_block_header = remote_client.header(&remote_block_id).unwrap().unwrap(); - remote_block_header.state_root = remote_client.state_at(&remote_block_id).unwrap().storage_root(::std::iter::empty()).0.into(); + remote_block_header.state_root = remote_client.state_at(&remote_block_id) + .unwrap().storage_root(::std::iter::empty()).0.into(); // 'fetch' read proof from remote node let authorities_len = remote_client.authorities_at(&remote_block_id).unwrap().len(); let remote_read_proof = remote_client.read_proof(&remote_block_id, b":auth:len").unwrap(); // check remote read proof locally - let local_storage = InMemoryBlockchain::::new(); - local_storage.insert(remote_block_hash, remote_block_header, None, None, true); let local_executor = test_client::LocalExecutor::with_heap_pages(8, 8); - let local_checker: LightDataChecker< - InMemoryBlockchain, - executor::NativeExecutor, - OkCallFetcher - > = new_fetch_checker(new_light_blockchain(local_storage), local_executor); - assert_eq!(local_checker.check_read_proof(&RemoteReadRequest { + let local_checker = new_fetch_checker(local_executor); + let request = RemoteReadRequest { block: remote_block_hash, + header: remote_block_header, key: b":auth:len".to_vec(), - }, remote_read_proof).unwrap().unwrap()[0], authorities_len as u8); + }; + assert_eq!((&local_checker as &FetchChecker).check_read_proof( + &request, + remote_read_proof).unwrap().unwrap()[0], authorities_len as u8); } } diff --git a/substrate/client/src/light/call_executor.rs b/substrate/client/src/light/call_executor.rs index 40d8665510100..44b9ad5991fef 100644 --- a/substrate/client/src/light/call_executor.rs +++ b/substrate/client/src/light/call_executor.rs @@ -60,9 +60,11 @@ impl CallExecutor for RemoteCallExecutor BlockId::Number(number) => self.blockchain.hash(number)? .ok_or_else(|| ClientErrorKind::UnknownBlock(format!("{}", number)))?, }; + let block_header = self.blockchain.expect_header(id.clone())?; self.fetcher.remote_call(RemoteCallRequest { - block: block_hash.clone(), + block: block_hash, + header: block_header, method: method.into(), call_data: call_data.to_vec(), }).into_future().wait() @@ -97,34 +99,17 @@ impl CallExecutor for RemoteCallExecutor } /// Check remote execution proof using given backend. -pub fn check_execution_proof( - blockchain: &B, +pub fn check_execution_proof( executor: &E, - request: &RemoteCallRequest, + request: &RemoteCallRequest
, remote_proof: Vec> ) -> ClientResult where - Block: BlockT, - B: ChainBackend, + Header: HeaderT, E: CodeExecutor, { - let local_header = blockchain.header(BlockId::Hash(request.block))?; - let local_header = local_header.ok_or_else(|| ClientErrorKind::UnknownBlock(format!("{}", request.block)))?; - let local_state_root = *local_header.state_root(); - do_check_execution_proof(local_state_root.into(), executor, request, remote_proof) -} + let local_state_root = request.header.state_root(); -/// Check remote execution proof using given state root. -fn do_check_execution_proof( - local_state_root: Hash, - executor: &E, - request: &RemoteCallRequest, - remote_proof: Vec>, -) -> ClientResult - where - Hash: ::std::fmt::Display + ::std::convert::AsRef<[u8]>, - E: CodeExecutor, -{ let mut changes = OverlayedChanges::default(); let (local_result, _) = execution_proof_check( TrieH256::from_slice(local_state_root.as_ref()).into(), @@ -156,8 +141,15 @@ mod tests { // check remote execution proof locally let local_executor = test_client::LocalExecutor::with_heap_pages(8, 8); - do_check_execution_proof(remote_block_storage_root.into(), &local_executor, &RemoteCallRequest { + check_execution_proof(&local_executor, &RemoteCallRequest { block: test_client::runtime::Hash::default(), + header: test_client::runtime::Header { + state_root: remote_block_storage_root.into(), + parent_hash: Default::default(), + number: 0, + extrinsics_root: Default::default(), + digest: Default::default(), + }, method: "authorities".into(), call_data: vec![], }, remote_execution_proof).unwrap(); diff --git a/substrate/client/src/light/fetcher.rs b/substrate/client/src/light/fetcher.rs index 5cda7d766e8f2..07c26a471dee8 100644 --- a/substrate/client/src/light/fetcher.rs +++ b/substrate/client/src/light/fetcher.rs @@ -16,24 +16,22 @@ //! Light client data fetcher. Fetches requested data from remote full nodes. -use std::sync::Arc; use futures::IntoFuture; -use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT}; use state_machine::{CodeExecutor, read_proof_check}; use call_executor::CallResult; -use error::{Error as ClientError, ErrorKind as ClientErrorKind, Result as ClientResult}; -use light::blockchain::{Blockchain, Storage as BlockchainStorage}; +use error::{Error as ClientError, Result as ClientResult}; use light::call_executor::check_execution_proof; -use blockchain::HeaderBackend as BlockchainHeaderBackend; /// Remote call request. #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct RemoteCallRequest { +pub struct RemoteCallRequest { /// Call at state of given block. - pub block: Hash, + pub block: Header::Hash, + /// Head of block at which call is perormed. + pub header: Header, /// Method to call. pub method: String, /// Call data. @@ -42,9 +40,11 @@ pub struct RemoteCallRequest { /// Remote storage read request. #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct RemoteReadRequest { +pub struct RemoteReadRequest { /// Read at state of given block. - pub block: Hash, + pub block: Header::Hash, + /// Head of block at which read is perormed. + pub header: Header, /// Storage key to read. pub key: Vec, } @@ -58,72 +58,64 @@ pub trait Fetcher: Send + Sync { type RemoteCallResult: IntoFuture; /// Fetch remote storage value. - fn remote_read(&self, request: RemoteReadRequest) -> Self::RemoteReadResult; + fn remote_read(&self, request: RemoteReadRequest) -> Self::RemoteReadResult; /// Fetch remote call result. - fn remote_call(&self, request: RemoteCallRequest) -> Self::RemoteCallResult; + fn remote_call(&self, request: RemoteCallRequest) -> Self::RemoteCallResult; } /// Light client remote data checker. +/// +/// Implementations of this trait should not use any blockchain data except that is +/// passed to its methods. pub trait FetchChecker: Send + Sync { /// Check remote storage read proof. fn check_read_proof( &self, - request: &RemoteReadRequest, + request: &RemoteReadRequest, remote_proof: Vec> ) -> ClientResult>>; /// Check remote method execution proof. fn check_execution_proof( &self, - request: &RemoteCallRequest, + request: &RemoteCallRequest, remote_proof: Vec> ) -> ClientResult; } /// Remote data checker. -pub struct LightDataChecker { - blockchain: Arc>, +pub struct LightDataChecker { executor: E, } -impl LightDataChecker { +impl LightDataChecker { /// Create new light data checker. - pub fn new(blockchain: Arc>, executor: E) -> Self { + pub fn new(executor: E) -> Self { Self { - blockchain, executor, } } - - /// Get blockchain reference. - pub fn blockchain(&self) -> &Arc> { - &self.blockchain - } } -impl FetchChecker for LightDataChecker +impl FetchChecker for LightDataChecker where Block: BlockT, Block::Hash: Into<[u8; 32]>, - S: BlockchainStorage, E: CodeExecutor, - F: Fetcher, { fn check_read_proof( &self, - request: &RemoteReadRequest, + request: &RemoteReadRequest, remote_proof: Vec> ) -> ClientResult>> { - let local_header = self.blockchain.header(BlockId::Hash(request.block))?; - let local_header = local_header.ok_or_else(|| ClientErrorKind::UnknownBlock(format!("{}", request.block)))?; - let local_state_root = *local_header.state_root(); + let local_state_root = request.header.state_root().clone(); read_proof_check(local_state_root.into(), remote_proof, &request.key).map_err(Into::into) } fn check_execution_proof( &self, - request: &RemoteCallRequest, + request: &RemoteCallRequest, remote_proof: Vec> ) -> ClientResult { - check_execution_proof(&*self.blockchain, &self.executor, request, remote_proof) + check_execution_proof(&self.executor, request, remote_proof) } } diff --git a/substrate/client/src/light/mod.rs b/substrate/client/src/light/mod.rs index 40b54cdd634ce..57bd8ce45beb7 100644 --- a/substrate/client/src/light/mod.rs +++ b/substrate/client/src/light/mod.rs @@ -62,14 +62,11 @@ pub fn new_light( } /// Create an instance of fetch data checker. -pub fn new_fetch_checker( - blockchain: Arc>, +pub fn new_fetch_checker( executor: E, -) -> LightDataChecker +) -> LightDataChecker where - B: BlockT, - S: BlockchainStorage, E: CodeExecutor, { - LightDataChecker::new(blockchain, executor) + LightDataChecker::new(executor) } diff --git a/substrate/network/src/on_demand.rs b/substrate/network/src/on_demand.rs index 069cd84c5c658..05aa1d7716fd3 100644 --- a/substrate/network/src/on_demand.rs +++ b/substrate/network/src/on_demand.rs @@ -80,8 +80,8 @@ struct Request { } enum RequestData { - RemoteRead(RemoteReadRequest, Sender>, client::error::Error>>), - RemoteCall(RemoteCallRequest, Sender>), + RemoteRead(RemoteReadRequest, Sender>, client::error::Error>>), + RemoteCall(RemoteCallRequest, Sender>), } enum Accept { @@ -235,13 +235,13 @@ impl Fetcher for OnDemand where type RemoteReadResult = RemoteResponse>>; type RemoteCallResult = RemoteResponse; - fn remote_read(&self, request: RemoteReadRequest) -> Self::RemoteReadResult { + fn remote_read(&self, request: RemoteReadRequest) -> Self::RemoteReadResult { let (sender, receiver) = channel(); self.schedule_request(RequestData::RemoteRead(request, sender), RemoteResponse { receiver }) } - fn remote_call(&self, request: RemoteCallRequest) -> Self::RemoteCallResult { + fn remote_call(&self, request: RemoteCallRequest) -> Self::RemoteCallResult { let (sender, receiver) = channel(); self.schedule_request(RequestData::RemoteCall(request, sender), RemoteResponse { receiver }) @@ -363,7 +363,7 @@ pub mod tests { use service::{Roles, ExecuteInContext}; use test::TestIo; use super::{REQUEST_TIMEOUT, OnDemand, OnDemandService}; - use test_client::runtime::{Block, Hash}; + use test_client::runtime::{Block, Header}; pub struct DummyExecutor; struct DummyFetchChecker { ok: bool } @@ -373,14 +373,14 @@ pub mod tests { } impl FetchChecker for DummyFetchChecker { - fn check_read_proof(&self, _request: &RemoteReadRequest, _remote_proof: Vec>) -> client::error::Result>> { + fn check_read_proof(&self, _request: &RemoteReadRequest
, _remote_proof: Vec>) -> client::error::Result>> { match self.ok { true => Ok(Some(vec![42])), false => Err(client::error::ErrorKind::Backend("Test error".into()).into()), } } - fn check_execution_proof(&self, _request: &RemoteCallRequest, _remote_proof: Vec>) -> client::error::Result { + fn check_execution_proof(&self, _request: &RemoteCallRequest
, _remote_proof: Vec>) -> client::error::Result { match self.ok { true => Ok(client::CallResult { return_data: vec![42], @@ -410,6 +410,16 @@ pub mod tests { }); } + fn dummy_header() -> Header { + Header { + parent_hash: Default::default(), + number: 0, + state_root: Default::default(), + extrinsics_root: Default::default(), + digest: Default::default(), + } + } + #[test] fn knows_about_peers_roles() { let (_, on_demand) = dummy(true); @@ -439,7 +449,12 @@ pub mod tests { assert_eq!(vec![0, 1], on_demand.core.lock().idle_peers.iter().cloned().collect::>()); assert!(on_demand.core.lock().active_peers.is_empty()); - on_demand.remote_call(RemoteCallRequest { block: Default::default(), method: "test".into(), call_data: vec![] }); + on_demand.remote_call(RemoteCallRequest { + block: Default::default(), + header: dummy_header(), + method: "test".into(), + call_data: vec![], + }); assert_eq!(vec![1], on_demand.core.lock().idle_peers.iter().cloned().collect::>()); assert_eq!(vec![0], on_demand.core.lock().active_peers.keys().cloned().collect::>()); @@ -457,7 +472,12 @@ pub mod tests { let mut network = TestIo::new(&queue, None); on_demand.on_connect(0, Roles::FULL); - on_demand.remote_call(RemoteCallRequest { block: Default::default(), method: "test".into(), call_data: vec![] }); + on_demand.remote_call(RemoteCallRequest { + block: Default::default(), + header: dummy_header(), + method: "test".into(), + call_data: vec![], + }); receive_call_response(&*on_demand, &mut network, 0, 1); assert!(network.to_disconnect.contains(&0)); assert_eq!(on_demand.core.lock().pending_requests.len(), 1); @@ -468,7 +488,12 @@ pub mod tests { let (_x, on_demand) = dummy(false); let queue = RwLock::new(VecDeque::new()); let mut network = TestIo::new(&queue, None); - on_demand.remote_call(RemoteCallRequest { block: Default::default(), method: "test".into(), call_data: vec![] }); + on_demand.remote_call(RemoteCallRequest { + block: Default::default(), + header: dummy_header(), + method: "test".into(), + call_data: vec![], + }); on_demand.on_connect(0, Roles::FULL); receive_call_response(&*on_demand, &mut network, 0, 0); @@ -494,7 +519,12 @@ pub mod tests { let mut network = TestIo::new(&queue, None); on_demand.on_connect(0, Roles::FULL); - let response = on_demand.remote_call(RemoteCallRequest { block: Default::default(), method: "test".into(), call_data: vec![] }); + let response = on_demand.remote_call(RemoteCallRequest { + block: Default::default(), + header: dummy_header(), + method: "test".into(), + call_data: vec![], + }); let thread = ::std::thread::spawn(move || { let result = response.wait().unwrap(); assert_eq!(result.return_data, vec![42]); diff --git a/substrate/service/src/components.rs b/substrate/service/src/components.rs index 058ea13dc7b84..a6c83db888206 100644 --- a/substrate/service/src/components.rs +++ b/substrate/service/src/components.rs @@ -239,7 +239,7 @@ impl Components for LightComponents }; let db_storage = client_db::light::LightStorage::new(db_settings)?; let light_blockchain = client::light::new_light_blockchain(db_storage); - let fetch_checker = Arc::new(client::light::new_fetch_checker(light_blockchain.clone(), executor)); + let fetch_checker = Arc::new(client::light::new_fetch_checker(executor)); let fetcher = Arc::new(network::OnDemand::new(fetch_checker)); let client_backend = client::light::new_light_backend(light_blockchain, fetcher.clone()); let client = client::light::new_light(client_backend, fetcher.clone(), &config.chain_spec)?; diff --git a/substrate/state-machine/src/lib.rs b/substrate/state-machine/src/lib.rs index ab8d5b575d7ef..71a22b7b710fc 100644 --- a/substrate/state-machine/src/lib.rs +++ b/substrate/state-machine/src/lib.rs @@ -426,7 +426,7 @@ pub fn prove_read( let result = proving_backend.storage(key).map_err(|e| Box::new(e) as Box)?; Ok((result, proving_backend.extract_proof())) } - /// Check storage read proof, generated by `prove` call. + /// Check storage read proof, generated by `prove_read` call. pub fn read_proof_check( root: [u8; 32], proof: Vec>, From 304f307349f863b09a9969c93d2787ca660b629b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Aug 2018 12:48:28 +0200 Subject: [PATCH 3/3] Update lib.rs --- substrate/state-machine/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/state-machine/src/lib.rs b/substrate/state-machine/src/lib.rs index a2817b77f5f93..9b0afc37bb00e 100644 --- a/substrate/state-machine/src/lib.rs +++ b/substrate/state-machine/src/lib.rs @@ -418,7 +418,8 @@ pub fn prove_read( let result = proving_backend.storage(key).map_err(|e| Box::new(e) as Box)?; Ok((result, proving_backend.extract_proof())) } - /// Check storage read proof, generated by `prove_read` call. + +/// Check storage read proof, generated by `prove_read` call. pub fn read_proof_check( root: [u8; 32], proof: Vec>,