use alloc::vec::Vec;
use codec::{Decode, Encode};
use sp_core::Hasher;
use sp_runtime::DispatchError;
pub use sp_runtime::proving_trie::*;
pub trait VerifyExistenceProof {
type Proof;
type Hash;
fn verify_proof(proof: Self::Proof, root: &Self::Hash) -> Result<Vec<u8>, DispatchError>;
}
pub struct BinaryMerkleTreeProver<H>(core::marker::PhantomData<H>);
impl<H: Hasher> VerifyExistenceProof for BinaryMerkleTreeProver<H>
where
H::Out: Decode + Encode,
{
type Proof = binary_merkle_tree::MerkleProof<H::Out, Vec<u8>>;
type Hash = H::Out;
fn verify_proof(proof: Self::Proof, root: &Self::Hash) -> Result<Vec<u8>, DispatchError> {
if proof.root != *root {
return Err(TrieError::RootMismatch.into());
}
if binary_merkle_tree::verify_proof::<H, _, _>(
&proof.root,
proof.proof,
proof.number_of_leaves,
proof.leaf_index,
&proof.leaf,
) {
Ok(proof.leaf)
} else {
Err(TrieError::IncompleteProof.into())
}
}
}
impl<H: Hasher> ProofToHashes for BinaryMerkleTreeProver<H> {
type Proof = binary_merkle_tree::MerkleProof<H::Out, Vec<u8>>;
fn proof_to_hashes(proof: &Self::Proof) -> Result<u32, DispatchError> {
let depth = proof.proof.len();
Ok(depth as u32)
}
}
#[derive(Encode, Decode, Clone)]
pub struct SixteenPatriciaMerkleTreeExistenceProof {
pub key: Vec<u8>,
pub value: Vec<u8>,
pub proof: Vec<Vec<u8>>,
}
pub struct SixteenPatriciaMerkleTreeProver<H>(core::marker::PhantomData<H>);
impl<H: Hasher> VerifyExistenceProof for SixteenPatriciaMerkleTreeProver<H> {
type Proof = SixteenPatriciaMerkleTreeExistenceProof;
type Hash = H::Out;
fn verify_proof(proof: Self::Proof, root: &Self::Hash) -> Result<Vec<u8>, DispatchError> {
sp_trie::verify_trie_proof::<sp_trie::LayoutV1<H>, _, _, _>(
&root,
&proof.proof,
[&(&proof.key, Some(&proof.value))],
)
.map_err(|err| TrieError::from(err).into())
.map(|_| proof.value)
}
}
impl<H: Hasher> ProofToHashes for SixteenPatriciaMerkleTreeProver<H> {
type Proof = SixteenPatriciaMerkleTreeExistenceProof;
fn proof_to_hashes(proof: &Self::Proof) -> Result<u32, DispatchError> {
let depth = proof.proof.len();
Ok(depth as u32)
}
}
#[cfg(test)]
mod tests {
use super::*;
use sp_runtime::{
proving_trie::{base16::BasicProvingTrie, ProvingTrie},
traits::BlakeTwo256,
};
#[test]
fn verify_binary_merkle_tree_prover_works() {
let proof = binary_merkle_tree::merkle_proof::<BlakeTwo256, _, _>(
vec![b"hey".encode(), b"yes".encode()],
1,
);
let root = proof.root;
assert_eq!(
BinaryMerkleTreeProver::<BlakeTwo256>::verify_proof(proof, &root).unwrap(),
b"yes".encode()
);
}
#[test]
fn verify_sixteen_patricia_merkle_tree_prover_works() {
let trie = BasicProvingTrie::<BlakeTwo256, u32, _>::generate_for(vec![
(0u32, String::from("hey")),
(1u32, String::from("yes")),
])
.unwrap();
let proof = trie.create_proof(&1u32).unwrap();
let structured_proof: Vec<Vec<u8>> = Decode::decode(&mut &proof[..]).unwrap();
let root = *trie.root();
let proof = SixteenPatriciaMerkleTreeExistenceProof {
key: 1u32.encode(),
value: String::from("yes").encode(),
proof: structured_proof,
};
assert_eq!(
SixteenPatriciaMerkleTreeProver::<BlakeTwo256>::verify_proof(proof, &root).unwrap(),
String::from("yes").encode()
);
}
#[test]
fn proof_to_hashes_sixteen() {
let mut i: u32 = 1;
let log16 = |x: u32| -> u32 {
let x_f64 = x as f64;
let log16_x = (x_f64.ln() / 16_f64.ln()).ceil();
log16_x as u32
};
while i < 10_000_000 {
let trie = BasicProvingTrie::<BlakeTwo256, u32, _>::generate_for(
(0..i).map(|i| (i, u128::from(i))),
)
.unwrap();
let proof = trie.create_proof(&0).unwrap();
let structured_proof: Vec<Vec<u8>> = Decode::decode(&mut &proof[..]).unwrap();
let root = *trie.root();
let proof = SixteenPatriciaMerkleTreeExistenceProof {
key: 0u32.encode(),
value: 0u128.encode(),
proof: structured_proof,
};
let hashes =
SixteenPatriciaMerkleTreeProver::<BlakeTwo256>::proof_to_hashes(&proof).unwrap();
let log16 = log16(i).max(1);
assert_eq!(hashes, log16);
assert_eq!(
SixteenPatriciaMerkleTreeProver::<BlakeTwo256>::verify_proof(proof.clone(), &root)
.unwrap(),
proof.value
);
i = i * 10;
}
}
#[test]
fn proof_to_hashes_binary() {
let mut i: u32 = 1;
while i < 10_000_000 {
let proof = binary_merkle_tree::merkle_proof::<BlakeTwo256, _, _>(
(0..i).map(|i| u128::from(i).encode()),
0,
);
let root = proof.root;
let hashes = BinaryMerkleTreeProver::<BlakeTwo256>::proof_to_hashes(&proof).unwrap();
let log2 = (i as f64).log2().ceil() as u32;
assert_eq!(hashes, log2);
assert_eq!(
BinaryMerkleTreeProver::<BlakeTwo256>::verify_proof(proof, &root).unwrap(),
0u128.encode()
);
i = i * 10;
}
}
}