Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve APIs for Tries in Runtime #5756

Draft
wants to merge 72 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 64 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
d50d5e4
initial ideas
shawntabrizi Mar 28, 2024
7f4422e
Update proving_trie.rs
shawntabrizi Mar 28, 2024
bdc0c84
create trait
shawntabrizi Mar 28, 2024
da385ab
use trait
shawntabrizi Mar 28, 2024
6ab4bfb
clean up trait and basic trie further
shawntabrizi Mar 28, 2024
1cfb29f
use trait in session historical
shawntabrizi Mar 28, 2024
3080c7b
fix api, add basic end to end test
shawntabrizi Mar 28, 2024
39b0fca
fix test
shawntabrizi Mar 28, 2024
599f576
Revert "use trait in session historical"
shawntabrizi Mar 28, 2024
a1c8886
Merge branch 'master' into shawntabrizi-proving-trie
shawntabrizi Mar 29, 2024
6bde2a3
Merge branch 'master' into shawntabrizi-proving-trie
Ank4n Apr 4, 2024
ead7951
Update substrate/primitives/runtime/src/proving_trie.rs
shawntabrizi Apr 4, 2024
0cac048
Merge branch 'master' into shawntabrizi-proving-trie
shawntabrizi Aug 15, 2024
acfe734
fix some feedback
shawntabrizi Aug 15, 2024
45f4287
update name
shawntabrizi Aug 15, 2024
efbe1c9
docs and multi value proof
shawntabrizi Aug 15, 2024
cfa62ce
improve test
shawntabrizi Aug 15, 2024
885fd94
add multi-value query test
shawntabrizi Aug 15, 2024
18a5c2e
Merge branch 'master' into shawntabrizi-proving-trie
shawntabrizi Aug 15, 2024
5e3e518
Create pr_3881.prdoc
shawntabrizi Aug 15, 2024
f35cacc
Merge branch 'shawntabrizi-proving-trie' of https://github.com/shawnt…
shawntabrizi Aug 15, 2024
e6c3759
use v1
shawntabrizi Aug 17, 2024
89679c3
Merge branch 'master' into shawntabrizi-proving-trie
shawntabrizi Aug 17, 2024
b40c96a
initial idea
shawntabrizi Aug 19, 2024
37052ee
some bs code to make things compile
shawntabrizi Aug 19, 2024
08f2b35
more stuff
shawntabrizi Aug 19, 2024
118a51c
complete logic
shawntabrizi Aug 19, 2024
44bc5bb
add verification check
shawntabrizi Aug 19, 2024
6e853ba
Merge branch 'master' into shawntabrizi-proving-trie
shawntabrizi Sep 2, 2024
89abcd0
initial idea
shawntabrizi Aug 19, 2024
8ad3381
some bs code to make things compile
shawntabrizi Aug 19, 2024
ae6fab7
more stuff
shawntabrizi Aug 19, 2024
115f89b
complete logic
shawntabrizi Aug 19, 2024
e5f0056
add verification check
shawntabrizi Aug 19, 2024
766790a
Merge branch 'shawntabrizi-assets-distribution' of https://github.com…
shawntabrizi Sep 2, 2024
b80589c
large refactor to proving trie
shawntabrizi Sep 3, 2024
83c66e7
fix tests
shawntabrizi Sep 3, 2024
5a4ff43
use basic proving trie
shawntabrizi Sep 3, 2024
394cc6f
Merge branch 'master' into shawntabrizi-assets-distribution
shawntabrizi Sep 3, 2024
84574e1
undo changes to binary merkle tree
shawntabrizi Sep 3, 2024
444b1f7
remove comment code
shawntabrizi Sep 3, 2024
f47b12e
make api more runtime friendly
shawntabrizi Sep 3, 2024
0305bc7
Merge remote-tracking branch 'upstream/master' into shawntabrizi-asse…
shawntabrizi Sep 4, 2024
ee90711
add basic test, and fix missing check for tracking distribution
shawntabrizi Sep 6, 2024
61162b6
introduce distribution info and active
shawntabrizi Sep 6, 2024
ae2ff18
introduce end_distribution
shawntabrizi Sep 6, 2024
fb63207
add clean distribution
shawntabrizi Sep 7, 2024
e713698
Merge branch 'master' into shawntabrizi-assets-distribution
shawntabrizi Sep 7, 2024
988b201
weight stuff
shawntabrizi Sep 7, 2024
233d339
temp fix for ui
shawntabrizi Sep 7, 2024
48fe9c6
Merge branch 'master' into pr/5400
shawntabrizi Sep 16, 2024
122f9cc
make work with binary tree
shawntabrizi Sep 17, 2024
59fdc63
initial stuff
shawntabrizi Sep 17, 2024
1f587ef
more
shawntabrizi Sep 17, 2024
dbb8368
Merge branch 'master' into shawntabrizi-binary-trie2
shawntabrizi Sep 17, 2024
f3a1af0
initial stuff
shawntabrizi Sep 17, 2024
daf8f50
more
shawntabrizi Sep 17, 2024
133a440
fix up binary tree
shawntabrizi Sep 17, 2024
813caae
refactor
shawntabrizi Sep 18, 2024
e270275
fixes
shawntabrizi Sep 18, 2024
a679bc9
update api for a single opaque blob
shawntabrizi Sep 18, 2024
be3e6c4
Merge branch 'master' into shawntabrizi-binary-trie2
shawntabrizi Sep 18, 2024
65d2b98
undo changes in assets
shawntabrizi Sep 18, 2024
ed30142
undo weight
shawntabrizi Sep 18, 2024
39e78d7
Update substrate/frame/support/src/traits/proving.rs
shawntabrizi Sep 18, 2024
aabaf76
Merge branch 'master' into shawntabrizi-binary-trie2
shawntabrizi Sep 19, 2024
450b6c6
consolidate apis
shawntabrizi Sep 19, 2024
d153c74
Merge branch 'shawntabrizi-binary-trie2' of https://github.com/parity…
shawntabrizi Sep 19, 2024
240a777
create a proving trie trait
shawntabrizi Sep 19, 2024
0f1e28b
implement trait for base2
shawntabrizi Sep 19, 2024
375dc12
fix tests
shawntabrizi Sep 19, 2024
99135e4
Merge branch 'master' into shawntabrizi-binary-trie2
shawntabrizi Sep 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

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

