mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 05:51:02 +00:00
Create opaque struct for StorageProof. (#3834)
Passing around Vec<Vec<u8>> everywhere is gross and confusing and breaks encapsulation.
This commit is contained in:
committed by
Bastian Köcher
parent
073040a053
commit
a167f37b91
@@ -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<B, H, Exec>(
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
keystore: Option<KeystoreExt>,
|
||||
) -> Result<(Vec<u8>, Vec<Vec<u8>>), Box<dyn Error>>
|
||||
) -> Result<(Vec<u8>, StorageProof), Box<dyn Error>>
|
||||
where
|
||||
B: Backend<H>,
|
||||
H: Hasher<Out=H256>,
|
||||
@@ -490,7 +490,7 @@ pub fn prove_execution_on_trie_backend<S, H, Exec>(
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
keystore: Option<KeystoreExt>,
|
||||
) -> Result<(Vec<u8>, Vec<Vec<u8>>), Box<dyn Error>>
|
||||
) -> Result<(Vec<u8>, StorageProof), Box<dyn Error>>
|
||||
where
|
||||
S: trie_backend_essence::TrieBackendStorage<H>,
|
||||
H: Hasher<Out=H256>,
|
||||
@@ -513,7 +513,7 @@ where
|
||||
/// Check execution proof, generated by `prove_execution` call.
|
||||
pub fn execution_proof_check<H, Exec>(
|
||||
root: H::Out,
|
||||
proof: Vec<Vec<u8>>,
|
||||
proof: StorageProof,
|
||||
overlay: &mut OverlayedChanges,
|
||||
exec: &Exec,
|
||||
method: &str,
|
||||
@@ -557,7 +557,7 @@ where
|
||||
pub fn prove_read<B, H, I>(
|
||||
mut backend: B,
|
||||
keys: I,
|
||||
) -> Result<Vec<Vec<u8>>, Box<dyn Error>>
|
||||
) -> Result<StorageProof, Box<dyn Error>>
|
||||
where
|
||||
B: Backend<H>,
|
||||
H: Hasher<Out=H256>,
|
||||
@@ -577,7 +577,7 @@ pub fn prove_child_read<B, H, I>(
|
||||
mut backend: B,
|
||||
storage_key: &[u8],
|
||||
keys: I,
|
||||
) -> Result<Vec<Vec<u8>>, Box<dyn Error>>
|
||||
) -> Result<StorageProof, Box<dyn Error>>
|
||||
where
|
||||
B: Backend<H>,
|
||||
H: Hasher,
|
||||
@@ -594,7 +594,7 @@ where
|
||||
pub fn prove_read_on_trie_backend<S, H, I>(
|
||||
trie_backend: &TrieBackend<S, H>,
|
||||
keys: I,
|
||||
) -> Result<Vec<Vec<u8>>, Box<dyn Error>>
|
||||
) -> Result<StorageProof, Box<dyn Error>>
|
||||
where
|
||||
S: trie_backend_essence::TrieBackendStorage<H>,
|
||||
H: Hasher,
|
||||
@@ -616,7 +616,7 @@ pub fn prove_child_read_on_trie_backend<S, H, I>(
|
||||
trie_backend: &TrieBackend<S, H>,
|
||||
storage_key: &[u8],
|
||||
keys: I,
|
||||
) -> Result<Vec<Vec<u8>>, Box<dyn Error>>
|
||||
) -> Result<StorageProof, Box<dyn Error>>
|
||||
where
|
||||
S: trie_backend_essence::TrieBackendStorage<H>,
|
||||
H: Hasher,
|
||||
@@ -636,7 +636,7 @@ where
|
||||
/// Check storage read proof, generated by `prove_read` call.
|
||||
pub fn read_proof_check<H, I>(
|
||||
root: H::Out,
|
||||
proof: Vec<Vec<u8>>,
|
||||
proof: StorageProof,
|
||||
keys: I,
|
||||
) -> Result<HashMap<Vec<u8>, Option<Vec<u8>>>, Box<dyn Error>>
|
||||
where
|
||||
@@ -657,7 +657,7 @@ where
|
||||
/// Check child storage read proof, generated by `prove_child_read` call.
|
||||
pub fn read_child_proof_check<H, I>(
|
||||
root: H::Out,
|
||||
proof: Vec<Vec<u8>>,
|
||||
proof: StorageProof,
|
||||
storage_key: &[u8],
|
||||
keys: I,
|
||||
) -> Result<HashMap<Vec<u8>, Option<Vec<u8>>>, Box<dyn Error>>
|
||||
|
||||
@@ -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<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl StorageProof {
|
||||
/// Constructs a storage proof from a subset of encoded trie nodes in a storage backend.
|
||||
pub fn new(trie_nodes: Vec<Vec<u8>>) -> 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: <Vec<Vec<u8>> as IntoIterator>::IntoIter,
|
||||
}
|
||||
|
||||
impl StorageProofNodeIterator {
|
||||
fn new(proof: StorageProof) -> Self {
|
||||
StorageProofNodeIterator {
|
||||
inner: proof.trie_nodes.into_iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for StorageProofNodeIterator {
|
||||
type Item = Vec<u8>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
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<I>(proofs: I) -> StorageProof
|
||||
where I: IntoIterator<Item=StorageProof>
|
||||
{
|
||||
let trie_nodes = proofs.into_iter()
|
||||
.flat_map(|proof| proof.iter_nodes())
|
||||
.collect::<HashSet<_>>()
|
||||
.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>, H: 'a + Hasher> {
|
||||
@@ -129,13 +206,14 @@ impl<'a, S: 'a + TrieBackendStorage<H>, 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<Vec<u8>> {
|
||||
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<H> for ProvingBackend<'a, S, H>
|
||||
/// Create proof check backend.
|
||||
pub fn create_proof_check_backend<H>(
|
||||
root: H::Out,
|
||||
proof: Vec<Vec<u8>>
|
||||
proof: StorageProof,
|
||||
) -> Result<TrieBackend<MemoryDB<H>, H>, Box<dyn Error>>
|
||||
where
|
||||
H: Hasher,
|
||||
@@ -233,13 +311,13 @@ where
|
||||
|
||||
/// Create in-memory storage of proof check backend.
|
||||
pub fn create_proof_check_backend_storage<H>(
|
||||
proof: Vec<Vec<u8>>
|
||||
proof: StorageProof,
|
||||
) -> MemoryDB<H>
|
||||
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::<Blake2Hasher>(H256::from_low_u64_be(1), vec![]).is_err());
|
||||
let result = create_proof_check_backend::<Blake2Hasher>(
|
||||
H256::from_low_u64_be(1),
|
||||
StorageProof::empty()
|
||||
);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user