feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
@@ -0,0 +1,327 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// 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.
|
||||
|
||||
//! Types for a compact base-16 merkle trie used for checking and generating proofs within the
|
||||
//! runtime. The `sp-trie` crate exposes all of these same functionality (and more), but this
|
||||
//! library is designed to work more easily with runtime native types, which simply need to
|
||||
//! implement `Encode`/`Decode`. It also exposes a runtime friendly `TrieError` type which can be
|
||||
//! use inside of a FRAME Pallet.
|
||||
//!
|
||||
//! Proofs are created with latest bizinikiwi trie format (`LayoutV1`), and are not compatible with
|
||||
//! proofs using `LayoutV0`.
|
||||
|
||||
use super::{ProofToHashes, ProvingTrie, TrieError};
|
||||
use crate::{Decode, DispatchError, Encode};
|
||||
use alloc::vec::Vec;
|
||||
use codec::MaxEncodedLen;
|
||||
use pezsp_trie::{
|
||||
trie_types::{TrieDBBuilder, TrieDBMutBuilderV1},
|
||||
LayoutV1, MemoryDB, RandomState, Trie, TrieMut,
|
||||
};
|
||||
|
||||
/// A helper structure for building a basic base-16 merkle trie and creating compact proofs for that
|
||||
/// trie. Proofs are created with latest bizinikiwi trie format (`LayoutV1`), and are not compatible
|
||||
/// with proofs using `LayoutV0`.
|
||||
pub struct BasicProvingTrie<Hashing, Key, Value>
|
||||
where
|
||||
Hashing: pezsp_core::Hasher,
|
||||
{
|
||||
db: MemoryDB<Hashing>,
|
||||
root: Hashing::Out,
|
||||
_phantom: core::marker::PhantomData<(Key, Value)>,
|
||||
}
|
||||
|
||||
impl<Hashing, Key, Value> BasicProvingTrie<Hashing, Key, Value>
|
||||
where
|
||||
Hashing: pezsp_core::Hasher,
|
||||
Key: Encode,
|
||||
{
|
||||
/// Create a compact merkle proof needed to prove all `keys` and their values are in the trie.
|
||||
///
|
||||
/// When verifying the proof created by this function, you must include all of the keys and
|
||||
/// values of the proof, else the verifier will complain that extra nodes are provided in the
|
||||
/// proof that are not needed.
|
||||
pub fn create_multi_proof(&self, keys: &[Key]) -> Result<Vec<u8>, DispatchError> {
|
||||
pezsp_trie::generate_trie_proof::<LayoutV1<Hashing>, _, _, _>(
|
||||
&self.db,
|
||||
self.root,
|
||||
&keys.into_iter().map(|k| k.encode()).collect::<Vec<Vec<u8>>>(),
|
||||
)
|
||||
.map_err(|err| TrieError::from(*err).into())
|
||||
.map(|structured_proof| structured_proof.encode())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Hashing, Key, Value> ProvingTrie<Hashing, Key, Value> for BasicProvingTrie<Hashing, Key, Value>
|
||||
where
|
||||
Hashing: pezsp_core::Hasher,
|
||||
Key: Encode,
|
||||
Value: Encode + Decode,
|
||||
{
|
||||
/// Create a new instance of a `ProvingTrie` using an iterator of key/value pairs.
|
||||
fn generate_for<I>(items: I) -> Result<Self, DispatchError>
|
||||
where
|
||||
I: IntoIterator<Item = (Key, Value)>,
|
||||
{
|
||||
let mut db = MemoryDB::with_hasher(RandomState::default());
|
||||
let mut root = Default::default();
|
||||
|
||||
{
|
||||
let mut trie = TrieDBMutBuilderV1::new(&mut db, &mut root).build();
|
||||
for (key, value) in items.into_iter() {
|
||||
key.using_encoded(|k| value.using_encoded(|v| trie.insert(k, v)))
|
||||
.map_err(|_| "failed to insert into trie")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self { db, root, _phantom: Default::default() })
|
||||
}
|
||||
|
||||
/// Access the underlying trie root.
|
||||
fn root(&self) -> &Hashing::Out {
|
||||
&self.root
|
||||
}
|
||||
|
||||
/// Query a value contained within the current trie. Returns `None` if the
|
||||
/// nodes within the current `MemoryDB` are insufficient to query the item.
|
||||
fn query(&self, key: &Key) -> Option<Value> {
|
||||
let trie = TrieDBBuilder::new(&self.db, &self.root).build();
|
||||
key.using_encoded(|s| trie.get(s))
|
||||
.ok()?
|
||||
.and_then(|raw| Value::decode(&mut &*raw).ok())
|
||||
}
|
||||
|
||||
/// Create a compact merkle proof needed to prove a single key and its value are in the trie.
|
||||
fn create_proof(&self, key: &Key) -> Result<Vec<u8>, DispatchError> {
|
||||
pezsp_trie::generate_trie_proof::<LayoutV1<Hashing>, _, _, _>(
|
||||
&self.db,
|
||||
self.root,
|
||||
&[key.encode()],
|
||||
)
|
||||
.map_err(|err| TrieError::from(*err).into())
|
||||
.map(|structured_proof| structured_proof.encode())
|
||||
}
|
||||
|
||||
/// Verify the existence of `key` and `value` in a given trie root and proof.
|
||||
fn verify_proof(
|
||||
root: &Hashing::Out,
|
||||
proof: &[u8],
|
||||
key: &Key,
|
||||
value: &Value,
|
||||
) -> Result<(), DispatchError> {
|
||||
verify_proof::<Hashing, Key, Value>(root, proof, key, value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Hashing, Key, Value> ProofToHashes for BasicProvingTrie<Hashing, Key, Value>
|
||||
where
|
||||
Hashing: pezsp_core::Hasher,
|
||||
Hashing::Out: MaxEncodedLen,
|
||||
{
|
||||
// Our proof is just raw bytes.
|
||||
type Proof = [u8];
|
||||
// This base 16 trie uses a raw proof of `Vec<Vec<u8>`, where the length of the first `Vec`
|
||||
// is the depth of the trie. We can use this to predict the number of hashes.
|
||||
fn proof_to_hashes(proof: &[u8]) -> Result<u32, DispatchError> {
|
||||
use codec::DecodeLength;
|
||||
let depth =
|
||||
<Vec<Vec<u8>> as DecodeLength>::len(proof).map_err(|_| TrieError::DecodeError)?;
|
||||
Ok(depth as u32)
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify the existence of `key` and `value` in a given trie root and proof.
|
||||
pub fn verify_proof<Hashing, Key, Value>(
|
||||
root: &Hashing::Out,
|
||||
proof: &[u8],
|
||||
key: &Key,
|
||||
value: &Value,
|
||||
) -> Result<(), DispatchError>
|
||||
where
|
||||
Hashing: pezsp_core::Hasher,
|
||||
Key: Encode,
|
||||
Value: Encode,
|
||||
{
|
||||
let structured_proof: Vec<Vec<u8>> =
|
||||
Decode::decode(&mut &proof[..]).map_err(|_| TrieError::DecodeError)?;
|
||||
pezsp_trie::verify_trie_proof::<LayoutV1<Hashing>, _, _, _>(
|
||||
&root,
|
||||
&structured_proof,
|
||||
&[(key.encode(), Some(value.encode()))],
|
||||
)
|
||||
.map_err(|err| TrieError::from(err).into())
|
||||
}
|
||||
|
||||
/// Verify the existence of multiple `items` in a given trie root and proof.
|
||||
pub fn verify_multi_proof<Hashing, Key, Value>(
|
||||
root: &Hashing::Out,
|
||||
proof: &[u8],
|
||||
items: &[(Key, Value)],
|
||||
) -> Result<(), DispatchError>
|
||||
where
|
||||
Hashing: pezsp_core::Hasher,
|
||||
Key: Encode,
|
||||
Value: Encode,
|
||||
{
|
||||
let structured_proof: Vec<Vec<u8>> =
|
||||
Decode::decode(&mut &proof[..]).map_err(|_| TrieError::DecodeError)?;
|
||||
let items_encoded = items
|
||||
.into_iter()
|
||||
.map(|(key, value)| (key.encode(), Some(value.encode())))
|
||||
.collect::<Vec<(Vec<u8>, Option<Vec<u8>>)>>();
|
||||
|
||||
pezsp_trie::verify_trie_proof::<LayoutV1<Hashing>, _, _, _>(
|
||||
&root,
|
||||
&structured_proof,
|
||||
&items_encoded,
|
||||
)
|
||||
.map_err(|err| TrieError::from(err).into())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::traits::BlakeTwo256;
|
||||
use pezsp_core::H256;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
// A trie which simulates a trie of accounts (u32) and balances (u128).
|
||||
type BalanceTrie = BasicProvingTrie<BlakeTwo256, u32, u128>;
|
||||
|
||||
// The expected root hash for an empty trie.
|
||||
fn empty_root() -> H256 {
|
||||
pezsp_trie::empty_trie_root::<LayoutV1<BlakeTwo256>>()
|
||||
}
|
||||
|
||||
fn create_balance_trie() -> BalanceTrie {
|
||||
// Create a map of users and their balances.
|
||||
let mut map = BTreeMap::<u32, u128>::new();
|
||||
for i in 0..100u32 {
|
||||
map.insert(i, i.into());
|
||||
}
|
||||
|
||||
// Put items into the trie.
|
||||
let balance_trie = BalanceTrie::generate_for(map).unwrap();
|
||||
|
||||
// Root is changed.
|
||||
let root = *balance_trie.root();
|
||||
assert!(root != empty_root());
|
||||
|
||||
// Assert valid keys are queryable.
|
||||
assert_eq!(balance_trie.query(&6u32), Some(6u128));
|
||||
assert_eq!(balance_trie.query(&9u32), Some(9u128));
|
||||
assert_eq!(balance_trie.query(&69u32), Some(69u128));
|
||||
// Invalid key returns none.
|
||||
assert_eq!(balance_trie.query(&6969u32), None);
|
||||
|
||||
balance_trie
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_trie_works() {
|
||||
let empty_trie = BalanceTrie::generate_for(Vec::new()).unwrap();
|
||||
assert_eq!(*empty_trie.root(), empty_root());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_end_to_end_single_value() {
|
||||
let balance_trie = create_balance_trie();
|
||||
let root = *balance_trie.root();
|
||||
|
||||
// Create a proof for a valid key.
|
||||
let proof = balance_trie.create_proof(&6u32).unwrap();
|
||||
|
||||
// Assert key is provable, all other keys are invalid.
|
||||
for i in 0..200u32 {
|
||||
if i == 6 {
|
||||
assert_eq!(
|
||||
verify_proof::<BlakeTwo256, _, _>(&root, &proof, &i, &u128::from(i)),
|
||||
Ok(())
|
||||
);
|
||||
// Wrong value is invalid.
|
||||
assert_eq!(
|
||||
verify_proof::<BlakeTwo256, _, _>(&root, &proof, &i, &u128::from(i + 1)),
|
||||
Err(TrieError::RootMismatch.into())
|
||||
);
|
||||
} else {
|
||||
assert!(
|
||||
verify_proof::<BlakeTwo256, _, _>(&root, &proof, &i, &u128::from(i)).is_err()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_end_to_end_multi() {
|
||||
let balance_trie = create_balance_trie();
|
||||
let root = *balance_trie.root();
|
||||
|
||||
// Create a proof for a valid and invalid key.
|
||||
let proof = balance_trie.create_multi_proof(&[6u32, 9u32, 69u32]).unwrap();
|
||||
let items = [(6u32, 6u128), (9u32, 9u128), (69u32, 69u128)];
|
||||
|
||||
assert_eq!(verify_multi_proof::<BlakeTwo256, _, _>(&root, &proof, &items), Ok(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn proof_fails_with_bad_data() {
|
||||
let balance_trie = create_balance_trie();
|
||||
let root = *balance_trie.root();
|
||||
|
||||
// Create a proof for a valid key.
|
||||
let proof = balance_trie.create_proof(&6u32).unwrap();
|
||||
|
||||
// Correct data verifies successfully
|
||||
assert_eq!(verify_proof::<BlakeTwo256, _, _>(&root, &proof, &6u32, &6u128), Ok(()));
|
||||
|
||||
// Fail to verify proof with wrong root
|
||||
assert_eq!(
|
||||
verify_proof::<BlakeTwo256, _, _>(&Default::default(), &proof, &6u32, &6u128),
|
||||
Err(TrieError::RootMismatch.into())
|
||||
);
|
||||
|
||||
// Crete a bad proof.
|
||||
let bad_proof = balance_trie.create_proof(&99u32).unwrap();
|
||||
|
||||
// Fail to verify data with the wrong proof
|
||||
assert_eq!(
|
||||
verify_proof::<BlakeTwo256, _, _>(&root, &bad_proof, &6u32, &6u128),
|
||||
Err(TrieError::ExtraneousHashReference.into())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn proof_to_hashes() {
|
||||
let mut i: u32 = 1;
|
||||
// Compute log base 16 and round up
|
||||
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 = BalanceTrie::generate_for((0..i).map(|i| (i, u128::from(i)))).unwrap();
|
||||
let proof = trie.create_proof(&0).unwrap();
|
||||
let hashes = BalanceTrie::proof_to_hashes(&proof).unwrap();
|
||||
let log16 = log16(i).max(1);
|
||||
|
||||
assert_eq!(hashes, log16);
|
||||
i = i * 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// 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.
|
||||
|
||||
//! Types for a base-2 merkle tree used for checking and generating proofs within the
|
||||
//! runtime. The `binary-merkle-tree` crate exposes all of these same functionality (and more), but
|
||||
//! this library is designed to work more easily with runtime native types, which simply need to
|
||||
//! implement `Encode`/`Decode`.
|
||||
|
||||
use super::{ProofToHashes, ProvingTrie, TrieError};
|
||||
use crate::{Decode, DispatchError, Encode};
|
||||
use alloc::{collections::BTreeMap, vec::Vec};
|
||||
use binary_merkle_tree::{merkle_proof, merkle_root, MerkleProof};
|
||||
use codec::MaxEncodedLen;
|
||||
|
||||
/// A helper structure for building a basic base-2 merkle trie and creating compact proofs for that
|
||||
/// trie.
|
||||
pub struct BasicProvingTrie<Hashing, Key, Value>
|
||||
where
|
||||
Hashing: pezsp_core::Hasher,
|
||||
{
|
||||
db: BTreeMap<Key, Value>,
|
||||
root: Hashing::Out,
|
||||
_phantom: core::marker::PhantomData<(Key, Value)>,
|
||||
}
|
||||
|
||||
impl<Hashing, Key, Value> ProvingTrie<Hashing, Key, Value> for BasicProvingTrie<Hashing, Key, Value>
|
||||
where
|
||||
Hashing: pezsp_core::Hasher,
|
||||
Hashing::Out: Encode + Decode,
|
||||
Key: Encode + Decode + Ord,
|
||||
Value: Encode + Decode + Clone,
|
||||
{
|
||||
/// Create a new instance of a `ProvingTrie` using an iterator of key/value pairs.
|
||||
fn generate_for<I>(items: I) -> Result<Self, DispatchError>
|
||||
where
|
||||
I: IntoIterator<Item = (Key, Value)>,
|
||||
{
|
||||
let mut db = BTreeMap::default();
|
||||
for (key, value) in items.into_iter() {
|
||||
db.insert(key, value);
|
||||
}
|
||||
let root = merkle_root::<Hashing, _>(db.iter().map(|item| item.encode()));
|
||||
Ok(Self { db, root, _phantom: Default::default() })
|
||||
}
|
||||
|
||||
/// Access the underlying trie root.
|
||||
fn root(&self) -> &Hashing::Out {
|
||||
&self.root
|
||||
}
|
||||
|
||||
/// Query a value contained within the current trie. Returns `None` if the
|
||||
/// nodes within the current `db` are insufficient to query the item.
|
||||
fn query(&self, key: &Key) -> Option<Value> {
|
||||
self.db.get(&key).cloned()
|
||||
}
|
||||
|
||||
/// Create a compact merkle proof needed to prove a single key and its value are in the trie.
|
||||
/// Returns an error if the nodes within the current `db` are insufficient to create a proof.
|
||||
fn create_proof(&self, key: &Key) -> Result<Vec<u8>, DispatchError> {
|
||||
let mut encoded = Vec::with_capacity(self.db.len());
|
||||
let mut found_index = None;
|
||||
|
||||
// Find the index of our key, and encode the (key, value) pair.
|
||||
for (i, (k, v)) in self.db.iter().enumerate() {
|
||||
// If we found the key we are looking for, save it.
|
||||
if k == key {
|
||||
found_index = Some(i);
|
||||
}
|
||||
|
||||
encoded.push((k, v).encode());
|
||||
}
|
||||
|
||||
let index = found_index.ok_or(TrieError::IncompleteDatabase)?;
|
||||
let proof = merkle_proof::<Hashing, Vec<Vec<u8>>, Vec<u8>>(encoded, index as u32);
|
||||
Ok(proof.encode())
|
||||
}
|
||||
|
||||
/// Verify the existence of `key` and `value` in a given trie root and proof.
|
||||
fn verify_proof(
|
||||
root: &Hashing::Out,
|
||||
proof: &[u8],
|
||||
key: &Key,
|
||||
value: &Value,
|
||||
) -> Result<(), DispatchError> {
|
||||
verify_proof::<Hashing, Key, Value>(root, proof, key, value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Hashing, Key, Value> ProofToHashes for BasicProvingTrie<Hashing, Key, Value>
|
||||
where
|
||||
Hashing: pezsp_core::Hasher,
|
||||
Hashing::Out: MaxEncodedLen + Decode,
|
||||
Key: Decode,
|
||||
Value: Decode,
|
||||
{
|
||||
// Our proof is just raw bytes.
|
||||
type Proof = [u8];
|
||||
// This base 2 merkle trie includes a `proof` field which is a `Vec<Hash>`.
|
||||
// The length of this vector tells us the depth of the proof, and how many
|
||||
// hashes we need to calculate.
|
||||
fn proof_to_hashes(proof: &[u8]) -> Result<u32, DispatchError> {
|
||||
let decoded_proof: MerkleProof<Hashing::Out, Vec<u8>> =
|
||||
Decode::decode(&mut &proof[..]).map_err(|_| TrieError::IncompleteProof)?;
|
||||
let depth = decoded_proof.proof.len();
|
||||
Ok(depth as u32)
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify the existence of `key` and `value` in a given trie root and proof.
|
||||
pub fn verify_proof<Hashing, Key, Value>(
|
||||
root: &Hashing::Out,
|
||||
proof: &[u8],
|
||||
key: &Key,
|
||||
value: &Value,
|
||||
) -> Result<(), DispatchError>
|
||||
where
|
||||
Hashing: pezsp_core::Hasher,
|
||||
Hashing::Out: Decode,
|
||||
Key: Encode + Decode,
|
||||
Value: Encode + Decode,
|
||||
{
|
||||
let decoded_proof: MerkleProof<Hashing::Out, Vec<u8>> =
|
||||
Decode::decode(&mut &proof[..]).map_err(|_| TrieError::IncompleteProof)?;
|
||||
if *root != decoded_proof.root {
|
||||
return Err(TrieError::RootMismatch.into());
|
||||
}
|
||||
|
||||
if (key, value).encode() != decoded_proof.leaf {
|
||||
return Err(TrieError::ValueMismatch.into());
|
||||
}
|
||||
|
||||
if binary_merkle_tree::verify_proof::<Hashing, _, _>(
|
||||
&decoded_proof.root,
|
||||
decoded_proof.proof,
|
||||
decoded_proof.number_of_leaves,
|
||||
decoded_proof.leaf_index,
|
||||
&decoded_proof.leaf,
|
||||
) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(TrieError::IncompleteProof.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::traits::BlakeTwo256;
|
||||
use pezsp_core::H256;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
// A trie which simulates a trie of accounts (u32) and balances (u128).
|
||||
type BalanceTrie = BasicProvingTrie<BlakeTwo256, u32, u128>;
|
||||
|
||||
// The expected root hash for an empty trie.
|
||||
fn empty_root() -> H256 {
|
||||
let tree = BalanceTrie::generate_for(Vec::new()).unwrap();
|
||||
*tree.root()
|
||||
}
|
||||
|
||||
fn create_balance_trie() -> BalanceTrie {
|
||||
// Create a map of users and their balances.
|
||||
let mut map = BTreeMap::<u32, u128>::new();
|
||||
for i in 0..100u32 {
|
||||
map.insert(i, i.into());
|
||||
}
|
||||
|
||||
// Put items into the trie.
|
||||
let balance_trie = BalanceTrie::generate_for(map).unwrap();
|
||||
|
||||
// Root is changed.
|
||||
let root = *balance_trie.root();
|
||||
assert!(root != empty_root());
|
||||
|
||||
// Assert valid keys are queryable.
|
||||
assert_eq!(balance_trie.query(&6u32), Some(6u128));
|
||||
assert_eq!(balance_trie.query(&9u32), Some(9u128));
|
||||
assert_eq!(balance_trie.query(&69u32), Some(69u128));
|
||||
|
||||
balance_trie
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_trie_works() {
|
||||
let empty_trie = BalanceTrie::generate_for(Vec::new()).unwrap();
|
||||
assert_eq!(*empty_trie.root(), empty_root());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_end_to_end_single_value() {
|
||||
let balance_trie = create_balance_trie();
|
||||
let root = *balance_trie.root();
|
||||
|
||||
// Create a proof for a valid key.
|
||||
let proof = balance_trie.create_proof(&6u32).unwrap();
|
||||
|
||||
// Assert key is provable, all other keys are invalid.
|
||||
for i in 0..200u32 {
|
||||
if i == 6 {
|
||||
assert_eq!(
|
||||
verify_proof::<BlakeTwo256, _, _>(&root, &proof, &i, &u128::from(i)),
|
||||
Ok(())
|
||||
);
|
||||
// Wrong value is invalid.
|
||||
assert_eq!(
|
||||
verify_proof::<BlakeTwo256, _, _>(&root, &proof, &i, &u128::from(i + 1)),
|
||||
Err(TrieError::ValueMismatch.into())
|
||||
);
|
||||
} else {
|
||||
assert!(
|
||||
verify_proof::<BlakeTwo256, _, _>(&root, &proof, &i, &u128::from(i)).is_err()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn proof_fails_with_bad_data() {
|
||||
let balance_trie = create_balance_trie();
|
||||
let root = *balance_trie.root();
|
||||
|
||||
// Create a proof for a valid key.
|
||||
let proof = balance_trie.create_proof(&6u32).unwrap();
|
||||
|
||||
// Correct data verifies successfully
|
||||
assert_eq!(verify_proof::<BlakeTwo256, _, _>(&root, &proof, &6u32, &6u128), Ok(()));
|
||||
|
||||
// Fail to verify proof with wrong root
|
||||
assert_eq!(
|
||||
verify_proof::<BlakeTwo256, _, _>(&Default::default(), &proof, &6u32, &6u128),
|
||||
Err(TrieError::RootMismatch.into())
|
||||
);
|
||||
|
||||
// Fail to verify proof with wrong data
|
||||
assert_eq!(
|
||||
verify_proof::<BlakeTwo256, _, _>(&root, &[], &6u32, &6u128),
|
||||
Err(TrieError::IncompleteProof.into())
|
||||
);
|
||||
}
|
||||
|
||||
// We make assumptions about the structure of the merkle proof in order to provide the
|
||||
// `proof_to_hashes` function. This test keeps those assumptions checked.
|
||||
#[test]
|
||||
fn assert_structure_of_merkle_proof() {
|
||||
let balance_trie = create_balance_trie();
|
||||
let root = *balance_trie.root();
|
||||
// Create a proof for a valid key.
|
||||
let proof = balance_trie.create_proof(&6u32).unwrap();
|
||||
let decoded_proof: MerkleProof<H256, Vec<u8>> = Decode::decode(&mut &proof[..]).unwrap();
|
||||
|
||||
let constructed_proof = MerkleProof::<H256, Vec<u8>> {
|
||||
root,
|
||||
proof: decoded_proof.proof.clone(),
|
||||
number_of_leaves: 100,
|
||||
leaf_index: 6,
|
||||
leaf: (6u32, 6u128).encode(),
|
||||
};
|
||||
assert_eq!(constructed_proof, decoded_proof);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn proof_to_hashes() {
|
||||
let mut i: u32 = 1;
|
||||
while i < 10_000_000 {
|
||||
let trie = BalanceTrie::generate_for((0..i).map(|i| (i, u128::from(i)))).unwrap();
|
||||
let proof = trie.create_proof(&0).unwrap();
|
||||
let hashes = BalanceTrie::proof_to_hashes(&proof).unwrap();
|
||||
let log2 = (i as f64).log2().ceil() as u32;
|
||||
|
||||
assert_eq!(hashes, log2);
|
||||
i = i * 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// 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.
|
||||
|
||||
//! Types for merkle tries compatible with the runtime.
|
||||
|
||||
pub mod base16;
|
||||
pub mod base2;
|
||||
|
||||
use crate::{Decode, DecodeWithMemTracking, DispatchError, Encode, MaxEncodedLen, TypeInfo};
|
||||
#[cfg(feature = "serde")]
|
||||
use crate::{Deserialize, Serialize};
|
||||
use alloc::vec::Vec;
|
||||
use pezsp_trie::{trie_types::TrieError as SpTrieError, VerifyError};
|
||||
|
||||
/// A runtime friendly error type for tries.
|
||||
#[derive(
|
||||
Eq,
|
||||
PartialEq,
|
||||
Clone,
|
||||
Copy,
|
||||
Encode,
|
||||
Decode,
|
||||
DecodeWithMemTracking,
|
||||
Debug,
|
||||
TypeInfo,
|
||||
MaxEncodedLen,
|
||||
)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum TrieError {
|
||||
/* From TrieError */
|
||||
/// Attempted to create a trie with a state root not in the DB.
|
||||
InvalidStateRoot,
|
||||
/// Trie item not found in the database,
|
||||
IncompleteDatabase,
|
||||
/// A value was found in the trie with a nibble key that was not byte-aligned.
|
||||
ValueAtIncompleteKey,
|
||||
/// Corrupt Trie item.
|
||||
DecoderError,
|
||||
/// Hash is not value.
|
||||
InvalidHash,
|
||||
/* From VerifyError */
|
||||
/// The statement being verified contains multiple key-value pairs with the same key.
|
||||
DuplicateKey,
|
||||
/// The proof contains at least one extraneous node.
|
||||
ExtraneousNode,
|
||||
/// The proof contains at least one extraneous value which should have been omitted from the
|
||||
/// proof.
|
||||
ExtraneousValue,
|
||||
/// The proof contains at least one extraneous hash reference the should have been omitted.
|
||||
ExtraneousHashReference,
|
||||
/// The proof contains an invalid child reference that exceeds the hash length.
|
||||
InvalidChildReference,
|
||||
/// The proof indicates that an expected value was not found in the trie.
|
||||
ValueMismatch,
|
||||
/// The proof is missing trie nodes required to verify.
|
||||
IncompleteProof,
|
||||
/// The root hash computed from the proof is incorrect.
|
||||
RootMismatch,
|
||||
/// One of the proof nodes could not be decoded.
|
||||
DecodeError,
|
||||
}
|
||||
|
||||
impl<T> From<SpTrieError<T>> for TrieError {
|
||||
fn from(error: SpTrieError<T>) -> Self {
|
||||
match error {
|
||||
SpTrieError::InvalidStateRoot(..) => Self::InvalidStateRoot,
|
||||
SpTrieError::IncompleteDatabase(..) => Self::IncompleteDatabase,
|
||||
SpTrieError::ValueAtIncompleteKey(..) => Self::ValueAtIncompleteKey,
|
||||
SpTrieError::DecoderError(..) => Self::DecoderError,
|
||||
SpTrieError::InvalidHash(..) => Self::InvalidHash,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> From<VerifyError<T, U>> for TrieError {
|
||||
fn from(error: VerifyError<T, U>) -> Self {
|
||||
match error {
|
||||
VerifyError::DuplicateKey(..) => Self::DuplicateKey,
|
||||
VerifyError::ExtraneousNode => Self::ExtraneousNode,
|
||||
VerifyError::ExtraneousValue(..) => Self::ExtraneousValue,
|
||||
VerifyError::ExtraneousHashReference(..) => Self::ExtraneousHashReference,
|
||||
VerifyError::InvalidChildReference(..) => Self::InvalidChildReference,
|
||||
VerifyError::ValueMismatch(..) => Self::ValueMismatch,
|
||||
VerifyError::IncompleteProof => Self::IncompleteProof,
|
||||
VerifyError::RootMismatch(..) => Self::RootMismatch,
|
||||
VerifyError::DecodeError(..) => Self::DecodeError,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TrieError> for &'static str {
|
||||
fn from(e: TrieError) -> &'static str {
|
||||
match e {
|
||||
TrieError::InvalidStateRoot => "The state root is not in the database.",
|
||||
TrieError::IncompleteDatabase => "A trie item was not found in the database.",
|
||||
TrieError::ValueAtIncompleteKey =>
|
||||
"A value was found with a key that is not byte-aligned.",
|
||||
TrieError::DecoderError => "A corrupt trie item was encountered.",
|
||||
TrieError::InvalidHash => "The hash does not match the expected value.",
|
||||
TrieError::DuplicateKey => "The proof contains duplicate keys.",
|
||||
TrieError::ExtraneousNode => "The proof contains extraneous nodes.",
|
||||
TrieError::ExtraneousValue => "The proof contains extraneous values.",
|
||||
TrieError::ExtraneousHashReference => "The proof contains extraneous hash references.",
|
||||
TrieError::InvalidChildReference => "The proof contains an invalid child reference.",
|
||||
TrieError::ValueMismatch => "The proof indicates a value mismatch.",
|
||||
TrieError::IncompleteProof => "The proof is incomplete.",
|
||||
TrieError::RootMismatch => "The root hash computed from the proof is incorrect.",
|
||||
TrieError::DecodeError => "One of the proof nodes could not be decoded.",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An interface for creating, interacting with, and creating proofs in a merkle trie.
|
||||
pub trait ProvingTrie<Hashing, Key, Value>
|
||||
where
|
||||
Self: Sized,
|
||||
Hashing: pezsp_core::Hasher,
|
||||
{
|
||||
/// Create a new instance of a `ProvingTrie` using an iterator of key/value pairs.
|
||||
fn generate_for<I>(items: I) -> Result<Self, DispatchError>
|
||||
where
|
||||
I: IntoIterator<Item = (Key, Value)>;
|
||||
/// Access the underlying trie root.
|
||||
fn root(&self) -> &Hashing::Out;
|
||||
/// Query a value contained within the current trie. Returns `None` if the
|
||||
/// the value does not exist in the trie.
|
||||
fn query(&self, key: &Key) -> Option<Value>;
|
||||
/// Create a proof that can be used to verify a key and its value are in the trie.
|
||||
fn create_proof(&self, key: &Key) -> Result<Vec<u8>, DispatchError>;
|
||||
/// Verify the existence of `key` and `value` in a given trie root and proof.
|
||||
fn verify_proof(
|
||||
root: &Hashing::Out,
|
||||
proof: &[u8],
|
||||
key: &Key,
|
||||
value: &Value,
|
||||
) -> Result<(), DispatchError>;
|
||||
}
|
||||
|
||||
/// This trait is one strategy that can be used to benchmark a trie proof verification for the
|
||||
/// runtime. This strategy assumes that the majority complexity of verifying a merkle proof comes
|
||||
/// from computing hashes to recreate the merkle root. This trait converts the the proof, some
|
||||
/// bytes, to the number of hashes we expect to execute to verify that proof.
|
||||
pub trait ProofToHashes {
|
||||
/// The Proof type we will use to determine the number of hashes.
|
||||
type Proof: ?Sized;
|
||||
/// This function returns the number of hashes we expect to calculate based on the
|
||||
/// size of the proof. This is used for benchmarking, so for worst case scenario, we should
|
||||
/// round up.
|
||||
///
|
||||
/// The major complexity of doing a `verify_proof` is computing the hashes needed
|
||||
/// to calculate the merkle root. For tries, it should be easy to predict the depth
|
||||
/// of the trie (which is equivalent to the hashes), by looking at the length of the proof.
|
||||
fn proof_to_hashes(proof: &Self::Proof) -> Result<u32, DispatchError>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::traits::BlakeTwo256;
|
||||
|
||||
// A trie which simulates a trie of accounts (u32) and balances (u128).
|
||||
type BalanceTrie2 = base2::BasicProvingTrie<BlakeTwo256, u32, u128>;
|
||||
type BalanceTrie16 = base16::BasicProvingTrie<BlakeTwo256, u32, u128>;
|
||||
|
||||
#[test]
|
||||
fn basic_api_usage_base_2() {
|
||||
let balance_trie = BalanceTrie2::generate_for((0..100u32).map(|i| (i, i.into()))).unwrap();
|
||||
let root = *balance_trie.root();
|
||||
assert_eq!(balance_trie.query(&69), Some(69));
|
||||
assert_eq!(balance_trie.query(&6969), None);
|
||||
let proof = balance_trie.create_proof(&69u32).unwrap();
|
||||
assert_eq!(BalanceTrie2::verify_proof(&root, &proof, &69u32, &69u128), Ok(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_api_usage_base_16() {
|
||||
let balance_trie = BalanceTrie16::generate_for((0..100u32).map(|i| (i, i.into()))).unwrap();
|
||||
let root = *balance_trie.root();
|
||||
assert_eq!(balance_trie.query(&69), Some(69));
|
||||
assert_eq!(balance_trie.query(&6969), None);
|
||||
let proof = balance_trie.create_proof(&69u32).unwrap();
|
||||
assert_eq!(BalanceTrie16::verify_proof(&root, &proof, &69u32, &69u128), Ok(()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user