Skip to content

Commit

Permalink
Introduces VerifyExistenceProof trait (#5682)
Browse files Browse the repository at this point in the history
Introduces a trait for verifying existence proofs in the runtime. The
trait is implemented for the 16 patricia merkle tree and the binary
tree.

---------

Co-authored-by: Shawn Tabrizi <[email protected]>
Co-authored-by: command-bot <>
  • Loading branch information
bkchr and shawntabrizi authored Sep 16, 2024
1 parent 51f3367 commit 316b7a7
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 33 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions prdoc/pr_5682.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
title: Introduces `VerifyExistenceProof` trait

doc:
- audience: Runtime Dev
description: |
Introduces `VerifyExistenceProof` trait for verifying proofs in the runtime.
An implementation of the trait for binary and 16 patricia merkle tree is provided.

crates:
- name: binary-merkle-tree
bump: major
- name: sp-runtime
bump: patch
- name: frame-support
bump: minor
4 changes: 4 additions & 0 deletions substrate/frame/support/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
array-bytes = { workspace = true }
binary-merkle-tree.workspace = true
serde = { features = ["alloc", "derive"], workspace = true }
codec = { features = [
"derive",
Expand Down Expand Up @@ -44,6 +45,7 @@ sp-staking = { workspace = true }
sp-weights = { workspace = true }
sp-debug-derive = { workspace = true }
sp-metadata-ir = { workspace = true }
sp-trie = { workspace = true }
tt-call = { workspace = true }
macro_magic = { workspace = true }
frame-support-procedural = { workspace = true }
Expand Down Expand Up @@ -73,6 +75,7 @@ sp-crypto-hashing = { workspace = true, default-features = true }
[features]
default = ["std"]
std = [
"binary-merkle-tree/std",
"codec/std",
"environmental/std",
"frame-metadata/std",
Expand All @@ -97,6 +100,7 @@ std = [
"sp-std/std",
"sp-timestamp/std",
"sp-tracing/std",
"sp-trie/std",
"sp-weights/std",
]
runtime-benchmarks = [
Expand Down
3 changes: 3 additions & 0 deletions substrate/frame/support/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ pub mod dynamic_params;
pub mod tasks;
pub use tasks::Task;

mod proving;
pub use proving::*;

#[cfg(feature = "try-runtime")]
mod try_runtime;
#[cfg(feature = "try-runtime")]
Expand Down
135 changes: 135 additions & 0 deletions substrate/frame/support/src/traits/proving.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// This file is part of Substrate.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Provides functionality for verifying proofs.
use alloc::vec::Vec;
use codec::{Decode, Encode};
use sp_core::Hasher;

/// Something that can verify the existence of some data in a given proof.
pub trait VerifyExistenceProof {
/// The proof type.
type Proof;
/// The hash type.
type Hash;

/// Verify the given `proof`.
///
/// Ensures that the `proof` was build for `root` and returns the proved data.
fn verify_proof(proof: Self::Proof, root: &Self::Hash) -> Result<Vec<u8>, ()>;
}

/// Implements [`VerifyExistenceProof`] using a binary merkle tree.
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>, ()> {
if proof.root != *root {
return Err(());
}

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(())
}
}
}

/// Proof used by [`SixteenPatriciaMerkleTreeProver`] for [`VerifyExistenceProof`].
#[derive(Encode, Decode)]
pub struct SixteenPatriciaMerkleTreeExistenceProof {
/// The key of the value to prove.
pub key: Vec<u8>,
/// The value for that the existence is proved.
pub value: Vec<u8>,
/// The encoded nodes to prove the existence of the data under `key`.
pub proof: Vec<Vec<u8>>,
}

/// Implements [`VerifyExistenceProof`] using a 16-patricia merkle tree.
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>, ()> {
sp_trie::verify_trie_proof::<sp_trie::LayoutV1<H>, _, _, _>(
&root,
&proof.proof,
[&(&proof.key, Some(&proof.value))],
)
.map_err(drop)
.map(|_| proof.value)
}
}

#[cfg(test)]
mod tests {
use super::*;
use sp_runtime::{proving_trie::BasicProvingTrie, 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, &[u8]>::generate_for(vec![
(0u32, &b"hey"[..]),
(1u32, &b"yes"[..]),
])
.unwrap();
let proof = trie.create_single_value_proof(1u32).unwrap();
let root = *trie.root();

let proof = SixteenPatriciaMerkleTreeExistenceProof {
key: 1u32.encode(),
value: b"yes"[..].encode(),
proof,
};

assert_eq!(
SixteenPatriciaMerkleTreeProver::<BlakeTwo256>::verify_proof(proof, &root).unwrap(),
b"yes"[..].encode()
);
}
}
7 changes: 5 additions & 2 deletions substrate/primitives/runtime/src/proving_trie.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ impl<Hashing, Key, Value> BasicProvingTrie<Hashing, Key, Value>
where
Hashing: sp_core::Hasher,
Key: Encode,
Value: Encode + Decode,
Value: Encode,
{
/// Create a new instance of a `ProvingTrie` using an iterator of key/value pairs.
pub fn generate_for<I>(items: I) -> Result<Self, DispatchError>
Expand Down Expand Up @@ -167,7 +167,10 @@ where

/// Query a value contained within the current trie. Returns `None` if the
/// nodes within the current `MemoryDB` are insufficient to query the item.
pub fn query(&self, key: Key) -> Option<Value> {
pub fn query(&self, key: Key) -> Option<Value>
where
Value: Decode,
{
let trie = TrieDBBuilder::new(&self.db, &self.root).build();
key.using_encoded(|s| trie.get(s))
.ok()?
Expand Down
9 changes: 8 additions & 1 deletion substrate/utils/binary-merkle-tree/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ homepage.workspace = true
workspace = true

[dependencies]
codec = { workspace = true, features = ["derive"] }
array-bytes = { optional = true, workspace = true, default-features = true }
log = { optional = true, workspace = true }
hash-db = { workspace = true }
Expand All @@ -25,4 +26,10 @@ sp-runtime = { workspace = true, default-features = true }
[features]
debug = ["array-bytes", "log"]
default = ["debug", "std"]
std = ["hash-db/std", "log/std", "sp-core/std", "sp-runtime/std"]
std = [
"codec/std",
"hash-db/std",
"log/std",
"sp-core/std",
"sp-runtime/std",
]
Loading

0 comments on commit 316b7a7

Please sign in to comment.