Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
121 commits
Select commit Hold shift + click to select a range
77c61a6
add benching util
iovoid Sep 9, 2025
37fadd9
edit root cargo.toml
iovoid Sep 9, 2025
731f5ef
basic pathbased impl
iovoid Sep 10, 2025
29850f8
improve serialization
iovoid Sep 10, 2025
4f8e956
read optimization
iovoid Sep 10, 2025
fa27f76
fixes
iovoid Sep 11, 2025
9bda718
start fixing snapsync
iovoid Sep 11, 2025
fd66967
cleanup
iovoid Sep 11, 2025
26a5715
validate node fetches
iovoid Sep 11, 2025
aa86d98
fix opening hash
iovoid Sep 11, 2025
675ee90
fix state healing node fetch
iovoid Sep 11, 2025
60e3476
Merge branch 'main' into pathbased_testing
iovoid Sep 16, 2025
cc54cd9
fix merge
iovoid Sep 16, 2025
e3103f0
cleanup
iovoid Sep 16, 2025
fd0a71c
remove contains_X_node APIs
iovoid Sep 16, 2025
148655f
lint
iovoid Sep 16, 2025
0592338
heal terminal leaves too
iovoid Sep 16, 2025
8aa3966
fix rocksdb test
iovoid Sep 17, 2025
175de2d
save rollback logs
iovoid Sep 17, 2025
454db9b
Revert "save rollback logs"
iovoid Sep 18, 2025
8eac9a9
re-add full-path leaves
iovoid Sep 18, 2025
2678119
lint&fix
iovoid Sep 18, 2025
cfda5fb
basic trie layer implementation
iovoid Sep 18, 2025
a23275d
add passthrough for trie wrapper, for now
iovoid Sep 18, 2025
e1b301c
flush batch to cache instead of db
iovoid Sep 19, 2025
5c34ee8
Merge branch 'main' into pathbased_testing
iovoid Sep 19, 2025
e4f5a18
clippy
iovoid Sep 19, 2025
3af5e60
fix insert ordering
iovoid Sep 19, 2025
b8d5a78
better find the state root
iovoid Sep 19, 2025
840cb3d
fix storage handling
iovoid Sep 19, 2025
77458d4
fix insert-after-remove
iovoid Sep 22, 2025
fad5ba5
revert head to last state
iovoid Sep 23, 2025
9935d98
direct trie and fixes
iovoid Sep 24, 2025
a011a3e
fix incorrect miss
iovoid Sep 24, 2025
5f41620
snapsync fixes
iovoid Sep 25, 2025
63f01dc
Merge branch 'main' into pathbased_testing
iovoid Sep 25, 2025
dede3ab
also delete from db
iovoid Sep 25, 2025
fa28ad7
add healing logic
iovoid Sep 26, 2025
fa47749
healing fixes
iovoid Sep 29, 2025
ee75c19
docs: add comment
MegaRedHand Sep 29, 2025
6136bf8
refactor: add delete_range function in Store
MegaRedHand Sep 29, 2025
2b077da
Revert "refactor: add delete_range function in Store"
MegaRedHand Sep 29, 2025
fc02510
delete range improvement
iovoid Sep 29, 2025
aa63a77
Reapply "refactor: add delete_range function in Store"
MegaRedHand Sep 29, 2025
9e06da7
fix extension range delete
iovoid Sep 29, 2025
8750945
fix: add logs and add fix to storage healing
MegaRedHand Sep 29, 2025
0c6ba6e
fix delete path calculation
iovoid Sep 29, 2025
3a01580
Improved logs for speed
fedacking Sep 29, 2025
e5645dd
Update storage_healing.rs
fedacking Sep 29, 2025
ef27dc6
test: add test for computing subtree ranges
MegaRedHand Sep 29, 2025
49e817f
chore: comment out spammy print
MegaRedHand Sep 29, 2025
dce6506
Merge branch 'main' into pathbased_testing
MegaRedHand Sep 29, 2025
63eec48
perf: remove unnecessary clone
MegaRedHand Sep 29, 2025
f688021
fix: use full path when computing storage range
MegaRedHand Sep 30, 2025
5d45a41
chore: remove logs
MegaRedHand Sep 30, 2025
d4cdc9c
chore: remove commented print
MegaRedHand Sep 30, 2025
2d81017
do not return empty value nodes
iovoid Sep 30, 2025
9f0a639
Merge branch 'main' into pathbased_testing
MegaRedHand Sep 30, 2025
bb0464f
fix: remove nodes when writing empty
MegaRedHand Sep 30, 2025
9387932
refactor: improve InconsistentTree error messages
MegaRedHand Sep 30, 2025
8cfbe4c
move storage healing to db thread
iovoid Sep 30, 2025
f058dd6
also delete leaf-related paths
iovoid Oct 1, 2025
7dd5d73
chore: enable warn-on-block feature in spawned
MegaRedHand Oct 1, 2025
5c0a47c
fix
MegaRedHand Oct 1, 2025
f80e1b5
chore: disable warn-on-block again
MegaRedHand Oct 1, 2025
62dba3c
fix failed insertion error
iovoid Oct 1, 2025
ca69f55
Change vec for btreemap on nodes to write state healing
gianbelinche Oct 1, 2025
2753a9a
avoid costly deletions when not needed
iovoid Oct 1, 2025
dd45f7d
Merge branch 'main' into pathbased_testing
MegaRedHand Oct 2, 2025
cd889eb
Add delete range batch
gianbelinche Oct 2, 2025
36d7a40
Add delete ranges log
gianbelinche Oct 2, 2025
f8150c4
fix deleting the wrong nodes
iovoid Oct 2, 2025
389c8d4
Merge branch 'main' into pathbased_testing
MegaRedHand Oct 2, 2025
4a17209
remove unneeded apply_prefix
iovoid Oct 2, 2025
bbbe4eb
feat: add failed block hash to log
MegaRedHand Oct 2, 2025
844247f
also free peers in healing
iovoid Oct 3, 2025
e626ca0
avoid concurrent writes
iovoid Oct 3, 2025
a950ce2
Merge branch 'pathbased_testing' into pathbased_change_db_test
iovoid Oct 3, 2025
31b0590
regnerate snapshot from leaves after healing
iovoid Oct 3, 2025
bafbcc0
rename and update val
iovoid Oct 6, 2025
c60a57c
fixes
iovoid Oct 7, 2025
986f059
disable snapshots
iovoid Oct 7, 2025
d99b01a
restore snap cycle size
iovoid Oct 7, 2025
c703e13
remove spammy log
iovoid Oct 7, 2025
a82b75c
chore: run cargo fmt
MegaRedHand Oct 7, 2025
c0ee61e
chore: remove libmdbx
MegaRedHand Oct 7, 2025
78cbe11
Merge branch 'main' into path_based
MegaRedHand Oct 7, 2025
889a696
chore: fix some clippy issues
MegaRedHand Oct 7, 2025
5fb1428
chore: add some changes from old branch
MegaRedHand Oct 7, 2025
c8a0671
chore: remove unused delete_range functions
MegaRedHand Oct 7, 2025
6b994c3
fix: implement eth_getProof again
MegaRedHand Oct 7, 2025
bd49420
fix bug in storage insertion
iovoid Oct 8, 2025
d595a6a
Merge branch 'main' into path_based
MegaRedHand Oct 8, 2025
9236bea
fix: implement new functionality for InMemoryDb
MegaRedHand Oct 8, 2025
12357f6
chore: remove get_node_checked
MegaRedHand Oct 8, 2025
3a9a443
chore: UNCOMMENT CONDITION
MegaRedHand Oct 8, 2025
0253eae
chore: fix lints
MegaRedHand Oct 8, 2025
c7732cf
fix: update Trie::get_node
MegaRedHand Oct 8, 2025
f79ac75
chore: update archive_sync
MegaRedHand Oct 8, 2025
b28da0f
chore: bump max diff-layers to 128
MegaRedHand Oct 8, 2025
160381a
chore: ignore unused parameter
MegaRedHand Oct 8, 2025
449dbe5
chore: fix lint issue and add comment
MegaRedHand Oct 8, 2025
8721a47
Path based merge optimizations (#4825)
MegaRedHand Oct 9, 2025
df29b79
Merge commit '9a03e4c63' into path_based
MegaRedHand Oct 9, 2025
f48bc7b
Merge branch 'main' into path_based
MegaRedHand Oct 9, 2025
1b569e3
Merge branch 'main' into path_based
MegaRedHand Oct 9, 2025
06250b8
Merge branch 'main' into path_based
MegaRedHand Oct 13, 2025
a39449e
Merge branch 'main' into path_based
MegaRedHand Oct 13, 2025
d36b240
Merge branch 'main' into path_based
MegaRedHand Oct 14, 2025
6f1451b
fix: remove call to removed function
MegaRedHand Oct 14, 2025
7b19135
chore(l1): path based cleanup (#4837)
MegaRedHand Oct 14, 2025
af578b2
Merge branch 'main' into path_based
jrchatruc Oct 14, 2025
85a4147
chore: remove dbg!
MegaRedHand Oct 14, 2025
69be6af
Merge branch 'main' into path_based
MegaRedHand Oct 15, 2025
e88a692
Path based persist diff layers (#4888)
jrchatruc Oct 15, 2025
dd5fefb
chore: remove unused dependency
MegaRedHand Oct 15, 2025
a73f2da
Merge branch 'main' into path_based
MegaRedHand Oct 15, 2025
c835edf
chore: re-add deleted functions
MegaRedHand Oct 15, 2025
620f25d
Fix compilation
jrchatruc Oct 15, 2025
a893dd7
chore: remove unused import
MegaRedHand Oct 15, 2025
b4cd227
Fix clip help consistency
jrchatruc Oct 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions cmd/ethrex/initializers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ pub async fn init_l1(
},
);

regenerate_head_state(&store, &blockchain).await?;

let signer = get_signer(datadir);

let local_p2p_node = get_local_p2p_node(&opts, &signer);
Expand Down Expand Up @@ -484,3 +486,43 @@ pub async fn init_l1(
local_node_record,
))
}

