Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 11 additions & 1 deletion crates/exex/external-proofs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,21 @@ workspace = true
[dependencies]
reth-exex.workspace = true

# ethereum
alloy-primitives = { workspace = true }

# reth
reth-provider.workspace = true
reth-db-api.workspace = true
reth-node-types.workspace = true
reth-node-api.workspace = true
reth-primitives-traits.workspace = true
reth-provider.workspace = true
reth-trie.workspace = true

# misc
auto_impl.workspace = true
async-trait.workspace = true
eyre.workspace = true
futures-util.workspace = true
serde.workspace = true
thiserror.workspace = true
2 changes: 2 additions & 0 deletions crates/exex/external-proofs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use reth_provider::StateReader;

use reth_exex::{ExExContext, ExExEvent};

mod storage;

/// Saves and serves trie nodes to make proofs faster. This handles the process of
/// saving the current state, new blocks as they're added, and serving proof RPCs
/// based on the saved data.
Expand Down
169 changes: 169 additions & 0 deletions crates/exex/external-proofs/src/storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#![expect(dead_code, unreachable_pub)]
use alloy_primitives::{map::HashMap, B256, U256};
use async_trait::async_trait;
use auto_impl::auto_impl;
use reth_primitives_traits::Account;
use reth_trie::{updates::TrieUpdates, BranchNodeCompact, HashedPostState, Nibbles};
use std::fmt::Debug;
use thiserror::Error;

/// Error type for storage operations
#[derive(Debug, Error)]
pub enum ExternalStorageError {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub enum ExternalStorageError {
pub enum OpProofsWindowStorageError {

let's rename this, alt to OpProofsStorage

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do this on a PR on top of this stack to reduce merge conflicts!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// TODO: add more errors once we know what they are
/// Other error
#[error("Other error: {0}")]
Other(eyre::Error),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls add a todo comment that this is just a placeholder

}

/// Result type for storage operations
pub type ExternalStorageResult<T> = Result<T, ExternalStorageError>;

/// Seeks and iterates over trie nodes in the database by path (lexicographical order)
pub trait ExternalTrieCursor: Send + Sync {
/// Seek to an exact path, otherwise return None if not found.
fn seek_exact(
&mut self,
path: Nibbles,
) -> ExternalStorageResult<Option<(Nibbles, BranchNodeCompact)>>;

/// Seek to a path, otherwise return the first path greater than the given path
/// lexicographically.
fn seek(
&mut self,
path: Nibbles,
) -> ExternalStorageResult<Option<(Nibbles, BranchNodeCompact)>>;

/// Move the cursor to the next path and return it.
fn next(&mut self) -> ExternalStorageResult<Option<(Nibbles, BranchNodeCompact)>>;

/// Get the current path.
fn current(&mut self) -> ExternalStorageResult<Option<Nibbles>>;
}

/// Seeks and iterates over hashed entries in the database by key.
pub trait ExternalHashedCursor: Send + Sync {
/// Value returned by the cursor.
type Value: std::fmt::Debug;

/// Seek an entry greater or equal to the given key and position the cursor there.
/// Returns the first entry with the key greater or equal to the sought key.
fn seek(&mut self, key: B256) -> ExternalStorageResult<Option<(B256, Self::Value)>>;

/// Move the cursor to the next entry and return it.
fn next(&mut self) -> ExternalStorageResult<Option<(B256, Self::Value)>>;
}

/// Diff of trie updates and post state for a block.
#[derive(Debug, Clone)]
pub struct BlockStateDiff {
pub trie_updates: TrieUpdates,
pub post_state: HashedPostState,
}

/// Trait for reading trie nodes from the database.
///
/// Only leaf nodes and some branch nodes are stored. The bottom layer of branch nodes
/// are not stored to reduce write amplification. This matches Reth's non-historical trie storage.
#[async_trait]
#[auto_impl(Arc)]
pub trait ExternalStorage: Send + Sync + Debug {
type TrieCursor: ExternalTrieCursor;
type StorageCursor: ExternalHashedCursor<Value = U256>;
type AccountHashedCursor: ExternalHashedCursor<Value = Account>;

/// Store a batch of account trie branches. Used for saving existing state. For live state
/// capture, use [store_trie_updates](ExternalStorage::store_trie_updates).
async fn store_account_branches(
&self,
block_number: u64,
updates: Vec<(Nibbles, Option<BranchNodeCompact>)>,
) -> ExternalStorageResult<()>;

/// Store a batch of storage trie branches. Used for saving existing state.
async fn store_storage_branches(
&self,
block_number: u64,
hashed_address: B256,
items: Vec<(Nibbles, Option<BranchNodeCompact>)>,
) -> ExternalStorageResult<()>;

/// Store a batch of account trie leaf nodes. Used for saving existing state.
async fn store_hashed_accounts(
&self,
accounts: Vec<(B256, Option<Account>)>,
block_number: u64,
) -> ExternalStorageResult<()>;

/// Store a batch of storage trie leaf nodes. Used for saving existing state.
async fn store_hashed_storages(
&self,
hashed_address: B256,
storages: Vec<(B256, U256)>,
block_number: u64,
) -> ExternalStorageResult<()>;

/// Get the earliest block number and hash that has been stored
///
/// This is used to determine the block number of trie nodes with block number 0.
/// All earliest block numbers are stored in 0 to reduce updates required to prune trie nodes.
async fn get_earliest_block_number(&self) -> ExternalStorageResult<Option<(u64, B256)>>;

/// Get the latest block number and hash that has been stored
async fn get_latest_block_number(&self) -> ExternalStorageResult<Option<(u64, B256)>>;

/// Get a trie cursor for the storage backend
fn trie_cursor(
&self,
hashed_address: Option<B256>,
max_block_number: u64,
) -> ExternalStorageResult<Self::TrieCursor>;

/// Get a storage cursor for the storage backend
fn storage_hashed_cursor(
&self,
hashed_address: B256,
max_block_number: u64,
) -> ExternalStorageResult<Self::StorageCursor>;

/// Get an account hashed cursor for the storage backend
fn account_hashed_cursor(
&self,
max_block_number: u64,
) -> ExternalStorageResult<Self::AccountHashedCursor>;

/// Store a batch of trie updates.
///
/// If wiped is true, the entire storage trie is wiped, but this is unsupported going forward,
/// so should only happen for legacy reasons.
async fn store_trie_updates(
&self,
block_number: u64,
block_state_diff: BlockStateDiff,
) -> ExternalStorageResult<()>;

/// Fetch all updates for a given block number.
async fn fetch_trie_updates(&self, block_number: u64) -> ExternalStorageResult<BlockStateDiff>;

/// Applies `BlockStateDiff` to the earliest state (updating/deleting nodes) and updates the
/// earliest block number.
async fn prune_earliest_state(
&self,
new_earliest_block_number: u64,
diff: BlockStateDiff,
) -> ExternalStorageResult<()>;

/// Deletes all updates > `latest_common_block_number` and replaces them with the new updates.
async fn replace_updates(
&self,
latest_common_block_number: u64,
blocks_to_add: HashMap<u64, BlockStateDiff>,
) -> ExternalStorageResult<()>;

/// Set the earliest block number and hash that has been stored
async fn set_earliest_block_number(
&self,
block_number: u64,
hash: B256,
) -> ExternalStorageResult<()>;
}
Loading