pub mod base16;
pub mod base2;
use crate::{Decode, DispatchError, Encode, MaxEncodedLen, TypeInfo};
#[cfg(feature = "serde")]
use crate::{Deserialize, Serialize};
use sp_std::vec::Vec;
use sp_trie::{trie_types::TrieError as SpTrieError, VerifyError};
#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TrieError {
InvalidStateRoot,
IncompleteDatabase,
ValueAtIncompleteKey,
DecoderError,
InvalidHash,
DuplicateKey,
ExtraneousNode,
ExtraneousValue,
ExtraneousHashReference,
InvalidChildReference,
ValueMismatch,
IncompleteProof,
RootMismatch,
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.",
}
}
}
pub trait ProvingTrie<Hashing, Key, Value>
where
Self: Sized,
Hashing: sp_core::Hasher,
{
fn generate_for<I>(items: I) -> Result<Self, DispatchError>
where
I: IntoIterator<Item = (Key, Value)>;
fn root(&self) -> &Hashing::Out;
fn query(&self, key: &Key) -> Option<Value>;
fn create_proof(&self, key: &Key) -> Result<Vec<u8>, DispatchError>;
fn verify_proof(
root: &Hashing::Out,
proof: &[u8],
key: &Key,
value: &Value,
) -> Result<(), DispatchError>;
}
pub trait ProofToHashes {
type Proof: ?Sized;
fn proof_to_hashes(proof: &Self::Proof) -> Result<u32, DispatchError>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::traits::BlakeTwo256;
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(()));
}
}