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
+15 -1
View File
@@ -52,7 +52,7 @@ use primitives::storage::well_known_keys;
use parity_codec::{Encode, Decode};
use state_machine::{
DBValue, Backend as StateBackend, CodeExecutor, ChangesTrieAnchorBlockId,
ExecutionStrategy, ExecutionManager, prove_read,
ExecutionStrategy, ExecutionManager, prove_read, prove_child_read,
ChangesTrieRootsStorage, ChangesTrieStorage,
key_changes, key_changes_proof, OverlayedChanges, NeverOffchainExt,
};
@@ -374,6 +374,20 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
.map_err(Into::into))
}
/// Reads child storage value at a given block + storage_key + key, returning
/// read proof.
pub fn read_child_proof(
&self,
id: &BlockId<Block>,
storage_key: &[u8],
key: &[u8]
) -> error::Result<Vec<Vec<u8>>> {
self.state_at(id)
.and_then(|state| prove_child_read(state, storage_key, 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.
///
+9 -14
View File
@@ -24,7 +24,7 @@ use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero,
NumberFor, As, Digest, DigestItem};
use runtime_primitives::{Justification, StorageOverlay, ChildrenStorageOverlay};
use state_machine::backend::{Backend as StateBackend, InMemory, Consolidate};
use state_machine::backend::{Backend as StateBackend, InMemory};
use state_machine::{self, InMemoryChangesTrieStorage, ChangesTrieAnchorBlockId};
use hash_db::Hasher;
use trie::MemoryDB;
@@ -482,22 +482,17 @@ where
Ok(())
}
fn reset_storage(&mut self, mut top: StorageOverlay, children: ChildrenStorageOverlay) -> error::Result<H::Out> {
fn reset_storage(&mut self, top: StorageOverlay, children: ChildrenStorageOverlay) -> error::Result<H::Out> {
check_genesis_storage(&top, &children)?;
let mut transaction: Vec<(Option<Vec<u8>>, Vec<u8>, Option<Vec<u8>>)> = Default::default();
let child_delta = children.into_iter()
.map(|(storage_key, child_overlay)|
(storage_key, child_overlay.into_iter().map(|(k, v)| (k, Some(v)))));
for (child_key, child_map) in children {
let (root, is_default, update) = self.old_state.child_storage_root(&child_key, child_map.into_iter().map(|(k, v)| (k, Some(v))));
transaction.consolidate(update);
if !is_default {
top.insert(child_key, root);
}
}
let (root, update) = self.old_state.storage_root(top.into_iter().map(|(k, v)| (k, Some(v))));
transaction.consolidate(update);
let (root, transaction) = self.old_state.full_storage_root(
top.into_iter().map(|(k, v)| (k, Some(v))),
child_delta
);
self.new_state = Some(InMemory::from(transaction));
Ok(root)
+49 -2
View File
@@ -25,7 +25,8 @@ use hash_db::{HashDB, Hasher};
use primitives::{ChangesTrieConfiguration, convert_hash};
use runtime_primitives::traits::{As, Block as BlockT, Header as HeaderT, NumberFor};
use state_machine::{CodeExecutor, ChangesTrieRootsStorage, ChangesTrieAnchorBlockId,
TrieBackend, read_proof_check, key_changes_proof_check, create_proof_check_backend_storage};
TrieBackend, read_proof_check, key_changes_proof_check,
create_proof_check_backend_storage, read_child_proof_check};
use crate::cht;
use crate::error::{Error as ClientError, Result as ClientResult};
@@ -71,6 +72,21 @@ pub struct RemoteReadRequest<Header: HeaderT> {
pub retry_count: Option<usize>,
}
/// Remote storage read child request.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct RemoteReadChildRequest<Header: HeaderT> {
/// Read at state of given block.
pub block: Header::Hash,
/// Header of block at which read is performed.
pub header: Header,
/// Storage key for child.
pub storage_key: Vec<u8>,
/// Child storage key to read.
pub key: Vec<u8>,
/// Number of times to retry request. None means that default RETRY_COUNT is used.
pub retry_count: Option<usize>,
}
/// Remote key changes read request.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RemoteChangesRequest<Header: HeaderT> {
@@ -123,7 +139,15 @@ pub trait Fetcher<Block: BlockT>: Send + Sync {
/// Fetch remote header.
fn remote_header(&self, request: RemoteHeaderRequest<Block::Header>) -> Self::RemoteHeaderResult;
/// Fetch remote storage value.
fn remote_read(&self, request: RemoteReadRequest<Block::Header>) -> Self::RemoteReadResult;
fn remote_read(
&self,
request: RemoteReadRequest<Block::Header>
) -> Self::RemoteReadResult;
/// Fetch remote storage child value.
fn remote_read_child(
&self,
request: RemoteReadChildRequest<Block::Header>
) -> Self::RemoteReadResult;
/// Fetch remote call result.
fn remote_call(&self, request: RemoteCallRequest<Block::Header>) -> Self::RemoteCallResult;
/// Fetch remote changes ((block number, extrinsic index)) where given key has been changed
@@ -149,6 +173,12 @@ pub trait FetchChecker<Block: BlockT>: Send + Sync {
request: &RemoteReadRequest<Block::Header>,
remote_proof: Vec<Vec<u8>>
) -> ClientResult<Option<Vec<u8>>>;
/// Check remote storage read proof.
fn check_read_child_proof(
&self,
request: &RemoteReadChildRequest<Block::Header>,
remote_proof: Vec<Vec<u8>>
) -> ClientResult<Option<Vec<u8>>>;
/// Check remote method execution proof.
fn check_execution_proof(
&self,
@@ -338,6 +368,19 @@ impl<E, Block, H, S, F> FetchChecker<Block> for LightDataChecker<E, H, Block, S,
.map_err(Into::into)
}
fn check_read_child_proof(
&self,
request: &RemoteReadChildRequest<Block::Header>,
remote_proof: Vec<Vec<u8>>
) -> ClientResult<Option<Vec<u8>>> {
read_child_proof_check::<H>(
convert_hash(request.header.state_root()),
remote_proof,
&request.storage_key,
&request.key)
.map_err(Into::into)
}
fn check_execution_proof(
&self,
request: &RemoteCallRequest<Block::Header>,
@@ -425,6 +468,10 @@ pub mod tests {
err("Not implemented on test node".into())
}
fn remote_read_child(&self, _request: RemoteReadChildRequest<Header>) -> Self::RemoteReadResult {
err("Not implemented on test node".into())
}
fn remote_call(&self, _request: RemoteCallRequest<Header>) -> Self::RemoteCallResult {
ok((*self.lock()).clone())
}