From a69c4399528b80fbc5a482972e47165b0506e90c Mon Sep 17 00:00:00 2001 From: clabby Date: Mon, 22 Apr 2024 02:39:46 -0400 Subject: [PATCH] mem-trie-db init --- Cargo.lock | 128 ++++++++++++++++++++++++++++- crates/mpt/Cargo.toml | 2 + crates/mpt/src/db/mod.rs | 159 ++++++++++++++++++++++++++++++++++++ crates/mpt/src/lib.rs | 3 + crates/mpt/src/test_util.rs | 33 +++++++- 5 files changed, 322 insertions(+), 3 deletions(-) create mode 100644 crates/mpt/src/db/mod.rs diff --git a/Cargo.lock b/Cargo.lock index c12c73c8..46786fec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -748,6 +748,16 @@ dependencies = [ "syn 2.0.60", ] +[[package]] +name = "aurora-engine-modexp" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aef7712851e524f35fbbb74fa6599c5cd8692056a1c36f9ca0d2001b670e7e5" +dependencies = [ + "hex", + "num", +] + [[package]] name = "auto_impl" version = "1.2.0" @@ -1668,7 +1678,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "spin", + "spin 0.9.8", "tokio", "tracing", "tracing-subscriber", @@ -1688,6 +1698,8 @@ dependencies = [ "alloy-trie", "anyhow", "reqwest", + "revm", + "revm-primitives", "smallvec", "tokio", "tracing", @@ -1712,6 +1724,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] name = "libc" @@ -1825,6 +1840,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "num" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3135b08af27d103b0a51f2ae0f8632117b7b185ccf931445affa8df530576a41" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.4" @@ -1836,6 +1865,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +dependencies = [ + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.46" @@ -1845,6 +1883,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.18" @@ -2270,6 +2331,43 @@ dependencies = [ "winreg", ] +[[package]] +name = "revm" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a454c1c650b2b2e23f0c461af09e6c31e1d15e1cbebe905a701c46b8a50afc" +dependencies = [ + "auto_impl", + "cfg-if", + "dyn-clone", + "revm-interpreter", + "revm-precompile", +] + +[[package]] +name = "revm-interpreter" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d322f2730cd300e99d271a1704a2dfb8973d832428f5aa282aaa40e2473b5eec" +dependencies = [ + "revm-primitives", +] + +[[package]] +name = "revm-precompile" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "931f692f3f4fc72ec39d5d270f8e9d208c4a6008de7590ee96cf948e3b6d3f8d" +dependencies = [ + "aurora-engine-modexp", + "k256", + "once_cell", + "revm-primitives", + "ripemd", + "sha2", + "substrate-bn", +] + [[package]] name = "revm-primitives" version = "3.1.1" @@ -2301,6 +2399,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "rlp" version = "0.5.2" @@ -2611,6 +2718,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" @@ -2645,6 +2758,19 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand", + "rustc-hex", +] + [[package]] name = "subtle" version = "2.5.0" diff --git a/crates/mpt/Cargo.toml b/crates/mpt/Cargo.toml index bdc70a6a..b8b81313 100644 --- a/crates/mpt/Cargo.toml +++ b/crates/mpt/Cargo.toml @@ -18,6 +18,8 @@ alloy-primitives = { workspace = true, features = ["rlp"] } alloy-trie = { version = "0.3.1", default-features = false } alloy-rlp = { version = "0.3.4", default-features = false } smallvec = "1.13" +revm-primitives = { version = "3.1.1", default-features = false } +revm = { version = "8.0.0", default-features = false } [dev-dependencies] tokio = { version = "1.36.0", features = ["full"] } diff --git a/crates/mpt/src/db/mod.rs b/crates/mpt/src/db/mod.rs new file mode 100644 index 00000000..c7092472 --- /dev/null +++ b/crates/mpt/src/db/mod.rs @@ -0,0 +1,159 @@ +//! This module contains an implementation of an in-memory Trie DB, that allows for incremental updates through fetching +//! node preimages on the fly. + +#![allow(dead_code, unused)] + +use alloc::collections::VecDeque; +use alloy_primitives::{keccak256, Address, Bytes, B256, U256}; +use alloy_rlp::Decodable; +use alloy_trie::Nibbles; +use anyhow::{anyhow, Result}; +use core::marker::PhantomData; +use revm::{db::DbAccount, Database, DatabaseCommit, DatabaseRef, InMemoryDB}; +use revm_primitives::{hash_map::Entry, Account, AccountInfo, Bytecode, HashMap}; + +use crate::TrieNode; + +/// A Trie DB that caches account state in-memory. When accounts that don't already exist within the cache are queried, +/// the database fetches the preimages of the trie nodes on the path to the account using the `PreimageFetcher` +/// (`PF` generic) and `CodeHashFetcher` (`CHF` generic). This allows for data to be fetched in a verifiable manner +/// given an initial trusted state root as it is needed during execution. +/// +/// **Behavior**: +/// - When an account is queried and it does not already exist in the inner cache database, we fall through to the +/// `PreimageFetcher` to fetch the preimages of the trie nodes on the path to the account. After it has been fetched, +/// the account is inserted into the cache database and will be read from there on subsequent queries. +/// - When querying for the code hash of an account, the `CodeHashFetcher` is consulted to fetch the code hash of the +/// account. +/// - When a changeset is committed to the database, the changes are first applied to the cache database and then the +/// trie is recomputed. The root hash of the trie is then persisted as +#[derive(Debug, Default, Clone)] +pub struct TrieCacheDB { + /// The underlying DB that stores the account state in-memory. + db: InMemoryDB, + /// The current root node of the trie. + root: B256, + + _phantom_pf: PhantomData, + _phantom_chf: PhantomData, +} + +impl TrieCacheDB +where + PF: Fn(B256) -> Result + Copy + Default, + CHF: Fn(Address) -> Result + Copy + Default, +{ + /// Creates a new [TrieCacheDB] with the given root node. + pub fn new(root: B256) -> Self { + Self { root, ..Default::default() } + } + + /// Returns the current state root of the trie DB. + pub fn root(&self) -> B256 { + self.root + } + + /// Returns a reference to the underlying in-memory DB. + pub fn inner_db_ref(&self) -> &InMemoryDB { + &self.db + } + + /// Returns a mutable reference to the underlying in-memory DB. + pub fn inner_db_mut(&mut self) -> &mut InMemoryDB { + &mut self.db + } + + /// Returns the account for the given address. + /// + /// If the account was not found in the cache, it will be loaded from the underlying database. + /// + /// TODO: Check if it exists in the trie, if not, fetch it. + pub fn load_account(&mut self, address: Address) -> Result<&mut DbAccount> { + let db = self.inner_db_mut(); + match db.accounts.entry(address) { + Entry::Occupied(entry) => Ok(entry.into_mut()), + Entry::Vacant(entry) => Ok(entry.insert( + db.db + .basic_ref(address) + .map_err(|e| anyhow!(e))? + .map(|info| DbAccount { info, ..Default::default() }) + .unwrap_or_else(DbAccount::new_not_existing), + )), + } + } + + fn get_account_trie(&self, address: Address, fetcher: PF) -> Result { + let key = keccak256(address.as_slice()); + let root_node = TrieNode::decode(&mut fetcher(key)?.as_ref()); + + todo!() + } + + fn get_trie( + &self, + key: Nibbles, + trie_node: TrieNode, + pos: usize, + fetcher: PF, + ) -> Result { + todo!() + } +} + +impl DatabaseCommit for TrieCacheDB +where + PF: Fn(B256) -> Result + Copy, + CHF: Fn(Address) -> Result + Copy, +{ + fn commit(&mut self, changes: HashMap) { + todo!() + } +} + +impl Database for TrieCacheDB +where + PF: Fn(B256) -> Result + Copy, + CHF: Fn(Address) -> Result + Copy, +{ + type Error = anyhow::Error; + + fn basic(&mut self, address: Address) -> Result, Self::Error> { + todo!() + } + + fn code_by_hash(&mut self, code_hash: B256) -> Result { + todo!() + } + + fn storage(&mut self, address: Address, index: U256) -> Result { + todo!() + } + + fn block_hash(&mut self, number: U256) -> Result { + todo!() + } +} + +impl DatabaseRef for TrieCacheDB +where + PF: Fn(B256) -> Result + Copy, + CHF: Fn(Address) -> Result + Copy, +{ + type Error = anyhow::Error; + + fn basic_ref(&self, address: Address) -> Result, Self::Error> { + todo!() + } + + fn code_by_hash_ref(&self, code_hash: B256) -> Result { + todo!() + } + + fn storage_ref(&self, address: Address, index: U256) -> Result { + todo!() + } + + fn block_hash_ref(&self, number: U256) -> Result { + todo!() + } +} diff --git a/crates/mpt/src/lib.rs b/crates/mpt/src/lib.rs index a0b59ff1..6df04dd6 100644 --- a/crates/mpt/src/lib.rs +++ b/crates/mpt/src/lib.rs @@ -12,5 +12,8 @@ pub use node::{NodeElement, TrieNode}; mod list_walker; pub use list_walker::OrderedListWalker; +mod db; +pub use db::TrieCacheDB; + #[cfg(test)] mod test_util; diff --git a/crates/mpt/src/test_util.rs b/crates/mpt/src/test_util.rs index 49194d0e..4d38fb9b 100644 --- a/crates/mpt/src/test_util.rs +++ b/crates/mpt/src/test_util.rs @@ -2,9 +2,12 @@ extern crate std; -use alloc::{collections::BTreeMap, vec::Vec}; +use alloc::{ + collections::BTreeMap, + vec::{self, Vec}, +}; use alloy_consensus::{Receipt, ReceiptEnvelope, ReceiptWithBloom, TxEnvelope, TxType}; -use alloy_primitives::{keccak256, Bytes, Log, B256}; +use alloy_primitives::{b256, keccak256, Bytes, Log, B256}; use alloy_provider::{network::eip2718::Encodable2718, Provider, ProviderBuilder}; use alloy_rlp::{BufMut, Encodable}; use alloy_rpc_types::BlockTransactions; @@ -165,3 +168,29 @@ pub(crate) const fn adjust_index_for_rlp(i: usize, len: usize) -> usize { i + 1 } } + +#[test] +fn test_trie() { + use alloc::vec; + + let mut hb = HashBuilder::default() + .with_proof_retainer(vec![Nibbles::unpack(&[0x00]), Nibbles::unpack(&[0x01])]); + + // hb.add_leaf(Nibbles::unpack(&[0x00, 0xEE]), b"test one"); + // hb.add_leaf(Nibbles::unpack(&[0x00, 0xFF]), b"test one"); + // hb.add_leaf(Nibbles::unpack(&[0x01, 0xDD]), b"test one"); + // hb.add_leaf(Nibbles::unpack(&[0x01, 0xEE]), b"test one"); + // hb.add_leaf(Nibbles::unpack(&[0x01, 0xFF]), b"test one"); + hb.add_branch( + Nibbles::unpack(&[0x00]), + b256!("f4ae7801fd7296c9cb9f2387149e93079bd7c74158fea76d978947fddbead8b7"), + true, + ); + hb.add_branch( + Nibbles::unpack(&[0x01]), + b256!("91c0bc2b7771df00372f3b3ec799e2586115046fabc2b406c94b4d793ff1669c"), + true, + ); + std::dbg!(hb.root()); + std::dbg!(hb.take_proofs()); +}