0g-storage-node/common/merkle_light/src/lib.rs
peilun-conflux 4eb2a50b0e
Use inner lock in storage and use async lock. (#92)
* Use inner lock in storage.

* Remove mut.

* Remove async lock for storage.

* Fix tests and warnings.

* Use spawn_blocking for storage task.

* Fix clippy.

* Finalize the new tx at last.

* Revert "Finalize the new tx at last."

This reverts commit b56ad5582d.

* Wait for old same-root txs to finalize.

* Use async storage in miner.

* Update rust version to 1.79.0.

* Use Vec to avoid stack overflow.

* Fix unused warning.

* Fix clippy.

* Fix test warning.

* Fix test.

* fmt.

* Use async storage in pruner.

* nit.
2024-06-29 17:08:02 +08:00

178 lines
5.5 KiB
Rust

//! light _Merkle Tree_ implementation.
//!
//! Merkle tree (MT) implemented as a full binary tree allocated as a vec
//! of statically sized hashes to give hashes more locality. MT specialized
//! to the extent of hashing algorithm and hash item. [`Hashable`] trait is
//! compatible to the `std::hash::Hasher` and supports custom hash algorithms.
//! Implementation does not depend on any external crypto libraries, and tries
//! to be as performant as possible.
//!
//! This tree implementation uses encoding scheme as in _Certificate Transparency_
//! by default. Encoding scheme for leafs and nodes can be overridden though.
//! [RFC 6962](https://tools.ietf.org/html/rfc6962):
//!
//! ```text
//! MTH({d(0)}) = ALG(0x00 || d(0)).
//! For n > 1, let k be the largest power of two smaller than n (i.e.,
//! k < n <= 2k). The Merkle tree Hash of an n-element list D[n] is then
//! defined recursively as
//! MTH(D[n]) = ALG(0x01 || MTH(D[0:k]) || MTH(D[k:n])),
//! ```
//!
//! Link: [](https://en.wikipedia.org/wiki/Merkle_tree)
//!
//! # Implementation choices
//!
//! Main idea is the whole code must obtain specialization at compile time with
//! minimum allocations calls, hashes must be of fixed size arrays known at
//! compile time, hash algorithm must be a trait and must not depend on any
//! external cryptographic libraries and the lib itself must somehow mimic std Rust api.
//!
//! Standard way in Rust is to hash objects with a `std::hash::Hasher`, and mainly
//! that is the reason behind the choice of the abstractions:
//!
//! `Object : Hashable<H> -> Hasher + Algorithm <- Merkle Tree`
//!
//! Custom [`merkle::hash::Hashable`] trait allows implementations differ
//! from [`std::collection`] related hashes, different implementations for
//! different hashing algorithms / schemas and conforms object-safety trait rules.
//!
//! [`Algorithm`] complements [`Hasher`] to be reusable and follows the idea
//! that the result hash is a mapping of the data stream.
//!
//! [`Algorithm.hash`] had to change its signature to be `&mut self` (`&self`) because
//! most of the cryptographic digest algorithms breaks current state on finalization
//! into unusable. `ring` libra tho contains interfaces incompatible to
//! `start-update-finish-reset` lifecycle. It requires either `cloning()` its state
//! on finalization, or `Cell`-ing via unsafe.
//!
//! Turning back to having [`Algorithm.write(&mut self, &[u8])`] instead of
//! `write(T)` allows to relax [`Algorithm`] trait [`Hasher`] constraint, even tho
//! works together well still.
//!
//! # Interface
//!
//! ```text
//! - build_tree (items) -> tree
//! - get_root -> hash
//! - gen_proof -> proof
//! - validate_proof (proof, leaf, root) -> bool
//! ```
//!
//! # Examples
//!
//! [`test_cmh.rs`]: custom merkle hasher implementation example
//! [`crypto_bitcoin_mt.rs`]: bitcoin merkle tree using crypto lib
//! [`crypto_chaincore_mt.rs`]: chain core merkle tree using crypto lib
//! [`ring_bitcoin_mt.rs`]: bitcoin merkle tree using ring lib
//!
//! # Quick start
//!
//! ```
//! #[cfg(feature = "chaincore")]
//! extern crate crypto;
//! extern crate merkle_light;
//!
//! #[cfg(feature = "chaincore")]
//! mod example {
//! use std::fmt;
//! use std::hash::Hasher;
//! use std::iter::FromIterator;
//! use crypto::sha3::{Sha3, Sha3Mode};
//! use crypto::digest::Digest;
//! use merkle_light::hash::{Algorithm, Hashable};
//!
//! pub struct ExampleAlgorithm(Sha3);
//!
//! impl ExampleAlgorithm {
//! pub fn new() -> ExampleAlgorithm {
//! ExampleAlgorithm(Sha3::new(Sha3Mode::Sha3_256))
//! }
//! }
//!
//! impl Default for ExampleAlgorithm {
//! fn default() -> ExampleAlgorithm {
//! ExampleAlgorithm::new()
//! }
//! }
//!
//! impl Hasher for ExampleAlgorithm {
//! #[inline]
//! fn write(&mut self, msg: &[u8]) {
//! self.0.input(msg)
//! }
//!
//! #[inline]
//! fn finish(&self) -> u64 {
//! unimplemented!()
//! }
//! }
//!
//! impl Algorithm<[u8; 32]> for ExampleAlgorithm {
//! #[inline]
//! fn hash(&mut self) -> [u8; 32] {
//! let mut h = [0u8; 32];
//! self.0.result(&mut h);
//! h
//! }
//!
//! #[inline]
//! fn reset(&mut self) {
//! self.0.reset();
//! }
//! }
//! }
//!
//! fn main() {
//! #[cfg(feature = "chaincore")]
//! {
//! use example::ExampleAlgorithm;
//! use merkle_light::merkle::MerkleTree;
//! use std::iter::FromIterator;
//!
//! let mut h1 = [0u8; 32];
//! let mut h2 = [0u8; 32];
//! let mut h3 = [0u8; 32];
//! h1[0] = 0x11;
//! h2[0] = 0x22;
//! h3[0] = 0x33;
//!
//! let t: MerkleTree<[u8; 32], ExampleAlgorithm> = MerkleTree::from_iter(vec![h1, h2, h3]);
//! println!("{:?}", t.root());
//! }
//! }
//! ```
#![deny(
missing_docs,
unused_qualifications,
missing_debug_implementations,
missing_copy_implementations,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces
)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "nightly", allow(unstable_features))]
/// Hash infrastructure for items in Merkle tree.
pub mod hash;
/// Common implementations for [`Hashable`].
mod hash_impl;
/// Merkle tree inclusion proof
pub mod proof;
/// Merkle tree abstractions, implementation and algorithms.
pub mod merkle;
/// Tests data.
#[cfg(test)]
mod test_item;
/// Tests for Merkle Hasher Customization
#[cfg(test)]
mod test_cmh;