async fn regenerate_head_state(store: &Store, blockchain: &Arc<Blockchain>) -> eyre::Result<()> {
let head_block_number = store.get_latest_block_number().await?;
let Some(last_header) = store.get_block_header(head_block_number)? else {
unreachable!("Database is empty, genesis block should be present");
};

let mut current_last_header = last_header;

while !store.has_state_root(current_last_header.state_root)? {
let parent_number = current_last_header.number - 1;
debug!("Need to regenerate state for block {parent_number}");
let Some(parent_header) = store.get_block_header(parent_number)? else {
return Err(eyre::eyre!(
"Parent header for block {parent_number} not found"
));
};
current_last_header = parent_header;
}

let last_state_number = current_last_header.number;

if last_state_number == head_block_number {
debug!("State is already up to date");
return Ok(());
}
info!("Regenerating state from block {last_state_number} to {head_block_number}");

for i in (last_state_number + 1)..=head_block_number {
debug!("Re-applying block {i} to regenerate state");

let block = store
.get_block_by_number(i)
.await?
.ok_or_else(|| eyre::eyre!("Block {i} not found"))?;
blockchain.add_block(block).await?;
}
info!("Finished regenerating state");
Ok(())
}
49 changes: 18 additions & 31 deletions cmd/ethrex/l2/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use ethrex_l2_sdk::call_contract;
use ethrex_rpc::{
EthClient, clients::beacon::BeaconClient, types::block_identifier::BlockIdentifier,
};
use ethrex_storage::{EngineType, Store, UpdateBatch};
use ethrex_storage::{EngineType, Store};
use ethrex_storage_rollup::StoreRollup;
use eyre::OptionExt;
use itertools::Itertools;
Expand Down Expand Up @@ -405,11 +405,8 @@ impl Command {

// Get genesis
let genesis_header = store.get_block_header(0)?.expect("Genesis block not found");
let genesis_block_hash = genesis_header.hash();

let mut new_trie = store
.state_trie(genesis_block_hash)?
.expect("Genesis block not found");
let mut current_state_root = genesis_header.state_root;

let mut last_block_number = 0;
let mut new_canonical_blocks = vec![];
Expand All @@ -433,37 +430,30 @@ impl Command {
let state_diff = StateDiff::decode(&blob)?;

// Apply all account updates to trie
let account_updates = state_diff.to_account_updates(&new_trie)?;
let trie = store.open_direct_state_trie(current_state_root)?;

let account_updates = state_diff.to_account_updates(&trie)?;

let account_updates_list = store
.apply_account_updates_from_trie_batch(new_trie, account_updates.values())
.apply_account_updates_from_trie_batch(trie, account_updates.values())
.await
.map_err(|e| format!("Error applying account updates: {e}"))
.unwrap();

let (new_state_root, state_updates, accounts_updates) = (
account_updates_list.state_trie_hash,
account_updates_list.state_updates,
account_updates_list.storage_updates,
);
store
.open_direct_state_trie(current_state_root)?
.db()
.put_batch(account_updates_list.state_updates)?;

let pseudo_update_batch = UpdateBatch {
account_updates: state_updates,
storage_updates: accounts_updates,
blocks: vec![],
receipts: vec![],
code_updates: vec![],
};
current_state_root = account_updates_list.state_trie_hash;

store
.store_block_updates(pseudo_update_batch)
.await
.map_err(|e| format!("Error storing trie updates: {e}"))
.unwrap();
.write_storage_trie_nodes_batch(account_updates_list.storage_updates)
.await?;

new_trie = store
.open_state_trie(new_state_root)
.map_err(|e| format!("Error opening new state trie: {e}"))
.unwrap();
store
.write_account_code_batch(account_updates_list.code_updates)
.await?;

// Get withdrawal hashes
let message_hashes = state_diff
Expand All @@ -479,10 +469,7 @@ impl Command {
// Note that its state_root is the root of new_trie.
let new_block = BlockHeader {
coinbase,
state_root: new_trie
.hash()
.map_err(|e| format!("Error committing state: {e}"))
.unwrap(),
state_root: account_updates_list.state_trie_hash,
..state_diff.last_header
};

Expand Down
1 change: 0 additions & 1 deletion crates/blockchain/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,6 @@ impl Blockchain {
};

self.storage
.clone()
.store_block_updates(update_batch)
.await
.map_err(|e| e.into())
Expand Down
2 changes: 1 addition & 1 deletion crates/blockchain/smoke_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ mod blockchain_integration_test {
};

// Create blockchain
let blockchain = Blockchain::default_with_store(store.clone().clone());
let blockchain = Blockchain::default_with_store(store.clone());

let block = create_payload(&args, store, Bytes::new()).unwrap();
let result = blockchain.build_payload(block).await.unwrap();
Expand Down
2 changes: 1 addition & 1 deletion crates/blockchain/tracing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ async fn get_missing_state_parents(
let Some(parent_block) = store.get_block_by_hash(parent_hash).await? else {
return Err(ChainError::Custom("Parent Block not Found".to_string()));
};
if store.contains_state_node(parent_block.header.state_root)? {
if store.has_state_root(parent_block.header.state_root)? {
break;
}
parent_hash = parent_block.header.parent_hash;
Expand Down
71 changes: 55 additions & 16 deletions crates/common/trie/db.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,58 @@
use ethereum_types::H256;
use ethrex_rlp::encode::RLPEncode;

use crate::{Node, NodeHash, NodeRLP, Trie, error::TrieError};
use crate::{Nibbles, Node, NodeRLP, Trie, error::TrieError};
use std::{
collections::BTreeMap,
sync::{Arc, Mutex},
};

// Nibbles -> encoded node
pub type NodeMap = Arc<Mutex<BTreeMap<Vec<u8>, Vec<u8>>>>;

pub trait TrieDB: Send + Sync {
fn get(&self, key: NodeHash) -> Result<Option<Vec<u8>>, TrieError>;
fn put_batch(&self, key_values: Vec<(NodeHash, Vec<u8>)>) -> Result<(), TrieError>;
fn get(&self, key: Nibbles) -> Result<Option<Vec<u8>>, TrieError>;
fn put_batch(&self, key_values: Vec<(Nibbles, Vec<u8>)>) -> Result<(), TrieError>;
// TODO: replace putbatch with this function.
fn put_batch_no_alloc(&self, key_values: &[(NodeHash, Node)]) -> Result<(), TrieError> {
fn put_batch_no_alloc(&self, key_values: &[(Nibbles, Node)]) -> Result<(), TrieError> {
self.put_batch(
key_values
.iter()
.map(|node| (node.0, node.1.encode_to_vec()))
.map(|node| (node.0.clone(), node.1.encode_to_vec()))
.collect(),
)
}
fn put(&self, key: NodeHash, value: Vec<u8>) -> Result<(), TrieError> {
fn put(&self, key: Nibbles, value: Vec<u8>) -> Result<(), TrieError> {
self.put_batch(vec![(key, value)])
}
}

/// InMemory implementation for the TrieDB trait, with get and put operations.
#[derive(Default)]
pub struct InMemoryTrieDB {
pub inner: Arc<Mutex<BTreeMap<NodeHash, Vec<u8>>>>,
inner: NodeMap,
prefix: Option<Nibbles>,
}

impl InMemoryTrieDB {
pub const fn new(map: Arc<Mutex<BTreeMap<NodeHash, Vec<u8>>>>) -> Self {
Self { inner: map }
pub const fn new(map: NodeMap) -> Self {
Self {
inner: map,
prefix: None,
}
}

pub const fn new_with_prefix(map: NodeMap, prefix: Nibbles) -> Self {
Self {
inner: map,
prefix: Some(prefix),
}
}

pub fn new_empty() -> Self {
Self {
inner: Default::default(),
prefix: None,
}
}

Expand All @@ -45,33 +61,56 @@ impl InMemoryTrieDB {
state_nodes: &BTreeMap<H256, NodeRLP>,
) -> Result<Self, TrieError> {
let mut embedded_root = Trie::get_embedded_root(state_nodes, root_hash)?;
let mut hashed_nodes: Vec<(NodeHash, Vec<u8>)> = vec![];
embedded_root.commit(&mut hashed_nodes);
let mut hashed_nodes = vec![];
embedded_root.commit(Nibbles::default(), &mut hashed_nodes);

let hashed_nodes = hashed_nodes.into_iter().collect();
let hashed_nodes = hashed_nodes
.into_iter()
.map(|(k, v)| (k.into_vec(), v))
.collect();

let in_memory_trie = Arc::new(Mutex::new(hashed_nodes));
Ok(Self::new(in_memory_trie))
}

fn apply_prefix(&self, path: Nibbles) -> Nibbles {
match &self.prefix {
Some(prefix) => prefix.concat(&path),
None => path,
}
}
}

impl TrieDB for InMemoryTrieDB {
fn get(&self, key: NodeHash) -> Result<Option<Vec<u8>>, TrieError> {
fn get(&self, key: Nibbles) -> Result<Option<Vec<u8>>, TrieError> {
Ok(self
.inner
.lock()
.map_err(|_| TrieError::LockError)?
.get(&key)
.get(self.apply_prefix(key).as_ref())
.cloned())
}

fn put_batch(&self, key_values: Vec<(NodeHash, Vec<u8>)>) -> Result<(), TrieError> {
fn put_batch(&self, key_values: Vec<(Nibbles, Vec<u8>)>) -> Result<(), TrieError> {
let mut db = self.inner.lock().map_err(|_| TrieError::LockError)?;

for (key, value) in key_values {
db.insert(key, value);
let prefixed_key = self.apply_prefix(key);
db.insert(prefixed_key.into_vec(), value);
}

Ok(())
}
}

pub fn nibbles_to_fixed_size(nibbles: Nibbles) -> [u8; 33] {
let node_hash_ref = nibbles.to_bytes();
let original_len = node_hash_ref.len();

let mut buffer = [0u8; 33];

// Encode the node as [node_path..., original_len]
buffer[32] = nibbles.len() as u8;
buffer[..original_len].copy_from_slice(&node_hash_ref);
buffer
}
8 changes: 4 additions & 4 deletions crates/common/trie/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::{

use ethrex_rlp::decode::RLPDecode;

use crate::{Node, NodeHash, Trie, TrieDB, TrieError};
use crate::{Nibbles, Node, Trie, TrieDB, TrieError};

pub type TrieWitness = Arc<Mutex<HashSet<Vec<u8>>>>;

Expand Down Expand Up @@ -33,7 +33,7 @@ impl TrieLogger {
}

impl TrieDB for TrieLogger {
fn get(&self, key: NodeHash) -> Result<Option<Vec<u8>>, TrieError> {
fn get(&self, key: Nibbles) -> Result<Option<Vec<u8>>, TrieError> {
let result = self.inner_db.get(key)?;
if let Some(result) = result.as_ref()
&& let Ok(decoded) = Node::decode(result)
Expand All @@ -44,11 +44,11 @@ impl TrieDB for TrieLogger {
Ok(result)
}

fn put(&self, key: NodeHash, value: Vec<u8>) -> Result<(), TrieError> {
fn put(&self, key: Nibbles, value: Vec<u8>) -> Result<(), TrieError> {
self.inner_db.put(key, value)
}

fn put_batch(&self, key_values: Vec<(NodeHash, Vec<u8>)>) -> Result<(), TrieError> {
fn put_batch(&self, key_values: Vec<(Nibbles, Vec<u8>)>) -> Result<(), TrieError> {
self.inner_db.put_batch(key_values)
}
}
Loading
Loading