18 changes: 15 additions & 3 deletions substrate/frame/support/src/traits/proving.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ 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;
type Proof: Encode + Decode;
/// The hash type.
type Hash;
type Hash: Encode + Decode;

/// Verify the given `proof`.
///
Expand Down Expand Up @@ -77,7 +77,10 @@ pub struct SixteenPatriciaMerkleTreeExistenceProof {
/// Implements [`VerifyExistenceProof`] using a 16-patricia merkle tree.
pub struct SixteenPatriciaMerkleTreeProver<H>(core::marker::PhantomData<H>);

impl<H: Hasher> VerifyExistenceProof for SixteenPatriciaMerkleTreeProver<H> {
impl<H: Hasher> VerifyExistenceProof for SixteenPatriciaMerkleTreeProver<H>
where
H::Out: Decode + Encode,
shawntabrizi marked this conversation as resolved.
Show resolved Hide resolved
{
type Proof = SixteenPatriciaMerkleTreeExistenceProof;
type Hash = H::Out;

Expand All @@ -92,6 +95,15 @@ impl<H: Hasher> VerifyExistenceProof for SixteenPatriciaMerkleTreeProver<H> {
}
}

/// An implementation which always returns an error when this feature is unavailable.
impl VerifyExistenceProof for () {
type Proof = ();
type Hash = ();
fn verify_proof(_proof: Self::Proof, _root: &Self::Hash) -> Result<Vec<u8>, ()> {
Err(())
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
2 changes: 2 additions & 0 deletions substrate/primitives/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ sp-trie = { workspace = true }
sp-weights = { workspace = true }
docify = { workspace = true }
tracing = { workspace = true, features = ["log"], default-features = false }
binary-merkle-tree = { workspace = true }

simple-mermaid = { version = "0.1.1", optional = true }

Expand Down Expand Up @@ -73,6 +74,7 @@ std = [
"sp-trie/std",
"sp-weights/std",
"tracing/std",
"binary-merkle-tree/std",
]

# Serde support without relying on std features.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,105 +24,14 @@
//! Proofs are created with latest substrate trie format (`LayoutV1`), and are not compatible with
//! proofs using `LayoutV0`.

use crate::{Decode, DispatchError, Encode, MaxEncodedLen, TypeInfo};
#[cfg(feature = "serde")]
use crate::{Deserialize, Serialize};

use super::TrieError;
use crate::{Decode, DispatchError, Encode};
use sp_std::vec::Vec;
use sp_trie::{
trie_types::{TrieDBBuilder, TrieDBMutBuilderV1, TrieError as SpTrieError},
LayoutV1, MemoryDB, Trie, TrieMut, VerifyError,
trie_types::{TrieDBBuilder, TrieDBMutBuilderV1},
LayoutV1, MemoryDB, Trie, TrieMut,
};

type HashOf<Hashing> = <Hashing as sp_core::Hasher>::Out;

/// A runtime friendly error type for tries.
#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, 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.",
}
}
}

/// A helper structure for building a basic base-16 merkle trie and creating compact proofs for that
/// trie. Proofs are created with latest substrate trie format (`LayoutV1`), and are not compatible
/// with proofs using `LayoutV0`.
Expand All @@ -131,7 +40,7 @@ where
Hashing: sp_core::Hasher,
{
db: MemoryDB<Hashing>,
root: HashOf<Hashing>,
root: Hashing::Out,
_phantom: core::marker::PhantomData<(Key, Value)>,
}

Expand Down Expand Up @@ -161,7 +70,7 @@ where
}

