Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Expose proof generation and verifying api. (#4646)
Browse files Browse the repository at this point in the history
* Expose proof generation and verifying api.

* tabs to spaces

* bring back license comment

* Revert "tabs to spaces"

This reverts commit 4c3f72f.

* Formatting and docs nits

* Bump deps versions

* Upadte Cargo.lock

* into -> in
  • Loading branch information
montekki authored and bkchr committed Jan 17, 2020
1 parent 083ada5 commit 36a6de0
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 29 deletions.
49 changes: 25 additions & 24 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion primitives/state-machine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ edition = "2018"
log = "0.4.8"
parking_lot = "0.9.0"
hash-db = "0.15.2"
trie-db = "0.18.1"
trie-db = "0.19.2"
trie-root = "0.15.2"
sp-trie = { version = "2.0.0", path = "../trie" }
sp-core = { version = "2.0.0", path = "../core" }
Expand Down
6 changes: 3 additions & 3 deletions primitives/trie/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ harness = false
codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false }
sp-std = { version = "2.0.0", default-features = false, path = "../std" }
hash-db = { version = "0.15.2", default-features = false }
trie-db = { version = "0.18.1", default-features = false }
trie-db = { version = "0.19.2", default-features = false }
trie-root = { version = "0.15.2", default-features = false }
memory-db = { version = "0.18.0", default-features = false }
memory-db = { version = "0.18.1", default-features = false }
sp-core = { version = "2.0.0", default-features = false, path = "../core" }

[dev-dependencies]
trie-bench = "0.18.0"
trie-bench = "0.19.0"
trie-standardmap = "0.15.2"
criterion = "0.2.11"
hex-literal = "0.2.1"
Expand Down
128 changes: 128 additions & 0 deletions primitives/trie/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ use sp_std::boxed::Box;
use sp_std::marker::PhantomData;
use sp_std::vec::Vec;
use hash_db::{Hasher, Prefix};
use trie_db::proof::{generate_proof, verify_proof};
pub use trie_db::proof::VerifyError;
/// Our `NodeCodec`-specific error.
pub use error::Error;
/// The Substrate format implementation of `TrieStream`.
Expand Down Expand Up @@ -119,6 +121,47 @@ pub mod trie_types {
pub type TrieError<H> = trie_db::TrieError<H, super::Error>;
}

/// Create a proof for a subset of keys in a trie.
///
/// The `keys` may contain any set of keys regardless of each one of them is included
/// in the `db`.
///
/// For a key `K` that is included in the `db` a proof of inclusion is generated.
/// For a key `K` that is not included in the `db` a proof of non-inclusion is generated.
/// These can be later checked in `verify_trie_proof`.
pub fn generate_trie_proof<'a, L: TrieConfiguration, I, K, DB>(
db: &DB,
root: TrieHash<L>,
keys: I,
) -> Result<Vec<Vec<u8>>, Box<TrieError<L>>> where
I: IntoIterator<Item=&'a K>,
K: 'a + AsRef<[u8]>,
DB: hash_db::HashDBRef<L::Hash, trie_db::DBValue>,
{
let trie = TrieDB::<L>::new(db, &root)?;
generate_proof(&trie, keys)
}

/// Verify a set of key-value pairs against a trie root and a proof.
///
/// Checks a set of keys with optional values for inclusion in the proof that was generated by
/// `generate_trie_proof`.
/// If the value in the pair is supplied (`(key, Some(value))`), this key-value pair will be
/// checked for inclusion in the proof.
/// If the value is omitted (`(key, None)`), this key will be checked for non-inclusion in the
/// proof.
pub fn verify_trie_proof<'a, L: TrieConfiguration, I, K, V>(
root: &TrieHash<L>,
proof: &[Vec<u8>],
items: I,
) -> Result<(), VerifyError<TrieHash<L>, error::Error>> where
I: IntoIterator<Item=&'a (K, Option<V>)>,
K: 'a + AsRef<[u8]>,
V: 'a + AsRef<[u8]>,
{
verify_proof::<Layout<L::Hash>, _, _, _>(root, proof, items)
}

/// Determine a trie root given a hash DB and delta values.
pub fn delta_trie_root<L: TrieConfiguration, I, A, B, DB>(
db: &mut DB,
Expand Down Expand Up @@ -727,4 +770,89 @@ mod tests {

assert_eq!(pairs, iter_pairs);
}

#[test]
fn proof_non_inclusion_works() {
let pairs = vec![
(hex!("0102").to_vec(), hex!("01").to_vec()),
(hex!("0203").to_vec(), hex!("0405").to_vec()),
];

let mut memdb = MemoryDB::default();
let mut root = Default::default();
populate_trie::<Layout>(&mut memdb, &mut root, &pairs);

let non_included_key: Vec<u8> = hex!("0909").to_vec();
let proof = generate_trie_proof::<Layout, _, _, _>(
&memdb,
root,
&[non_included_key.clone()]
).unwrap();

// Verifying that the K was not included into the trie should work.
assert!(verify_trie_proof::<Layout, _, _, Vec<u8>>(
&root,
&proof,
&[(non_included_key.clone(), None)],
).is_ok()
);

// Verifying that the K was included into the trie should fail.
assert!(verify_trie_proof::<Layout, _, _, Vec<u8>>(
&root,
&proof,
&[(non_included_key, Some(hex!("1010").to_vec()))],
).is_err()
);
}

#[test]
fn proof_inclusion_works() {
let pairs = vec![
(hex!("0102").to_vec(), hex!("01").to_vec()),
(hex!("0203").to_vec(), hex!("0405").to_vec()),
];

let mut memdb = MemoryDB::default();
let mut root = Default::default();
populate_trie::<Layout>(&mut memdb, &mut root, &pairs);

let proof = generate_trie_proof::<Layout, _, _, _>(
&memdb,
root,
&[pairs[0].0.clone()]
).unwrap();

// Check that a K, V included into the proof are verified.
assert!(verify_trie_proof::<Layout, _, _, _>(
&root,
&proof,
&[(pairs[0].0.clone(), Some(pairs[0].1.clone()))]
).is_ok()
);

// Absence of the V is not verified with the proof that has K, V included.
assert!(verify_trie_proof::<Layout, _, _, Vec<u8>>(
&root,
&proof,
&[(pairs[0].0.clone(), None)]
).is_err()
);

// K not included into the trie is not verified.
assert!(verify_trie_proof::<Layout, _, _, _>(
&root,
&proof,
&[(hex!("4242").to_vec(), Some(pairs[0].1.clone()))]
).is_err()
);

// K included into the trie but not included into the proof is not verified.
assert!(verify_trie_proof::<Layout, _, _, _>(
&root,
&proof,
&[(pairs[1].0.clone(), Some(pairs[1].1.clone()))]
).is_err()
);
}
}
2 changes: 1 addition & 1 deletion test-utils/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pallet-timestamp = { version = "2.0.0", default-features = false, path = "../../
sc-client = { version = "0.8", optional = true, path = "../../client" }
sp-trie = { version = "2.0.0", default-features = false, path = "../../primitives/trie" }
sp-transaction-pool = { version = "2.0.0", default-features = false, path = "../../primitives/transaction-pool" }
trie-db = { version = "0.18.1", default-features = false }
trie-db = { version = "0.19.2", default-features = false }

[dev-dependencies]
sc-executor = { version = "0.8", path = "../../client/executor" }
Expand Down

0 comments on commit 36a6de0

Please sign in to comment.