From fea5ad59195b6dd15c7a50209a900a0c60e921d2 Mon Sep 17 00:00:00 2001 From: Martin Paulucci Date: Tue, 18 Feb 2025 18:57:31 +0100 Subject: [PATCH] refactor(core): move trie db implementations to store crate. (#1973) **Motivation** To avoid the `trie` crate from being coupled with db implementations, and having to deal with feature flags. **Description** - Moved the TrieDB implementations (libmdx and redb) to `store` crate, so that the `trie` crate becomes implementation agnostic - Unfortunately, we still need the `libmdx` flag, because of https://github.com/lambdaclass/ethrex/blob/39470aa58742ab60fd12625beb807e4e21f0a0d3/crates/storage/trie/node_hash.rs#L93-L110 . We can't implement that trait from within `store`. --- Cargo.lock | 3 +- cmd/ethrex/Cargo.toml | 3 +- crates/blockchain/Cargo.toml | 3 - crates/common/Cargo.toml | 2 - crates/storage/store/Cargo.toml | 5 +- crates/storage/store/engines/libmdbx.rs | 4 +- crates/storage/store/engines/redb.rs | 9 +- crates/storage/store/storage.rs | 1 + crates/storage/store/trie_db/libmdbx.rs | 222 ++++++++++++++++++ .../db => store/trie_db}/libmdbx_dupsort.rs | 24 +- crates/storage/store/trie_db/mod.rs | 11 + crates/storage/store/trie_db/redb.rs | 74 ++++++ .../storage/store/trie_db/redb_multitable.rs | 100 ++++++++ crates/storage/store/trie_db/test_utils.rs | 32 +++ .../{trie/db => store/trie_db}/utils.rs | 0 crates/storage/trie/Cargo.toml | 2 - crates/storage/trie/db.rs | 55 ++++- crates/storage/trie/db/in_memory.rs | 46 ---- crates/storage/trie/db/libmdbx.rs | 98 -------- crates/storage/trie/db/redb.rs | 48 ---- crates/storage/trie/db/redb_multitable.rs | 70 ------ crates/storage/trie/error.rs | 20 +- crates/storage/trie/state.rs | 2 +- crates/storage/trie/test_utils.rs | 33 --- crates/storage/trie/trie.rs | 156 +----------- crates/vm/Cargo.toml | 1 - 26 files changed, 515 insertions(+), 509 deletions(-) create mode 100644 crates/storage/store/trie_db/libmdbx.rs rename crates/storage/{trie/db => store/trie_db}/libmdbx_dupsort.rs (82%) create mode 100644 crates/storage/store/trie_db/mod.rs create mode 100644 crates/storage/store/trie_db/redb.rs create mode 100644 crates/storage/store/trie_db/redb_multitable.rs create mode 100644 crates/storage/store/trie_db/test_utils.rs rename crates/storage/{trie/db => store/trie_db}/utils.rs (100%) delete mode 100644 crates/storage/trie/db/in_memory.rs delete mode 100644 crates/storage/trie/db/libmdbx.rs delete mode 100644 crates/storage/trie/db/redb.rs delete mode 100644 crates/storage/trie/db/redb_multitable.rs diff --git a/Cargo.lock b/Cargo.lock index d6b7e8b25a..8b5f0cbdea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2809,7 +2809,6 @@ dependencies = [ "hex", "k256", "lazy_static", - "libmdbx", "local-ip-address", "rand 0.8.5", "redb", @@ -3098,6 +3097,7 @@ dependencies = [ "serde", "serde_json", "sha3", + "tempdir", "thiserror 2.0.9", "tracing", ] @@ -3118,7 +3118,6 @@ dependencies = [ "lazy_static", "libmdbx", "proptest", - "redb", "serde", "serde_json", "sha3", diff --git a/cmd/ethrex/Cargo.toml b/cmd/ethrex/Cargo.toml index 7e9f09b1a4..9d33b04904 100644 --- a/cmd/ethrex/Cargo.toml +++ b/cmd/ethrex/Cargo.toml @@ -28,7 +28,6 @@ anyhow = "1.0.86" rand = "0.8.5" local-ip-address = "0.6" tokio-util.workspace = true -libmdbx = { workspace = true, optional = true } redb = { workspace = true, optional = true } lazy_static.workspace = true @@ -46,7 +45,7 @@ default = ["libmdbx", "c-kzg", "blst"] dev = ["dep:ethrex-dev"] c-kzg = ["ethrex-vm/c-kzg", "ethrex-common/c-kzg", "ethrex-blockchain/c-kzg", "ethrex-p2p/c-kzg"] metrics = ["ethrex-blockchain/metrics", "ethrex-l2/metrics"] -libmdbx = ["dep:libmdbx", "ethrex-storage/libmdbx"] +libmdbx = ["ethrex-storage/libmdbx"] redb = ["dep:redb", "ethrex-storage/redb"] blst = ["ethrex-vm/blst"] l2 = ["dep:ethrex-l2", "ethrex-vm/l2"] diff --git a/crates/blockchain/Cargo.toml b/crates/blockchain/Cargo.toml index 4a30a964e2..c69496c798 100644 --- a/crates/blockchain/Cargo.toml +++ b/crates/blockchain/Cargo.toml @@ -18,8 +18,6 @@ tracing.workspace = true bytes.workspace = true cfg-if = "1.0.0" - - k256 = { version = "0.13.3", features = ["ecdh"] } ethrex-metrics = { path = "./metrics", default-features = false } @@ -33,6 +31,5 @@ path = "./blockchain.rs" [features] default = [] -libmdbx = ["ethrex-common/libmdbx", "ethrex-storage/default", "ethrex-vm/libmdbx"] c-kzg = ["ethrex-common/c-kzg", "ethrex-vm/c-kzg", "ethrex-levm/c-kzg"] metrics = ["ethrex-metrics/transactions"] diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 6e73a30663..702e1e71e2 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -32,8 +32,6 @@ hex-literal.workspace = true [features] default = [] -libmdbx = ["ethrex-trie/libmdbx"] -redb = ["ethrex-trie/redb"] c-kzg = ["dep:c-kzg"] [lib] diff --git a/crates/storage/store/Cargo.toml b/crates/storage/store/Cargo.toml index 1e9293aebd..f19bd16b2f 100644 --- a/crates/storage/store/Cargo.toml +++ b/crates/storage/store/Cargo.toml @@ -24,12 +24,13 @@ redb = { workspace = true, optional = true } [features] default = [] -libmdbx = ["dep:libmdbx", "ethrex-trie/libmdbx", "ethrex-common/libmdbx"] -redb = ["dep:redb", "ethrex-trie/redb", "ethrex-common/redb"] +libmdbx = ["dep:libmdbx", "ethrex-trie/libmdbx"] +redb = ["dep:redb"] [dev-dependencies] hex.workspace = true hex-literal.workspace = true +tempdir = "0.3.7" [lib] path = "./storage.rs" diff --git a/crates/storage/store/engines/libmdbx.rs b/crates/storage/store/engines/libmdbx.rs index 528246fd21..44dc9ac7f8 100644 --- a/crates/storage/store/engines/libmdbx.rs +++ b/crates/storage/store/engines/libmdbx.rs @@ -6,6 +6,8 @@ use crate::rlp::{ BlockHashRLP, BlockHeaderRLP, BlockRLP, BlockTotalDifficultyRLP, ReceiptRLP, Rlp, TransactionHashRLP, TupleRLP, }; +use crate::trie_db::libmdbx::LibmdbxTrieDB; +use crate::trie_db::libmdbx_dupsort::LibmdbxDupsortTrieDB; use crate::{MAX_SNAPSHOT_READS, STATE_TRIE_SEGMENTS}; use anyhow::Result; use bytes::Bytes; @@ -17,7 +19,7 @@ use ethrex_common::types::{ use ethrex_rlp::decode::RLPDecode; use ethrex_rlp::encode::RLPEncode; use ethrex_rlp::error::RLPDecodeError; -use ethrex_trie::{LibmdbxDupsortTrieDB, LibmdbxTrieDB, Nibbles, Trie}; +use ethrex_trie::{Nibbles, Trie}; use libmdbx::orm::{Decodable, Encodable, Table}; use libmdbx::{ dupsort, diff --git a/crates/storage/store/engines/redb.rs b/crates/storage/store/engines/redb.rs index 144da05d07..dc49d872ab 100644 --- a/crates/storage/store/engines/redb.rs +++ b/crates/storage/store/engines/redb.rs @@ -9,10 +9,7 @@ use ethrex_rlp::decode::RLPDecode; use ethrex_rlp::encode::RLPEncode; use ethrex_rlp::error::RLPDecodeError; use ethrex_trie::Nibbles; -use ethrex_trie::{ - db::{redb::RedBTrie, redb_multitable::RedBMultiTableTrieDB}, - Trie, -}; + use redb::{AccessGuard, Database, Key, MultimapTableDefinition, TableDefinition, TypeName, Value}; use crate::rlp::{ @@ -26,6 +23,10 @@ use crate::{ TupleRLP, }, }; +use crate::{ + trie_db::{redb::RedBTrie, redb_multitable::RedBMultiTableTrieDB}, + Trie, +}; use super::utils::SnapStateIndex; use super::{api::StoreEngine, utils::ChainDataIndex}; diff --git a/crates/storage/store/storage.rs b/crates/storage/store/storage.rs index e45a07c65d..774d9eb970 100644 --- a/crates/storage/store/storage.rs +++ b/crates/storage/store/storage.rs @@ -25,6 +25,7 @@ use tracing::info; mod engines; pub mod error; mod rlp; +mod trie_db; /// Number of state trie segments to fetch concurrently during state sync pub const STATE_TRIE_SEGMENTS: usize = 2; diff --git a/crates/storage/store/trie_db/libmdbx.rs b/crates/storage/store/trie_db/libmdbx.rs new file mode 100644 index 0000000000..67c602f888 --- /dev/null +++ b/crates/storage/store/trie_db/libmdbx.rs @@ -0,0 +1,222 @@ +use ethrex_trie::error::TrieError; +use libmdbx::orm::{Database, Table}; +use std::{marker::PhantomData, sync::Arc}; +/// Libmdbx implementation for the TrieDB trait, with get and put operations. +pub struct LibmdbxTrieDB { + db: Arc, + phantom: PhantomData, +} + +use ethrex_trie::TrieDB; + +impl LibmdbxTrieDB +where + T: Table, Value = Vec>, +{ + pub fn new(db: Arc) -> Self { + Self { + db, + phantom: PhantomData, + } + } +} + +impl TrieDB for LibmdbxTrieDB +where + T: Table, Value = Vec>, +{ + fn get(&self, key: Vec) -> Result>, TrieError> { + let txn = self.db.begin_read().map_err(TrieError::DbError)?; + txn.get::(key).map_err(TrieError::DbError) + } + + fn put(&self, key: Vec, value: Vec) -> Result<(), TrieError> { + let txn = self.db.begin_readwrite().map_err(TrieError::DbError)?; + txn.upsert::(key, value).map_err(TrieError::DbError)?; + txn.commit().map_err(TrieError::DbError) + } + + fn put_batch(&self, key_values: Vec<(Vec, Vec)>) -> Result<(), TrieError> { + let txn = self.db.begin_readwrite().map_err(TrieError::DbError)?; + for (key, value) in key_values { + txn.upsert::(key, value).map_err(TrieError::DbError)?; + } + txn.commit().map_err(TrieError::DbError) + } +} + +#[cfg(test)] +mod test { + use super::LibmdbxTrieDB; + use crate::trie_db::test_utils::libmdbx::{new_db, TestNodes}; + use ethrex_trie::Trie; + use ethrex_trie::TrieDB; + use libmdbx::{ + orm::{table, Database}, + table_info, + }; + use std::sync::Arc; + use tempdir::TempDir; + + #[test] + fn simple_addition() { + table!( + /// NodeHash to Node table + ( Nodes ) Vec => Vec + ); + let inner_db = new_db::(); + let db = LibmdbxTrieDB::::new(inner_db); + assert_eq!(db.get("hello".into()).unwrap(), None); + db.put("hello".into(), "value".into()).unwrap(); + assert_eq!(db.get("hello".into()).unwrap(), Some("value".into())); + } + + #[test] + fn different_tables() { + table!( + /// vec to vec + ( TableA ) Vec => Vec + ); + table!( + /// vec to vec + ( TableB ) Vec => Vec + ); + let tables = [table_info!(TableA), table_info!(TableB)] + .into_iter() + .collect(); + + let inner_db = Arc::new(Database::create(None, &tables).unwrap()); + let db_a = LibmdbxTrieDB::::new(inner_db.clone()); + let db_b = LibmdbxTrieDB::::new(inner_db.clone()); + db_a.put("hello".into(), "value".into()).unwrap(); + assert_eq!(db_b.get("hello".into()).unwrap(), None); + } + + #[test] + fn get_old_state() { + let db = new_db::(); + let mut trie = Trie::new(Box::new(LibmdbxTrieDB::::new(db.clone()))); + + trie.insert([0; 32].to_vec(), [0; 32].to_vec()).unwrap(); + trie.insert([1; 32].to_vec(), [1; 32].to_vec()).unwrap(); + + let root = trie.hash().unwrap(); + + trie.insert([0; 32].to_vec(), [2; 32].to_vec()).unwrap(); + trie.insert([1; 32].to_vec(), [3; 32].to_vec()).unwrap(); + + assert_eq!(trie.get(&[0; 32].to_vec()).unwrap(), Some([2; 32].to_vec())); + assert_eq!(trie.get(&[1; 32].to_vec()).unwrap(), Some([3; 32].to_vec())); + + let trie = Trie::open(Box::new(LibmdbxTrieDB::::new(db.clone())), root); + + assert_eq!(trie.get(&[0; 32].to_vec()).unwrap(), Some([0; 32].to_vec())); + assert_eq!(trie.get(&[1; 32].to_vec()).unwrap(), Some([1; 32].to_vec())); + } + + #[test] + fn get_old_state_with_removals() { + let db = new_db::(); + let mut trie = Trie::new(Box::new(LibmdbxTrieDB::::new(db.clone()))); + + trie.insert([0; 32].to_vec(), [0; 32].to_vec()).unwrap(); + trie.insert([1; 32].to_vec(), [1; 32].to_vec()).unwrap(); + trie.insert([2; 32].to_vec(), [2; 32].to_vec()).unwrap(); + + let root = trie.hash().unwrap(); + + trie.insert([0; 32].to_vec(), vec![0x04]).unwrap(); + trie.remove([1; 32].to_vec()).unwrap(); + trie.insert([2; 32].to_vec(), vec![0x05]).unwrap(); + trie.remove([0; 32].to_vec()).unwrap(); + + assert_eq!(trie.get(&[0; 32].to_vec()).unwrap(), None); + assert_eq!(trie.get(&[1; 32].to_vec()).unwrap(), None); + assert_eq!(trie.get(&[2; 32].to_vec()).unwrap(), Some(vec![0x05])); + + let trie = Trie::open(Box::new(LibmdbxTrieDB::::new(db.clone())), root); + + assert_eq!(trie.get(&[0; 32].to_vec()).unwrap(), Some([0; 32].to_vec())); + assert_eq!(trie.get(&[1; 32].to_vec()).unwrap(), Some([1; 32].to_vec())); + assert_eq!(trie.get(&[2; 32].to_vec()).unwrap(), Some([2; 32].to_vec())); + } + + #[test] + fn revert() { + let db = new_db::(); + let mut trie = Trie::new(Box::new(LibmdbxTrieDB::::new(db.clone()))); + + trie.insert([0; 32].to_vec(), [0; 32].to_vec()).unwrap(); + trie.insert([1; 32].to_vec(), [1; 32].to_vec()).unwrap(); + + let root = trie.hash().unwrap(); + + trie.insert([0; 32].to_vec(), [2; 32].to_vec()).unwrap(); + trie.insert([1; 32].to_vec(), [3; 32].to_vec()).unwrap(); + + let mut trie = Trie::open(Box::new(LibmdbxTrieDB::::new(db.clone())), root); + + trie.insert([2; 32].to_vec(), [4; 32].to_vec()).unwrap(); + + assert_eq!(trie.get(&[0; 32].to_vec()).unwrap(), Some([0; 32].to_vec())); + assert_eq!(trie.get(&[1; 32].to_vec()).unwrap(), Some([1; 32].to_vec())); + assert_eq!(trie.get(&[2; 32].to_vec()).unwrap(), Some([4; 32].to_vec())); + } + + #[test] + fn revert_with_removals() { + let db = new_db::(); + let mut trie = Trie::new(Box::new(LibmdbxTrieDB::::new(db.clone()))); + + trie.insert([0; 32].to_vec(), [0; 32].to_vec()).unwrap(); + trie.insert([1; 32].to_vec(), [1; 32].to_vec()).unwrap(); + trie.insert([2; 32].to_vec(), [2; 32].to_vec()).unwrap(); + + let root = trie.hash().unwrap(); + + trie.insert([0; 32].to_vec(), [4; 32].to_vec()).unwrap(); + trie.remove([1; 32].to_vec()).unwrap(); + trie.insert([2; 32].to_vec(), [5; 32].to_vec()).unwrap(); + trie.remove([0; 32].to_vec()).unwrap(); + + let mut trie = Trie::open(Box::new(LibmdbxTrieDB::::new(db.clone())), root); + + trie.remove([2; 32].to_vec()).unwrap(); + + assert_eq!(trie.get(&[0; 32].to_vec()).unwrap(), Some([0; 32].to_vec())); + assert_eq!(trie.get(&[1; 32].to_vec()).unwrap(), Some([1; 32].to_vec())); + assert_eq!(trie.get(&vec![0x02]).unwrap(), None); + } + + #[test] + fn resume_trie() { + use crate::trie_db::test_utils::libmdbx::{new_db_with_path, open_db}; + + const TRIE_DIR: &str = "trie-db-resume-trie-test"; + let trie_dir = TempDir::new(TRIE_DIR).expect("Failed to create temp dir"); + let trie_dir = trie_dir.path(); + + // Create new trie from clean DB + let db = new_db_with_path::(trie_dir.into()); + let mut trie = Trie::new(Box::new(LibmdbxTrieDB::::new(db.clone()))); + + trie.insert([0; 32].to_vec(), [1; 32].to_vec()).unwrap(); + trie.insert([1; 32].to_vec(), [2; 32].to_vec()).unwrap(); + trie.insert([2; 32].to_vec(), [4; 32].to_vec()).unwrap(); + + // Save current root + let root = trie.hash().unwrap(); + + // Release DB + drop(db); + drop(trie); + + let db2 = open_db::(trie_dir.to_str().unwrap()); + // Create a new trie based on the previous trie's DB + let trie = Trie::open(Box::new(LibmdbxTrieDB::::new(db2)), root); + + assert_eq!(trie.get(&[0; 32].to_vec()).unwrap(), Some([1; 32].to_vec())); + assert_eq!(trie.get(&[1; 32].to_vec()).unwrap(), Some([2; 32].to_vec())); + assert_eq!(trie.get(&[2; 32].to_vec()).unwrap(), Some([4; 32].to_vec())); + } +} diff --git a/crates/storage/trie/db/libmdbx_dupsort.rs b/crates/storage/store/trie_db/libmdbx_dupsort.rs similarity index 82% rename from crates/storage/trie/db/libmdbx_dupsort.rs rename to crates/storage/store/trie_db/libmdbx_dupsort.rs index 5a5c2420ca..398c68fcf1 100644 --- a/crates/storage/trie/db/libmdbx_dupsort.rs +++ b/crates/storage/store/trie_db/libmdbx_dupsort.rs @@ -1,10 +1,10 @@ use std::{marker::PhantomData, sync::Arc}; -use crate::error::TrieError; +use super::utils::node_hash_to_fixed_size; +use ethrex_trie::error::TrieError; +use ethrex_trie::TrieDB; use libmdbx::orm::{Database, DupSort, Encodable}; -use super::{utils::node_hash_to_fixed_size, TrieDB}; - /// Libmdbx implementation for the TrieDB trait for a dupsort table with a fixed primary key. /// For a dupsort table (A, B)[A] -> C, this trie will have a fixed A and just work on B -> C /// A will be a fixed-size encoded key set by the user (of generic type SK), B will be a fixed-size encoded NodeHash and C will be an encoded Node @@ -38,39 +38,39 @@ where SK: Clone + Encodable, { fn get(&self, key: Vec) -> Result>, TrieError> { - let txn = self.db.begin_read().map_err(TrieError::LibmdbxError)?; + let txn = self.db.begin_read().map_err(TrieError::DbError)?; txn.get::((self.fixed_key.clone(), node_hash_to_fixed_size(key))) - .map_err(TrieError::LibmdbxError) + .map_err(TrieError::DbError) } fn put(&self, key: Vec, value: Vec) -> Result<(), TrieError> { - let txn = self.db.begin_readwrite().map_err(TrieError::LibmdbxError)?; + let txn = self.db.begin_readwrite().map_err(TrieError::DbError)?; txn.upsert::( (self.fixed_key.clone(), node_hash_to_fixed_size(key)), value, ) - .map_err(TrieError::LibmdbxError)?; - txn.commit().map_err(TrieError::LibmdbxError) + .map_err(TrieError::DbError)?; + txn.commit().map_err(TrieError::DbError) } fn put_batch(&self, key_values: Vec<(Vec, Vec)>) -> Result<(), TrieError> { - let txn = self.db.begin_readwrite().map_err(TrieError::LibmdbxError)?; + let txn = self.db.begin_readwrite().map_err(TrieError::DbError)?; for (key, value) in key_values { txn.upsert::( (self.fixed_key.clone(), node_hash_to_fixed_size(key)), value, ) - .map_err(TrieError::LibmdbxError)?; + .map_err(TrieError::DbError)?; } - txn.commit().map_err(TrieError::LibmdbxError) + txn.commit().map_err(TrieError::DbError) } } #[cfg(test)] mod test { + use crate::trie_db::test_utils::libmdbx::new_db; use super::*; - use crate::test_utils::libmdbx::new_db; use libmdbx::{dupsort, table}; dupsort!( diff --git a/crates/storage/store/trie_db/mod.rs b/crates/storage/store/trie_db/mod.rs new file mode 100644 index 0000000000..df5ed5be55 --- /dev/null +++ b/crates/storage/store/trie_db/mod.rs @@ -0,0 +1,11 @@ +#[cfg(feature = "libmdbx")] +pub mod libmdbx; +#[cfg(feature = "libmdbx")] +pub mod libmdbx_dupsort; +#[cfg(feature = "redb")] +pub mod redb; +#[cfg(feature = "redb")] +pub mod redb_multitable; +#[cfg(test)] +mod test_utils; +mod utils; diff --git a/crates/storage/store/trie_db/redb.rs b/crates/storage/store/trie_db/redb.rs new file mode 100644 index 0000000000..abe086adc9 --- /dev/null +++ b/crates/storage/store/trie_db/redb.rs @@ -0,0 +1,74 @@ +use std::sync::Arc; + +use ethrex_trie::{TrieDB, TrieError}; +use redb::{Database, TableDefinition}; + +const TABLE: TableDefinition<&[u8], &[u8]> = TableDefinition::new("Trie"); + +pub struct RedBTrie { + db: Arc, +} + +impl RedBTrie { + pub fn new(db: Arc) -> Self { + Self { db } + } +} + +impl TrieDB for RedBTrie { + fn get(&self, key: Vec) -> Result>, TrieError> { + let read_txn = self + .db + .begin_read() + .map_err(|e| TrieError::DbError(e.into()))?; + let table = read_txn + .open_table(TABLE) + .map_err(|e| TrieError::DbError(e.into()))?; + Ok(table + .get(&*key) + .map_err(|e| TrieError::DbError(e.into()))? + .map(|value| value.value().to_vec())) + } + + fn put(&self, key: Vec, value: Vec) -> Result<(), TrieError> { + let write_txn = self + .db + .begin_write() + .map_err(|e| TrieError::DbError(e.into()))?; + { + let mut table = write_txn + .open_table(TABLE) + .map_err(|e| TrieError::DbError(e.into()))?; + table + .insert(&*key, &*value) + .map_err(|e| TrieError::DbError(e.into()))?; + } + write_txn + .commit() + .map_err(|e| TrieError::DbError(e.into()))?; + + Ok(()) + } + + fn put_batch(&self, key_values: Vec<(Vec, Vec)>) -> Result<(), TrieError> { + let write_txn = self + .db + .begin_write() + .map_err(|e| TrieError::DbError(e.into()))?; + { + let mut table = write_txn + .open_table(TABLE) + .map_err(|e| TrieError::DbError(e.into()))?; + for (key, value) in key_values { + table + .insert(&*key, &*value) + .map_err(|e| TrieError::DbError(e.into()))?; + } + } + write_txn + .commit() + .map_err(|e| TrieError::DbError(e.into()))?; + + Ok(()) + } +} diff --git a/crates/storage/store/trie_db/redb_multitable.rs b/crates/storage/store/trie_db/redb_multitable.rs new file mode 100644 index 0000000000..736edeb880 --- /dev/null +++ b/crates/storage/store/trie_db/redb_multitable.rs @@ -0,0 +1,100 @@ +use std::sync::Arc; + +use redb::{Database, MultimapTableDefinition}; + +use ethrex_trie::{TrieDB, TrieError}; + +use super::utils::node_hash_to_fixed_size; + +const STORAGE_TRIE_NODES_TABLE: MultimapTableDefinition<([u8; 32], [u8; 33]), &[u8]> = + MultimapTableDefinition::new("StorageTrieNodes"); + +/// RedB implementation for the TrieDB trait for a dupsort table with a fixed primary key. +/// For a dupsort table (A, B)[A] -> C, this trie will have a fixed A and just work on B -> C +/// A will be a fixed-size encoded key set by the user (of generic type SK), B will be a fixed-size encoded NodeHash and C will be an encoded Node +pub struct RedBMultiTableTrieDB { + db: Arc, + fixed_key: [u8; 32], +} + +impl RedBMultiTableTrieDB { + pub fn new(db: Arc, fixed_key: [u8; 32]) -> Self { + Self { db, fixed_key } + } +} + +impl TrieDB for RedBMultiTableTrieDB { + fn get(&self, key: Vec) -> Result>, TrieError> { + let read_txn = self + .db + .begin_read() + .map_err(|e| TrieError::DbError(e.into()))?; + let table = read_txn + .open_multimap_table(STORAGE_TRIE_NODES_TABLE) + .map_err(|e| TrieError::DbError(e.into()))?; + + let values = table + .get((self.fixed_key, node_hash_to_fixed_size(key))) + .map_err(|e| TrieError::DbError(e.into()))?; + + let mut ret = vec![]; + for value in values { + ret.push( + value + .map_err(|e| TrieError::DbError(e.into()))? + .value() + .to_vec(), + ); + } + + let ret_flattened = ret.concat(); + + if ret.is_empty() { + Ok(None) + } else { + Ok(Some(ret_flattened)) + } + } + + fn put(&self, key: Vec, value: Vec) -> Result<(), TrieError> { + let write_txn = self + .db + .begin_write() + .map_err(|e| TrieError::DbError(e.into()))?; + { + let mut table = write_txn + .open_multimap_table(STORAGE_TRIE_NODES_TABLE) + .map_err(|e| TrieError::DbError(e.into()))?; + table + .insert((self.fixed_key, node_hash_to_fixed_size(key)), &*value) + .map_err(|e| TrieError::DbError(e.into()))?; + } + write_txn + .commit() + .map_err(|e| TrieError::DbError(e.into()))?; + + Ok(()) + } + + fn put_batch(&self, key_values: Vec<(Vec, Vec)>) -> Result<(), TrieError> { + let write_txn = self + .db + .begin_write() + .map_err(|e| TrieError::DbError(e.into()))?; + { + let mut table = write_txn + .open_multimap_table(STORAGE_TRIE_NODES_TABLE) + .map_err(|e| TrieError::DbError(e.into()))?; + for (key, value) in key_values { + table + .insert((self.fixed_key, node_hash_to_fixed_size(key)), &*value) + .map_err(|e| TrieError::DbError(e.into()))?; + } + } + write_txn + .commit() + .map_err(|e| TrieError::DbError(e.into()))?; + + Ok(()) + } +} diff --git a/crates/storage/store/trie_db/test_utils.rs b/crates/storage/store/trie_db/test_utils.rs new file mode 100644 index 0000000000..886a3b7edf --- /dev/null +++ b/crates/storage/store/trie_db/test_utils.rs @@ -0,0 +1,32 @@ +#[cfg(feature = "libmdbx")] +pub mod libmdbx { + use std::{path::PathBuf, sync::Arc}; + + use libmdbx::{ + orm::{table_info, Database, Table}, + table, + }; + + table!( + /// Test table. + (TestNodes) Vec => Vec + ); + + /// Creates a new DB on a given path + pub fn new_db_with_path(path: PathBuf) -> Arc { + let tables = [table_info!(T)].into_iter().collect(); + Arc::new(Database::create(Some(path), &tables).expect("Failed creating db with path")) + } + + /// Creates a new temporary DB + pub fn new_db() -> Arc { + let tables = [table_info!(T)].into_iter().collect(); + Arc::new(Database::create(None, &tables).expect("Failed to create temp DB")) + } + + /// Opens a DB from a given path + pub fn open_db(path: &str) -> Arc { + let tables = [table_info!(T)].into_iter().collect(); + Arc::new(Database::open(path, &tables).expect("Failed to open DB")) + } +} diff --git a/crates/storage/trie/db/utils.rs b/crates/storage/store/trie_db/utils.rs similarity index 100% rename from crates/storage/trie/db/utils.rs rename to crates/storage/store/trie_db/utils.rs diff --git a/crates/storage/trie/Cargo.toml b/crates/storage/trie/Cargo.toml index ca397236a2..fdeeb4c24e 100644 --- a/crates/storage/trie/Cargo.toml +++ b/crates/storage/trie/Cargo.toml @@ -19,12 +19,10 @@ libmdbx = { workspace = true, optional = true } smallvec = { version = "1.10.0", features = ["const_generics", "union"] } digest = "0.10.6" lazy_static.workspace = true -redb = { workspace = true, optional = true } [features] default = [] libmdbx = ["dep:libmdbx"] -redb = ["dep:redb"] [dev-dependencies] hex.workspace = true diff --git a/crates/storage/trie/db.rs b/crates/storage/trie/db.rs index d69e337ed4..b2a92fd32f 100644 --- a/crates/storage/trie/db.rs +++ b/crates/storage/trie/db.rs @@ -1,15 +1,8 @@ -pub mod in_memory; -#[cfg(feature = "libmdbx")] -pub mod libmdbx; -#[cfg(feature = "libmdbx")] -pub mod libmdbx_dupsort; -#[cfg(feature = "redb")] -pub mod redb; -#[cfg(feature = "redb")] -pub mod redb_multitable; -mod utils; - use crate::error::TrieError; +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, +}; pub trait TrieDB { fn get(&self, key: Vec) -> Result>, TrieError>; @@ -17,3 +10,43 @@ pub trait TrieDB { // fn put_batch(&self, key: Vec, value: Vec) -> Result<(), TrieError>; fn put_batch(&self, key_values: Vec<(Vec, Vec)>) -> Result<(), TrieError>; } + +/// InMemory implementation for the TrieDB trait, with get and put operations. +pub struct InMemoryTrieDB { + inner: Arc, Vec>>>, +} + +impl InMemoryTrieDB { + pub fn new(map: Arc, Vec>>>) -> Self { + Self { inner: map } + } +} + +impl TrieDB for InMemoryTrieDB { + fn get(&self, key: Vec) -> Result>, TrieError> { + Ok(self + .inner + .lock() + .map_err(|_| TrieError::LockError)? + .get(&key) + .cloned()) + } + + fn put(&self, key: Vec, value: Vec) -> Result<(), TrieError> { + self.inner + .lock() + .map_err(|_| TrieError::LockError)? + .insert(key, value); + Ok(()) + } + + fn put_batch(&self, key_values: Vec<(Vec, Vec)>) -> Result<(), TrieError> { + let mut db = self.inner.lock().map_err(|_| TrieError::LockError)?; + + for (key, value) in key_values { + db.insert(key, value); + } + + Ok(()) + } +} diff --git a/crates/storage/trie/db/in_memory.rs b/crates/storage/trie/db/in_memory.rs deleted file mode 100644 index f9daa7080c..0000000000 --- a/crates/storage/trie/db/in_memory.rs +++ /dev/null @@ -1,46 +0,0 @@ -use super::TrieDB; -use crate::error::TrieError; -use std::{ - collections::HashMap, - sync::{Arc, Mutex}, -}; - -/// InMemory implementation for the TrieDB trait, with get and put operations. -pub struct InMemoryTrieDB { - inner: Arc, Vec>>>, -} - -impl InMemoryTrieDB { - pub fn new(map: Arc, Vec>>>) -> Self { - Self { inner: map } - } -} - -impl TrieDB for InMemoryTrieDB { - fn get(&self, key: Vec) -> Result>, TrieError> { - Ok(self - .inner - .lock() - .map_err(|_| TrieError::LockError)? - .get(&key) - .cloned()) - } - - fn put(&self, key: Vec, value: Vec) -> Result<(), TrieError> { - self.inner - .lock() - .map_err(|_| TrieError::LockError)? - .insert(key, value); - Ok(()) - } - - fn put_batch(&self, key_values: Vec<(Vec, Vec)>) -> Result<(), TrieError> { - let mut db = self.inner.lock().map_err(|_| TrieError::LockError)?; - - for (key, value) in key_values { - db.insert(key, value); - } - - Ok(()) - } -} diff --git a/crates/storage/trie/db/libmdbx.rs b/crates/storage/trie/db/libmdbx.rs deleted file mode 100644 index 6f6d2d567b..0000000000 --- a/crates/storage/trie/db/libmdbx.rs +++ /dev/null @@ -1,98 +0,0 @@ -use std::{marker::PhantomData, sync::Arc}; - -use crate::error::TrieError; -use libmdbx::orm::{Database, Table}; - -/// Libmdbx implementation for the TrieDB trait, with get and put operations. -pub struct LibmdbxTrieDB { - db: Arc, - phantom: PhantomData, -} - -use super::TrieDB; - -impl LibmdbxTrieDB -where - T: Table, Value = Vec>, -{ - pub fn new(db: Arc) -> Self { - Self { - db, - phantom: PhantomData, - } - } -} - -impl TrieDB for LibmdbxTrieDB -where - T: Table, Value = Vec>, -{ - fn get(&self, key: Vec) -> Result>, TrieError> { - let txn = self.db.begin_read().map_err(TrieError::LibmdbxError)?; - txn.get::(key).map_err(TrieError::LibmdbxError) - } - - fn put(&self, key: Vec, value: Vec) -> Result<(), TrieError> { - let txn = self.db.begin_readwrite().map_err(TrieError::LibmdbxError)?; - txn.upsert::(key, value) - .map_err(TrieError::LibmdbxError)?; - txn.commit().map_err(TrieError::LibmdbxError) - } - - fn put_batch(&self, key_values: Vec<(Vec, Vec)>) -> Result<(), TrieError> { - let txn = self.db.begin_readwrite().map_err(TrieError::LibmdbxError)?; - for (key, value) in key_values { - txn.upsert::(key, value) - .map_err(TrieError::LibmdbxError)?; - } - txn.commit().map_err(TrieError::LibmdbxError) - } -} - -#[cfg(test)] -mod test { - use std::sync::Arc; - - use super::LibmdbxTrieDB; - use crate::test_utils::libmdbx::new_db; - use libmdbx::{ - orm::{table, Database}, - table_info, - }; - table!( - /// NodeHash to Node table - ( Nodes ) Vec => Vec - ); - - use crate::TrieDB; - - #[test] - fn simple_addition() { - let inner_db = new_db::(); - let db = LibmdbxTrieDB::::new(inner_db); - assert_eq!(db.get("hello".into()).unwrap(), None); - db.put("hello".into(), "value".into()).unwrap(); - assert_eq!(db.get("hello".into()).unwrap(), Some("value".into())); - } - - #[test] - fn different_tables() { - table!( - /// vec to vec - ( TableA ) Vec => Vec - ); - table!( - /// vec to vec - ( TableB ) Vec => Vec - ); - let tables = [table_info!(TableA), table_info!(TableB)] - .into_iter() - .collect(); - - let inner_db = Arc::new(Database::create(None, &tables).unwrap()); - let db_a = LibmdbxTrieDB::::new(inner_db.clone()); - let db_b = LibmdbxTrieDB::::new(inner_db.clone()); - db_a.put("hello".into(), "value".into()).unwrap(); - assert_eq!(db_b.get("hello".into()).unwrap(), None); - } -} diff --git a/crates/storage/trie/db/redb.rs b/crates/storage/trie/db/redb.rs deleted file mode 100644 index e7f38c50a9..0000000000 --- a/crates/storage/trie/db/redb.rs +++ /dev/null @@ -1,48 +0,0 @@ -use std::sync::Arc; - -use super::TrieDB; -use redb::{Database, TableDefinition}; - -const TABLE: TableDefinition<&[u8], &[u8]> = TableDefinition::new("Trie"); - -pub struct RedBTrie { - db: Arc, -} - -impl RedBTrie { - pub fn new(db: Arc) -> Self { - Self { db } - } -} - -impl TrieDB for RedBTrie { - fn get(&self, key: Vec) -> Result>, crate::TrieError> { - let read_txn = self.db.begin_read()?; - let table = read_txn.open_table(TABLE)?; - Ok(table.get(&*key)?.map(|value| value.value().to_vec())) - } - - fn put(&self, key: Vec, value: Vec) -> Result<(), crate::TrieError> { - let write_txn = self.db.begin_write()?; - { - let mut table = write_txn.open_table(TABLE)?; - table.insert(&*key, &*value)?; - } - write_txn.commit()?; - - Ok(()) - } - - fn put_batch(&self, key_values: Vec<(Vec, Vec)>) -> Result<(), crate::TrieError> { - let write_txn = self.db.begin_write()?; - { - let mut table = write_txn.open_table(TABLE)?; - for (key, value) in key_values { - table.insert(&*key, &*value)?; - } - } - write_txn.commit()?; - - Ok(()) - } -} diff --git a/crates/storage/trie/db/redb_multitable.rs b/crates/storage/trie/db/redb_multitable.rs deleted file mode 100644 index 0035ab5cf2..0000000000 --- a/crates/storage/trie/db/redb_multitable.rs +++ /dev/null @@ -1,70 +0,0 @@ -use std::sync::Arc; - -use redb::{Database, MultimapTableDefinition}; - -use crate::TrieError; - -use super::{utils::node_hash_to_fixed_size, TrieDB}; - -const STORAGE_TRIE_NODES_TABLE: MultimapTableDefinition<([u8; 32], [u8; 33]), &[u8]> = - MultimapTableDefinition::new("StorageTrieNodes"); - -/// RedB implementation for the TrieDB trait for a dupsort table with a fixed primary key. -/// For a dupsort table (A, B)[A] -> C, this trie will have a fixed A and just work on B -> C -/// A will be a fixed-size encoded key set by the user (of generic type SK), B will be a fixed-size encoded NodeHash and C will be an encoded Node -pub struct RedBMultiTableTrieDB { - db: Arc, - fixed_key: [u8; 32], -} - -impl RedBMultiTableTrieDB { - pub fn new(db: Arc, fixed_key: [u8; 32]) -> Self { - Self { db, fixed_key } - } -} - -impl TrieDB for RedBMultiTableTrieDB { - fn get(&self, key: Vec) -> Result>, TrieError> { - let read_txn = self.db.begin_read()?; - let table = read_txn.open_multimap_table(STORAGE_TRIE_NODES_TABLE)?; - - let values = table.get((self.fixed_key, node_hash_to_fixed_size(key)))?; - - let mut ret = vec![]; - for value in values { - ret.push(value?.value().to_vec()); - } - - let ret_flattened = ret.concat(); - - if ret.is_empty() { - Ok(None) - } else { - Ok(Some(ret_flattened)) - } - } - - fn put(&self, key: Vec, value: Vec) -> Result<(), TrieError> { - let write_txn = self.db.begin_write()?; - { - let mut table = write_txn.open_multimap_table(STORAGE_TRIE_NODES_TABLE)?; - table.insert((self.fixed_key, node_hash_to_fixed_size(key)), &*value)?; - } - write_txn.commit()?; - - Ok(()) - } - - fn put_batch(&self, key_values: Vec<(Vec, Vec)>) -> Result<(), TrieError> { - let write_txn = self.db.begin_write()?; - { - let mut table = write_txn.open_multimap_table(STORAGE_TRIE_NODES_TABLE)?; - for (key, value) in key_values { - table.insert((self.fixed_key, node_hash_to_fixed_size(key)), &*value)?; - } - } - write_txn.commit()?; - - Ok(()) - } -} diff --git a/crates/storage/trie/error.rs b/crates/storage/trie/error.rs index 7b7ffd49dc..14ea2cff42 100644 --- a/crates/storage/trie/error.rs +++ b/crates/storage/trie/error.rs @@ -1,26 +1,8 @@ use ethrex_rlp::error::RLPDecodeError; -#[cfg(feature = "redb")] -use redb::{CommitError, StorageError, TableError, TransactionError}; use thiserror::Error; #[derive(Debug, Error)] pub enum TrieError { - #[cfg(feature = "libmdbx")] - #[error("Libmdbx error: {0}")] - LibmdbxError(anyhow::Error), - #[cfg(feature = "redb")] - #[error("Redb Storage error: {0}")] - RedbStorageError(#[from] StorageError), - #[cfg(feature = "redb")] - #[error("Redb Table error: {0}")] - #[cfg(feature = "redb")] - RedbTableError(#[from] TableError), - #[error("Redb Commit error: {0}")] - #[cfg(feature = "redb")] - RedbCommitError(#[from] CommitError), - #[error("Redb Transaction error: {0}")] - #[cfg(feature = "redb")] - RedbTransactionError(#[from] TransactionError), #[error(transparent)] RLPDecode(#[from] RLPDecodeError), #[error("Verification Error: {0}")] @@ -29,4 +11,6 @@ pub enum TrieError { InconsistentTree, #[error("Lock Error: Panicked when trying to acquire a lock")] LockError, + #[error("Database error: {0}")] + DbError(anyhow::Error), } diff --git a/crates/storage/trie/state.rs b/crates/storage/trie/state.rs index bc849de634..b1d46f4e41 100644 --- a/crates/storage/trie/state.rs +++ b/crates/storage/trie/state.rs @@ -5,7 +5,7 @@ use ethrex_rlp::{decode::RLPDecode, encode::RLPEncode}; use super::db::TrieDB; -/// Libmdbx database representing the trie state +/// Database representing the trie state /// It contains a table mapping node hashes to rlp encoded nodes /// All nodes are stored in the DB and no node is ever removed use super::{node::Node, node_hash::NodeHash}; diff --git a/crates/storage/trie/test_utils.rs b/crates/storage/trie/test_utils.rs index b49ec25880..369a9e2b8d 100644 --- a/crates/storage/trie/test_utils.rs +++ b/crates/storage/trie/test_utils.rs @@ -1,36 +1,3 @@ -#[cfg(feature = "libmdbx")] -pub mod libmdbx { - use std::{path::PathBuf, sync::Arc}; - - use libmdbx::{ - orm::{table_info, Database, Table}, - table, - }; - - table!( - /// Test table. - (TestNodes) Vec => Vec - ); - - /// Creates a new DB on a given path - pub fn new_db_with_path(path: PathBuf) -> Arc { - let tables = [table_info!(T)].into_iter().collect(); - Arc::new(Database::create(Some(path), &tables).expect("Failed creating db with path")) - } - - /// Creates a new temporary DB - pub fn new_db() -> Arc { - let tables = [table_info!(T)].into_iter().collect(); - Arc::new(Database::create(None, &tables).expect("Failed to create temp DB")) - } - - /// Opens a DB from a given path - pub fn open_db(path: &str) -> Arc { - let tables = [table_info!(T)].into_iter().collect(); - Arc::new(Database::open(path, &tables).expect("Failed to open DB")) - } -} - #[macro_export] /// Creates a trie node /// All partial paths are expressed in nibbles and values in bytes diff --git a/crates/storage/trie/trie.rs b/crates/storage/trie/trie.rs index ee61b639a6..3ee69ec322 100644 --- a/crates/storage/trie/trie.rs +++ b/crates/storage/trie/trie.rs @@ -1,5 +1,5 @@ pub mod db; -mod error; +pub mod error; mod nibbles; mod node; mod node_hash; @@ -15,10 +15,7 @@ use node_hash::NodeHash; use sha3::{Digest, Keccak256}; use std::collections::HashSet; -#[cfg(feature = "libmdbx")] -pub use self::db::{libmdbx::LibmdbxTrieDB, libmdbx_dupsort::LibmdbxDupsortTrieDB}; - -pub use self::db::{in_memory::InMemoryTrieDB, TrieDB}; +pub use self::db::{InMemoryTrieDB, TrieDB}; pub use self::nibbles::Nibbles; pub use self::verify_range::verify_range; pub use self::{node::Node, state::TrieState}; @@ -332,16 +329,7 @@ impl Trie { &self.state } - #[cfg(all(test, feature = "libmdbx"))] - /// Creates a new Trie based on a temporary Libmdbx DB - fn new_temp() -> Self { - let db = test_utils::libmdbx::new_db::(); - Trie::new(Box::new( - LibmdbxTrieDB::::new(db), - )) - } - - #[cfg(all(test, not(feature = "libmdbx")))] + #[cfg(test)] /// Creates a new Trie based on a temporary InMemory DB fn new_temp() -> Self { use std::collections::HashMap; @@ -372,13 +360,6 @@ mod test { use super::*; - #[cfg(feature = "libmdbx")] - use crate::test_utils::libmdbx::TestNodes; - #[cfg(feature = "libmdbx")] - use db::libmdbx::LibmdbxTrieDB; - #[cfg(feature = "libmdbx")] - use tempdir::TempDir; - use hasher::HasherKeccak; use hex_literal::hex; use proptest::{ @@ -684,137 +665,6 @@ mod test { ); } - #[cfg(feature = "libmdbx")] - #[test] - fn get_old_state() { - let db = test_utils::libmdbx::new_db::(); - let mut trie = Trie::new(Box::new(LibmdbxTrieDB::::new(db.clone()))); - - trie.insert([0; 32].to_vec(), [0; 32].to_vec()).unwrap(); - trie.insert([1; 32].to_vec(), [1; 32].to_vec()).unwrap(); - - let root = trie.hash().unwrap(); - - trie.insert([0; 32].to_vec(), [2; 32].to_vec()).unwrap(); - trie.insert([1; 32].to_vec(), [3; 32].to_vec()).unwrap(); - - assert_eq!(trie.get(&[0; 32].to_vec()).unwrap(), Some([2; 32].to_vec())); - assert_eq!(trie.get(&[1; 32].to_vec()).unwrap(), Some([3; 32].to_vec())); - - let trie = Trie::open(Box::new(LibmdbxTrieDB::::new(db.clone())), root); - - assert_eq!(trie.get(&[0; 32].to_vec()).unwrap(), Some([0; 32].to_vec())); - assert_eq!(trie.get(&[1; 32].to_vec()).unwrap(), Some([1; 32].to_vec())); - } - - #[cfg(feature = "libmdbx")] - #[test] - fn get_old_state_with_removals() { - let db = test_utils::libmdbx::new_db::(); - let mut trie = Trie::new(Box::new(LibmdbxTrieDB::::new(db.clone()))); - - trie.insert([0; 32].to_vec(), [0; 32].to_vec()).unwrap(); - trie.insert([1; 32].to_vec(), [1; 32].to_vec()).unwrap(); - trie.insert([2; 32].to_vec(), [2; 32].to_vec()).unwrap(); - - let root = trie.hash().unwrap(); - - trie.insert([0; 32].to_vec(), vec![0x04]).unwrap(); - trie.remove([1; 32].to_vec()).unwrap(); - trie.insert([2; 32].to_vec(), vec![0x05]).unwrap(); - trie.remove([0; 32].to_vec()).unwrap(); - - assert_eq!(trie.get(&[0; 32].to_vec()).unwrap(), None); - assert_eq!(trie.get(&[1; 32].to_vec()).unwrap(), None); - assert_eq!(trie.get(&[2; 32].to_vec()).unwrap(), Some(vec![0x05])); - - let trie = Trie::open(Box::new(LibmdbxTrieDB::::new(db.clone())), root); - - assert_eq!(trie.get(&[0; 32].to_vec()).unwrap(), Some([0; 32].to_vec())); - assert_eq!(trie.get(&[1; 32].to_vec()).unwrap(), Some([1; 32].to_vec())); - assert_eq!(trie.get(&[2; 32].to_vec()).unwrap(), Some([2; 32].to_vec())); - } - - #[cfg(feature = "libmdbx")] - #[test] - fn revert() { - let db = test_utils::libmdbx::new_db::(); - let mut trie = Trie::new(Box::new(LibmdbxTrieDB::::new(db.clone()))); - - trie.insert([0; 32].to_vec(), [0; 32].to_vec()).unwrap(); - trie.insert([1; 32].to_vec(), [1; 32].to_vec()).unwrap(); - - let root = trie.hash().unwrap(); - - trie.insert([0; 32].to_vec(), [2; 32].to_vec()).unwrap(); - trie.insert([1; 32].to_vec(), [3; 32].to_vec()).unwrap(); - - let mut trie = Trie::open(Box::new(LibmdbxTrieDB::::new(db.clone())), root); - - trie.insert([2; 32].to_vec(), [4; 32].to_vec()).unwrap(); - - assert_eq!(trie.get(&[0; 32].to_vec()).unwrap(), Some([0; 32].to_vec())); - assert_eq!(trie.get(&[1; 32].to_vec()).unwrap(), Some([1; 32].to_vec())); - assert_eq!(trie.get(&[2; 32].to_vec()).unwrap(), Some([4; 32].to_vec())); - } - - #[cfg(feature = "libmdbx")] - #[test] - fn revert_with_removals() { - let db = test_utils::libmdbx::new_db::(); - let mut trie = Trie::new(Box::new(LibmdbxTrieDB::::new(db.clone()))); - - trie.insert([0; 32].to_vec(), [0; 32].to_vec()).unwrap(); - trie.insert([1; 32].to_vec(), [1; 32].to_vec()).unwrap(); - trie.insert([2; 32].to_vec(), [2; 32].to_vec()).unwrap(); - - let root = trie.hash().unwrap(); - - trie.insert([0; 32].to_vec(), [4; 32].to_vec()).unwrap(); - trie.remove([1; 32].to_vec()).unwrap(); - trie.insert([2; 32].to_vec(), [5; 32].to_vec()).unwrap(); - trie.remove([0; 32].to_vec()).unwrap(); - - let mut trie = Trie::open(Box::new(LibmdbxTrieDB::::new(db.clone())), root); - - trie.remove([2; 32].to_vec()).unwrap(); - - assert_eq!(trie.get(&[0; 32].to_vec()).unwrap(), Some([0; 32].to_vec())); - assert_eq!(trie.get(&[1; 32].to_vec()).unwrap(), Some([1; 32].to_vec())); - assert_eq!(trie.get(&vec![0x02]).unwrap(), None); - } - - #[cfg(feature = "libmdbx")] - #[test] - fn resume_trie() { - const TRIE_DIR: &str = "trie-db-resume-trie-test"; - let trie_dir = TempDir::new(TRIE_DIR).expect("Failed to create temp dir"); - let trie_dir = trie_dir.path(); - - // Create new trie from clean DB - let db = test_utils::libmdbx::new_db_with_path::(trie_dir.into()); - let mut trie = Trie::new(Box::new(LibmdbxTrieDB::::new(db.clone()))); - - trie.insert([0; 32].to_vec(), [1; 32].to_vec()).unwrap(); - trie.insert([1; 32].to_vec(), [2; 32].to_vec()).unwrap(); - trie.insert([2; 32].to_vec(), [4; 32].to_vec()).unwrap(); - - // Save current root - let root = trie.hash().unwrap(); - - // Release DB - drop(db); - drop(trie); - - let db2 = test_utils::libmdbx::open_db::(trie_dir.to_str().unwrap()); - // Create a new trie based on the previous trie's DB - let trie = Trie::open(Box::new(LibmdbxTrieDB::::new(db2)), root); - - assert_eq!(trie.get(&[0; 32].to_vec()).unwrap(), Some([1; 32].to_vec())); - assert_eq!(trie.get(&[1; 32].to_vec()).unwrap(), Some([2; 32].to_vec())); - assert_eq!(trie.get(&[2; 32].to_vec()).unwrap(), Some([4; 32].to_vec())); - } - // Proptests proptest! { #[test] diff --git a/crates/vm/Cargo.toml b/crates/vm/Cargo.toml index 3db14712e0..a5dbf638c6 100644 --- a/crates/vm/Cargo.toml +++ b/crates/vm/Cargo.toml @@ -43,7 +43,6 @@ default = [] l2 = [] c-kzg = ["revm/c-kzg", "ethrex-levm/c-kzg", "ethrex-common/c-kzg"] blst = ["revm/blst"] -libmdbx = ["ethrex-storage/default", "ethrex-common/libmdbx"] [profile.test] opt-level = 3