/// Access the underlying trie root.
pub fn root(&self) -> &HashOf<Hashing> {
pub fn root(&self) -> &Hashing::Out {
&self.root
}

Expand All @@ -178,31 +87,28 @@ where
}

/// Create a compact merkle proof needed to prove all `keys` and their values are in the trie.
/// Returns `None` if the nodes within the current `MemoryDB` are insufficient to create a
/// proof.
///
/// This function makes a proof with latest substrate trie format (`LayoutV1`), and is not
/// compatible with `LayoutV0`.
///
/// 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_proof(&self, keys: &[Key]) -> Result<Vec<Vec<u8>>, DispatchError> {
pub fn create_proof(&self, keys: &[Key]) -> Result<Vec<u8>, DispatchError> {
sp_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())
}

/// Create a compact merkle proof needed to prove a single key and its value are in the trie.
/// Returns `None` if the nodes within the current `MemoryDB` are insufficient to create a
/// proof.
///
/// This function makes a proof with latest substrate trie format (`LayoutV1`), and is not
/// compatible with `LayoutV0`.
pub fn create_single_value_proof(&self, key: Key) -> Result<Vec<Vec<u8>>, DispatchError> {
pub fn create_single_value_proof(&self, key: Key) -> Result<Vec<u8>, DispatchError> {
self.create_proof(&[key])
}
}
Expand All @@ -211,8 +117,8 @@ where
///
/// Proofs must be created with latest substrate trie format (`LayoutV1`).
pub fn verify_single_value_proof<Hashing, Key, Value>(
root: HashOf<Hashing>,
proof: &[Vec<u8>],
root: Hashing::Out,
proof: &[u8],
key: Key,
maybe_value: Option<Value>,
) -> Result<(), DispatchError>
Expand All @@ -221,9 +127,11 @@ where
Key: Encode,
Value: Encode,
{
let structured_proof: Vec<Vec<u8>> =
Decode::decode(&mut &proof[..]).map_err(|_| TrieError::DecodeError)?;
sp_trie::verify_trie_proof::<LayoutV1<Hashing>, _, _, _>(
&root,
proof,
&structured_proof,
&[(key.encode(), maybe_value.map(|value| value.encode()))],
)
.map_err(|err| TrieError::from(err).into())
Expand All @@ -233,22 +141,28 @@ where
///
/// Proofs must be created with latest substrate trie format (`LayoutV1`).
pub fn verify_proof<Hashing, Key, Value>(
root: HashOf<Hashing>,
proof: &[Vec<u8>],
root: Hashing::Out,
proof: &[u8],
items: &[(Key, Option<Value>)],
) -> Result<(), DispatchError>
where
Hashing: sp_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, maybe_value)| (key.encode(), maybe_value.as_ref().map(|value| value.encode())))
.collect::<Vec<(Vec<u8>, Option<Vec<u8>>)>>();

sp_trie::verify_trie_proof::<LayoutV1<Hashing>, _, _, _>(&root, proof, &items_encoded)
.map_err(|err| TrieError::from(err).into())
sp_trie::verify_trie_proof::<LayoutV1<Hashing>, _, _, _>(
&root,
&structured_proof,
&items_encoded,
)
.map_err(|err| TrieError::from(err).into())
}

#[cfg(test)]
Expand Down Expand Up @@ -382,10 +296,13 @@ mod tests {
Err(TrieError::RootMismatch.into())
);

// Fail to verify proof with wrong data
// Crete a bad proof.
let bad_proof = balance_trie.create_single_value_proof(99u32).unwrap();

// Fail to verify data with the wrong proof
assert_eq!(
verify_single_value_proof::<BlakeTwo256, _, _>(root, &[], 6u32, Some(6u128)),
Err(TrieError::IncompleteProof.into())
verify_single_value_proof::<BlakeTwo256, _, _>(root, &bad_proof, 6u32, Some(6u128)),
Err(TrieError::ExtraneousHashReference.into())
);
}
}
Loading
Loading