mod cache;
mod error;
mod mpt;
mod nibbles;
mod node;
pub mod proof;
mod smt;
#[cfg(test)]
mod test;
pub use error::{Result, TrieError};
pub use mpt::MptProof;
pub use proof::VerMapWithProof;
pub use smt::SmtProof;
use mpt::{TrieMut, TrieRo};
use node::NodeHandle;
pub trait TrieCalc: Clone + Default {
fn from_entries(
kvs: impl IntoIterator<Item = (impl AsRef<[u8]>, impl AsRef<[u8]>)>,
) -> Result<Self>;
fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>>;
fn insert(&mut self, key: &[u8], value: &[u8]) -> Result<()>;
fn remove(&mut self, key: &[u8]) -> Result<()>;
fn root_hash(&mut self) -> Result<Vec<u8>>;
fn batch_update(&mut self, ops: &[(&[u8], Option<&[u8]>)]) -> Result<()>;
fn save_cache(&mut self, cache_id: u64, sync_tag: u64) -> Result<()>;
fn load_cache(cache_id: u64) -> Result<(Self, u64, Vec<u8>)>;
}
#[derive(Clone)]
pub struct MptCalc {
root: NodeHandle,
}
impl Default for MptCalc {
fn default() -> Self {
Self::new()
}
}
impl MptCalc {
pub fn new() -> Self {
Self {
root: NodeHandle::default(),
}
}
pub fn from_entries(
kvs: impl IntoIterator<Item = (impl AsRef<[u8]>, impl AsRef<[u8]>)>,
) -> Result<Self> {
let mut calc = Self::new();
for (k, v) in kvs {
calc.insert(k.as_ref(), v.as_ref())?;
}
Ok(calc)
}
pub fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
let trie = TrieRo::new(&self.root);
trie.get(key)
}
pub fn insert(&mut self, key: &[u8], value: &[u8]) -> Result<()> {
let mut trie = TrieMut::new(std::mem::take(&mut self.root));
trie.insert(key, value)?;
self.root = trie.into_root();
Ok(())
}
pub fn remove(&mut self, key: &[u8]) -> Result<()> {
let mut trie = TrieMut::new(std::mem::take(&mut self.root));
trie.remove(key)?;
self.root = trie.into_root();
Ok(())
}
pub fn root_hash(&mut self) -> Result<Vec<u8>> {
let trie = TrieMut::new(std::mem::take(&mut self.root));
let (hash, new_root) = trie.commit()?;
self.root = new_root;
Ok(hash)
}
pub fn batch_update(&mut self, ops: &[(&[u8], Option<&[u8]>)]) -> Result<()> {
let mut trie = TrieMut::new(std::mem::take(&mut self.root));
for (key, val) in ops {
if let Some(v) = val {
trie.insert(key, v)?;
} else {
trie.remove(key)?;
}
}
self.root = trie.into_root();
Ok(())
}
pub fn prove(&self, key: &[u8]) -> Result<MptProof> {
mpt::proof::prove(&self.root, key)
}
pub fn verify_proof(
root_hash: &[u8; 32],
expected_key: &[u8],
proof: &MptProof,
) -> Result<bool> {
mpt::proof::verify_proof(root_hash, expected_key, proof)
}
pub fn save_cache(&mut self, cache_id: u64, sync_tag: u64) -> Result<()> {
let hash = self.root_hash()?;
let path = vsdb_core::common::vsdb_get_custom_dir()
.join(format!("mpt_cache_{}.bin", cache_id));
cache::save_to_file(&self.root, sync_tag, &hash, &path)
}
pub fn load_cache(cache_id: u64) -> Result<(Self, u64, Vec<u8>)> {
let path = vsdb_core::common::vsdb_get_custom_dir()
.join(format!("mpt_cache_{}.bin", cache_id));
let (root, sync_tag, root_hash) = cache::load_from_file(&path)?;
Ok((Self { root }, sync_tag, root_hash))
}
}
impl TrieCalc for MptCalc {
fn from_entries(
kvs: impl IntoIterator<Item = (impl AsRef<[u8]>, impl AsRef<[u8]>)>,
) -> Result<Self> {
Self::from_entries(kvs)
}
fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
self.get(key)
}
fn insert(&mut self, key: &[u8], value: &[u8]) -> Result<()> {
self.insert(key, value)
}
fn remove(&mut self, key: &[u8]) -> Result<()> {
self.remove(key)
}
fn root_hash(&mut self) -> Result<Vec<u8>> {
self.root_hash()
}
fn batch_update(&mut self, ops: &[(&[u8], Option<&[u8]>)]) -> Result<()> {
self.batch_update(ops)
}
fn save_cache(&mut self, cache_id: u64, sync_tag: u64) -> Result<()> {
self.save_cache(cache_id, sync_tag)
}
fn load_cache(cache_id: u64) -> Result<(Self, u64, Vec<u8>)> {
Self::load_cache(cache_id)
}
}
#[derive(Clone)]
pub struct SmtCalc {
root: smt::SmtHandle,
}
impl Default for SmtCalc {
fn default() -> Self {
Self::new()
}
}
impl SmtCalc {
pub fn new() -> Self {
Self {
root: smt::SmtHandle::default(),
}
}
pub fn from_entries(
kvs: impl IntoIterator<Item = (impl AsRef<[u8]>, impl AsRef<[u8]>)>,
) -> Result<Self> {
let mut calc = Self::new();
for (k, v) in kvs {
calc.insert(k.as_ref(), v.as_ref())?;
}
Ok(calc)
}
pub fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
let key_hash = Self::hash_key(key);
let ro = smt::query::SmtRo::new(&self.root);
ro.get(&key_hash)
}
pub fn insert(&mut self, key: &[u8], value: &[u8]) -> Result<()> {
let key_hash = Self::hash_key(key);
let mut m = smt::mutation::SmtMut::new(std::mem::take(&mut self.root));
m.insert(&key_hash, value)?;
self.root = m.into_root();
Ok(())
}
pub fn remove(&mut self, key: &[u8]) -> Result<()> {
let key_hash = Self::hash_key(key);
let mut m = smt::mutation::SmtMut::new(std::mem::take(&mut self.root));
m.remove(&key_hash)?;
self.root = m.into_root();
Ok(())
}
pub fn root_hash(&mut self) -> Result<Vec<u8>> {
let m = smt::mutation::SmtMut::new(std::mem::take(&mut self.root));
let (hash, new_root) = m.commit()?;
self.root = new_root;
Ok(hash)
}
pub fn batch_update(&mut self, ops: &[(&[u8], Option<&[u8]>)]) -> Result<()> {
let mut m = smt::mutation::SmtMut::new(std::mem::take(&mut self.root));
for (key, val) in ops {
let key_hash = Self::hash_key(key);
if let Some(v) = val {
m.insert(&key_hash, v)?;
} else {
m.remove(&key_hash)?;
}
}
self.root = m.into_root();
Ok(())
}
pub fn prove(&self, key: &[u8]) -> Result<SmtProof> {
let key_hash = Self::hash_key(key);
smt::proof::prove(&self.root, &key_hash)
}
pub fn verify_proof(root_hash: &[u8; 32], proof: &SmtProof) -> Result<bool> {
smt::proof::verify_proof(root_hash, proof)
}
pub fn save_cache(&mut self, cache_id: u64, sync_tag: u64) -> Result<()> {
let hash = self.root_hash()?;
let path = vsdb_core::common::vsdb_get_custom_dir()
.join(format!("smt_cache_{}.bin", cache_id));
smt::cache::save_to_file(&self.root, sync_tag, &hash, &path)
}
pub fn load_cache(cache_id: u64) -> Result<(Self, u64, Vec<u8>)> {
let path = vsdb_core::common::vsdb_get_custom_dir()
.join(format!("smt_cache_{}.bin", cache_id));
let (root, sync_tag, root_hash) = smt::cache::load_from_file(&path)?;
Ok((Self { root }, sync_tag, root_hash))
}
fn hash_key(key: &[u8]) -> [u8; 32] {
use sha3::{Digest, Keccak256};
Keccak256::digest(key).into()
}
}
impl TrieCalc for SmtCalc {
fn from_entries(
kvs: impl IntoIterator<Item = (impl AsRef<[u8]>, impl AsRef<[u8]>)>,
) -> Result<Self> {
Self::from_entries(kvs)
}
fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
self.get(key)
}
fn insert(&mut self, key: &[u8], value: &[u8]) -> Result<()> {
self.insert(key, value)
}
fn remove(&mut self, key: &[u8]) -> Result<()> {
self.remove(key)
}
fn root_hash(&mut self) -> Result<Vec<u8>> {
self.root_hash()
}
fn batch_update(&mut self, ops: &[(&[u8], Option<&[u8]>)]) -> Result<()> {
self.batch_update(ops)
}
fn save_cache(&mut self, cache_id: u64, sync_tag: u64) -> Result<()> {
self.save_cache(cache_id, sync_tag)
}
fn load_cache(cache_id: u64) -> Result<(Self, u64, Vec<u8>)> {
Self::load_cache(cache_id)
}
}