Child trie storage proof (#2433)

* proof on child trie

* higher level api for child storage proof

* boilerplate for proof from light fetch

* actually check proof on light fetch

* Do not break former encoding

* tabify

* tabify2

* Add child trie root tx to full_storage_root transaction.

* Shorten long lines.

* Temp rename for audit

* Make full_storage a trait method

* Name back and replace some code with full_storage where it looks fine.

* fix indentations, remove unused import

* flush child root to top when calculated

* impl +1
This commit is contained in:
cheme
2019-05-10 14:31:41 +02:00
committed by Gavin Wood
parent 59be403730
commit 0d8379d5d2
14 changed files with 475 additions and 103 deletions
+18 -3
View File
@@ -23,7 +23,7 @@ pub use self::generic::{
BlockAnnounce, RemoteCallRequest, RemoteReadRequest,
RemoteHeaderRequest, RemoteHeaderResponse,
RemoteChangesRequest, RemoteChangesResponse,
FromBlock
FromBlock, RemoteReadChildRequest,
};
/// A unique ID of a request.
@@ -129,8 +129,8 @@ pub mod generic {
use runtime_primitives::Justification;
use crate::config::Roles;
use super::{
BlockAttributes, RemoteCallResponse, RemoteReadResponse,
RequestId, Transactions, Direction, ConsensusEngineId,
RemoteReadResponse, Transactions, Direction,
RequestId, BlockAttributes, RemoteCallResponse, ConsensusEngineId,
};
/// Consensus is mostly opaque to us
#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
@@ -198,6 +198,8 @@ pub mod generic {
RemoteChangesRequest(RemoteChangesRequest<Hash>),
/// Remote changes reponse.
RemoteChangesResponse(RemoteChangesResponse<Number, Hash>),
/// Remote child storage read request.
RemoteReadChildRequest(RemoteReadChildRequest<Hash>),
/// Chain-specific message
#[codec(index = "255")]
ChainSpecific(Vec<u8>),
@@ -291,6 +293,19 @@ pub mod generic {
pub key: Vec<u8>,
}
#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
/// Remote storage read child request.
pub struct RemoteReadChildRequest<H> {
/// Unique request id.
pub id: RequestId,
/// Block at which to perform call.
pub block: H,
/// Child Storage key.
pub storage_key: Vec<u8>,
/// Storage key.
pub key: Vec<u8>,
}
#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
/// Remote header request.
pub struct RemoteHeaderRequest<N> {
+98 -12
View File
@@ -27,7 +27,8 @@ use linked_hash_map::Entry;
use parking_lot::Mutex;
use client::error::Error as ClientError;
use client::light::fetcher::{Fetcher, FetchChecker, RemoteHeaderRequest,
RemoteCallRequest, RemoteReadRequest, RemoteChangesRequest, ChangesProof};
RemoteCallRequest, RemoteReadRequest, RemoteChangesRequest, ChangesProof,
RemoteReadChildRequest};
use crate::message;
use network_libp2p::PeerId;
use crate::config::Roles;
@@ -107,6 +108,10 @@ struct Request<Block: BlockT> {
enum RequestData<Block: BlockT> {
RemoteHeader(RemoteHeaderRequest<Block::Header>, OneShotSender<Result<Block::Header, ClientError>>),
RemoteRead(RemoteReadRequest<Block::Header>, OneShotSender<Result<Option<Vec<u8>>, ClientError>>),
RemoteReadChild(
RemoteReadChildRequest<Block::Header>,
OneShotSender<Result<Option<Vec<u8>>, ClientError>>
),
RemoteCall(RemoteCallRequest<Block::Header>, OneShotSender<Result<Vec<u8>, ClientError>>),
RemoteChanges(RemoteChangesRequest<Block::Header>, OneShotSender<Result<Vec<(NumberFor<Block>, u32)>, ClientError>>),
}
@@ -271,14 +276,30 @@ impl<B> OnDemandService<B> for OnDemand<B> where
fn on_remote_read_response(&self, peer: PeerId, response: message::RemoteReadResponse) {
self.accept_response("read", 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)),
},
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)
),
}},
RequestData::RemoteReadChild(request, sender) => {
match self.checker.check_read_child_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::RemoteReadChild(request, sender)
),
}},
data => Accept::Unexpected(data),
})
}
@@ -335,8 +356,23 @@ impl<B> Fetcher<B> for OnDemand<B> where
fn remote_read(&self, request: RemoteReadRequest<B::Header>) -> Self::RemoteReadResult {
let (sender, receiver) = channel();
self.schedule_request(request.retry_count.clone(), RequestData::RemoteRead(request, sender),
RemoteResponse { receiver })
self.schedule_request(
request.retry_count.clone(),
RequestData::RemoteRead(request, sender),
RemoteResponse { receiver }
)
}
fn remote_read_child(
&self,
request: RemoteReadChildRequest<B::Header>
) -> Self::RemoteReadResult {
let (sender, receiver) = channel();
self.schedule_request(
request.retry_count.clone(),
RequestData::RemoteReadChild(request, sender),
RemoteResponse { receiver }
)
}
fn remote_call(&self, request: RemoteCallRequest<B::Header>) -> Self::RemoteCallResult {
@@ -477,6 +513,7 @@ impl<Block: BlockT> Request<Block> {
match self.data {
RequestData::RemoteHeader(ref data, _) => data.block,
RequestData::RemoteRead(ref data, _) => *data.header.number(),
RequestData::RemoteReadChild(ref data, _) => *data.header.number(),
RequestData::RemoteCall(ref data, _) => *data.header.number(),
RequestData::RemoteChanges(ref data, _) => data.max_block.0,
}
@@ -495,6 +532,14 @@ impl<Block: BlockT> Request<Block> {
block: data.block,
key: data.key.clone(),
}),
RequestData::RemoteReadChild(ref data, _) =>
message::generic::Message::RemoteReadChildRequest(
message::RemoteReadChildRequest {
id: self.id,
block: data.block,
storage_key: data.storage_key.clone(),
key: data.key.clone(),
}),
RequestData::RemoteCall(ref data, _) =>
message::generic::Message::RemoteCallRequest(message::RemoteCallRequest {
id: self.id,
@@ -522,6 +567,7 @@ impl<Block: BlockT> RequestData<Block> {
RequestData::RemoteHeader(_, sender) => { let _ = sender.send(Err(error)); },
RequestData::RemoteCall(_, sender) => { let _ = sender.send(Err(error)); },
RequestData::RemoteRead(_, sender) => { let _ = sender.send(Err(error)); },
RequestData::RemoteReadChild(_, sender) => { let _ = sender.send(Err(error)); },
RequestData::RemoteChanges(_, sender) => { let _ = sender.send(Err(error)); },
}
}
@@ -535,7 +581,8 @@ pub mod tests {
use runtime_primitives::traits::NumberFor;
use client::{error::{Error as ClientError, Result as ClientResult}};
use client::light::fetcher::{Fetcher, FetchChecker, RemoteHeaderRequest,
RemoteCallRequest, RemoteReadRequest, RemoteChangesRequest, ChangesProof};
ChangesProof, RemoteCallRequest, RemoteReadRequest,
RemoteReadChildRequest, RemoteChangesRequest};
use crate::config::Roles;
use crate::message;
use network_libp2p::PeerId;
@@ -566,6 +613,17 @@ pub mod tests {
}
}
fn check_read_child_proof(
&self,
_: &RemoteReadChildRequest<Header>,
_: Vec<Vec<u8>>
) -> ClientResult<Option<Vec<u8>>> {
match self.ok {
true => Ok(Some(vec![42])),
false => Err(ClientError::Backend("Test error".into())),
}
}
fn check_execution_proof(&self, _: &RemoteCallRequest<Header>, _: Vec<Vec<u8>>) -> ClientResult<Vec<u8>> {
match self.ok {
true => Ok(vec![42]),
@@ -847,6 +905,34 @@ pub mod tests {
thread.join().unwrap();
}
#[test]
fn receives_remote_read_child_response() {
let (_x, on_demand) = dummy(true);
let (network_sender, _network_port) = network_channel();
let peer0 = PeerId::random();
on_demand.set_network_sender(network_sender.clone());
on_demand.on_connect(peer0.clone(), Roles::FULL, 1000);
let response = on_demand.remote_read_child(RemoteReadChildRequest {
header: dummy_header(),
block: Default::default(),
storage_key: b":child_storage:sub".to_vec(),
key: b":key".to_vec(),
retry_count: None,
});
let thread = ::std::thread::spawn(move || {
let result = response.wait().unwrap();
assert_eq!(result, Some(vec![42]));
});
on_demand.on_remote_read_response(
peer0.clone(), message::RemoteReadResponse {
id: 0,
proof: vec![vec![2]],
});
thread.join().unwrap();
}
#[test]
fn receives_remote_header_response() {
let (_x, on_demand) = dummy(true);