storage_proof_primitives/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
18
19use cumulus_primitives_core::relay_chain;
20use sp_core::H256;
21use sp_runtime::traits::{Hash, HashingFor};
22use sp_state_machine::{Backend, TrieBackend, TrieBackendBuilder};
23use sp_std::vec::Vec;
24use sp_trie::{HashDBT, MemoryDB, StorageProof, EMPTY_PREFIX};
25
26#[cfg(test)]
27mod tests;
28
29#[derive(Debug, PartialEq)]
30pub enum ProofError {
31 RootMismatch,
33 Proof,
35 Absent,
37 BlockNumberNotPresent,
39}
40
41pub type RawStorageProof = Vec<Vec<u8>>;
42
43#[derive(Debug)]
46pub struct StorageProofChecker<H>
47where
48 H: Hash,
49{
50 trie_backend: TrieBackend<MemoryDB<H>, H>,
51}
52
53impl<H: Hash> StorageProofChecker<H> {
54 pub fn new(
57 storage_root: H::Out,
58 raw_proof: impl IntoIterator<Item = Vec<u8>>,
59 ) -> Result<Self, ProofError> {
60 let storage_proof = StorageProof::new(raw_proof);
61 let db = storage_proof.into_memory_db::<H>();
62
63 if !db.contains(&storage_root, EMPTY_PREFIX) {
64 return Err(ProofError::RootMismatch);
65 }
66 let trie_backend = TrieBackendBuilder::new(db, storage_root).build();
67
68 Ok(Self { trie_backend })
69 }
70
71 pub fn read_entry(&self, key: &[u8]) -> Result<Vec<u8>, ProofError> {
75 self.trie_backend
76 .storage(key)
77 .map_err(|_| ProofError::Proof)?
78 .ok_or(ProofError::Absent)
79 }
80
81 pub fn read_entries(&self, keys: &[&[u8]]) -> Result<Vec<Vec<u8>>, ProofError> {
82 let mut values = Vec::new();
83 for key in keys {
84 let value = self.read_entry(key)?;
85 values.push(value);
86 }
87 Ok(values)
88 }
89}
90
91pub fn verify_entry(
92 expected_root: H256,
93 proof: impl IntoIterator<Item = Vec<u8>>,
94 key: &[u8],
95) -> Result<Vec<u8>, ProofError> {
96 let proof_checker =
97 StorageProofChecker::<HashingFor<relay_chain::Block>>::new(expected_root, proof)?;
98
99 proof_checker.read_entry(key)
100}
101
102pub fn verify_entries(
103 expected_root: H256,
104 proof: impl IntoIterator<Item = Vec<u8>>,
105 keys: &[&[u8]],
106) -> Result<Vec<Vec<u8>>, ProofError> {
107 let proof_checker =
108 StorageProofChecker::<HashingFor<relay_chain::Block>>::new(expected_root, proof)?;
109
110 proof_checker.read_entries(keys)
111}