Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce StateCommitment type #11842

Merged
merged 1 commit into from
Oct 30, 2024
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
5 changes: 5 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions crates/ethereum/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ reth-node-api.workspace = true
reth-chainspec.workspace = true
reth-primitives.workspace = true
reth-revm = { workspace = true, features = ["std"] }
reth-trie-db.workspace = true

# revm with required ethereum features
revm = { workspace = true, features = ["secp256k1", "blst", "c-kzg"] }
Expand Down Expand Up @@ -72,6 +73,7 @@ test-utils = [
"reth-db/test-utils",
"reth-provider/test-utils",
"reth-transaction-pool/test-utils",
"reth-trie-db/test-utils",
"revm/test-utils",
"reth-evm/test-utils"
]
2 changes: 2 additions & 0 deletions crates/ethereum/node/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use reth_transaction_pool::{
blobstore::DiskFileBlobStore, EthTransactionPool, TransactionPool,
TransactionValidationTaskExecutor,
};
use reth_trie_db::MerklePatriciaTrie;

use crate::{EthEngineTypes, EthEvmConfig};

Expand Down Expand Up @@ -81,6 +82,7 @@ impl EthereumNode {
impl NodeTypes for EthereumNode {
type Primitives = EthPrimitives;
type ChainSpec = ChainSpec;
type StateCommitment = MerklePatriciaTrie;
}

impl NodeTypesWithEngine for EthereumNode {
Expand Down
1 change: 1 addition & 0 deletions crates/exex/test-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ reth-primitives.workspace = true
reth-provider = { workspace = true, features = ["test-utils"] }
reth-tasks.workspace = true
reth-transaction-pool = { workspace = true, features = ["test-utils"] }
reth-trie-db.workspace = true

## async
futures-util.workspace = true
Expand Down
1 change: 1 addition & 0 deletions crates/exex/test-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ pub struct TestNode;
impl NodeTypes for TestNode {
type Primitives = ();
type ChainSpec = ChainSpec;
type StateCommitment = reth_trie_db::MerklePatriciaTrie;
}

impl NodeTypesWithEngine for TestNode {
Expand Down
2 changes: 2 additions & 0 deletions crates/node/builder/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ where
type Primitives = <N::Types as NodeTypes>::Primitives;

type ChainSpec = <N::Types as NodeTypes>::ChainSpec;

type StateCommitment = <N::Types as NodeTypes>::StateCommitment;
}

impl<N, C, AO> NodeTypesWithEngine for AnyNode<N, C, AO>
Expand Down
1 change: 1 addition & 0 deletions crates/node/types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ reth-db-api.workspace = true
reth-engine-primitives.workspace = true
reth-primitives.workspace = true
reth-primitives-traits.workspace = true
reth-trie-db.workspace = true
49 changes: 34 additions & 15 deletions crates/node/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use reth_db_api::{
Database,
};
use reth_engine_primitives::EngineTypes;
use reth_trie_db::StateCommitment;

/// Configures all the primitive types of the node.
pub trait NodePrimitives {
Expand All @@ -39,6 +40,8 @@ pub trait NodeTypes: Send + Sync + Unpin + 'static {
type Primitives: NodePrimitives;
/// The type used for configuration of the EVM.
type ChainSpec: EthChainSpec;
/// The type used to perform state commitment operations.
type StateCommitment: StateCommitment;
}

/// The type that configures an Ethereum-like node with an engine for consensus.
Expand Down Expand Up @@ -89,6 +92,7 @@ where
{
type Primitives = Types::Primitives;
type ChainSpec = Types::ChainSpec;
type StateCommitment = Types::StateCommitment;
}

impl<Types, DB> NodeTypesWithEngine for NodeTypesWithDBAdapter<Types, DB>
Expand All @@ -109,70 +113,85 @@ where

/// A [`NodeTypes`] type builder.
#[derive(Default, Debug)]
pub struct AnyNodeTypes<P = (), C = ()>(PhantomData<P>, PhantomData<C>);
pub struct AnyNodeTypes<P = (), C = (), S = ()>(PhantomData<P>, PhantomData<C>, PhantomData<S>);

impl<P, C> AnyNodeTypes<P, C> {
impl<P, C, S> AnyNodeTypes<P, C, S> {
/// Sets the `Primitives` associated type.
pub const fn primitives<T>(self) -> AnyNodeTypes<T, C> {
AnyNodeTypes::<T, C>(PhantomData::<T>, PhantomData::<C>)
pub const fn primitives<T>(self) -> AnyNodeTypes<T, C, S> {
AnyNodeTypes::<T, C, S>(PhantomData::<T>, PhantomData::<C>, PhantomData::<S>)
}

/// Sets the `ChainSpec` associated type.
pub const fn chain_spec<T>(self) -> AnyNodeTypes<P, T> {
AnyNodeTypes::<P, T>(PhantomData::<P>, PhantomData::<T>)
pub const fn chain_spec<T>(self) -> AnyNodeTypes<P, T, S> {
AnyNodeTypes::<P, T, S>(PhantomData::<P>, PhantomData::<T>, PhantomData::<S>)
}

/// Sets the `StateCommitment` associated type.
pub const fn state_commitment<T>(self) -> AnyNodeTypes<P, C, T> {
AnyNodeTypes::<P, C, T>(PhantomData::<P>, PhantomData::<C>, PhantomData::<T>)
}
}

impl<P, C> NodeTypes for AnyNodeTypes<P, C>
impl<P, C, S> NodeTypes for AnyNodeTypes<P, C, S>
where
P: NodePrimitives + Send + Sync + Unpin + 'static,
C: EthChainSpec + 'static,
S: StateCommitment,
{
type Primitives = P;
type ChainSpec = C;
type StateCommitment = S;
}

/// A [`NodeTypesWithEngine`] type builder.
#[derive(Default, Debug)]
pub struct AnyNodeTypesWithEngine<P = (), E = (), C = ()> {
pub struct AnyNodeTypesWithEngine<P = (), E = (), C = (), S = ()> {
/// Embedding the basic node types.
base: AnyNodeTypes<P, C>,
base: AnyNodeTypes<P, C, S>,
/// Phantom data for the engine.
_engine: PhantomData<E>,
}

impl<P, E, C> AnyNodeTypesWithEngine<P, E, C> {
impl<P, E, C, S> AnyNodeTypesWithEngine<P, E, C, S> {
/// Sets the `Primitives` associated type.
pub const fn primitives<T>(self) -> AnyNodeTypesWithEngine<T, E, C> {
pub const fn primitives<T>(self) -> AnyNodeTypesWithEngine<T, E, C, S> {
AnyNodeTypesWithEngine { base: self.base.primitives::<T>(), _engine: PhantomData }
}

/// Sets the `Engine` associated type.
pub const fn engine<T>(self) -> AnyNodeTypesWithEngine<P, T, C> {
pub const fn engine<T>(self) -> AnyNodeTypesWithEngine<P, T, C, S> {
AnyNodeTypesWithEngine { base: self.base, _engine: PhantomData::<T> }
}

/// Sets the `ChainSpec` associated type.
pub const fn chain_spec<T>(self) -> AnyNodeTypesWithEngine<P, E, T> {
pub const fn chain_spec<T>(self) -> AnyNodeTypesWithEngine<P, E, T, S> {
AnyNodeTypesWithEngine { base: self.base.chain_spec::<T>(), _engine: PhantomData }
}

/// Sets the `StateCommitment` associated type.
pub const fn state_commitment<T>(self) -> AnyNodeTypesWithEngine<P, E, C, T> {
AnyNodeTypesWithEngine { base: self.base.state_commitment::<T>(), _engine: PhantomData }
}
}

impl<P, E, C> NodeTypes for AnyNodeTypesWithEngine<P, E, C>
impl<P, E, C, S> NodeTypes for AnyNodeTypesWithEngine<P, E, C, S>
where
P: NodePrimitives + Send + Sync + Unpin + 'static,
E: EngineTypes + Send + Sync + Unpin,
C: EthChainSpec + 'static,
S: StateCommitment,
{
type Primitives = P;
type ChainSpec = C;
type StateCommitment = S;
}

impl<P, E, C> NodeTypesWithEngine for AnyNodeTypesWithEngine<P, E, C>
impl<P, E, C, S> NodeTypesWithEngine for AnyNodeTypesWithEngine<P, E, C, S>
where
P: NodePrimitives + Send + Sync + Unpin + 'static,
E: EngineTypes + Send + Sync + Unpin,
C: EthChainSpec + 'static,
S: StateCommitment,
{
type Engine = E;
}
2 changes: 2 additions & 0 deletions crates/optimism/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ reth-network.workspace = true
reth-evm.workspace = true
reth-revm = { workspace = true, features = ["std"] }
reth-beacon-consensus.workspace = true
reth-trie-db.workspace = true

# op-reth
reth-optimism-payload-builder.workspace = true
Expand Down Expand Up @@ -99,5 +100,6 @@ test-utils = [
"reth-db/test-utils",
"reth-provider/test-utils",
"reth-transaction-pool/test-utils",
"reth-trie-db/test-utils",
"revm/test-utils"
]
2 changes: 2 additions & 0 deletions crates/optimism/node/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use reth_transaction_pool::{
blobstore::DiskFileBlobStore, CoinbaseTipOrdering, TransactionPool,
TransactionValidationTaskExecutor,
};
use reth_trie_db::MerklePatriciaTrie;

use crate::{
args::RollupArgs,
Expand Down Expand Up @@ -122,6 +123,7 @@ where
impl NodeTypes for OptimismNode {
type Primitives = OpPrimitives;
type ChainSpec = OpChainSpec;
type StateCommitment = MerklePatriciaTrie;
}

impl NodeTypesWithEngine for OptimismNode {
Expand Down
2 changes: 2 additions & 0 deletions crates/storage/provider/src/test_utils/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use reth_trie::{
updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof, StorageProof,
TrieInput,
};
use reth_trie_db::MerklePatriciaTrie;
use revm::primitives::{BlockEnv, CfgEnvWithHandlerCfg};
use std::{
collections::BTreeMap,
Expand Down Expand Up @@ -157,6 +158,7 @@ pub struct MockNode;
impl NodeTypes for MockNode {
type Primitives = ();
type ChainSpec = ChainSpec;
type StateCommitment = MerklePatriciaTrie;
}

impl DatabaseProviderFactory for MockEthProvider {
Expand Down
1 change: 1 addition & 0 deletions crates/storage/provider/src/test_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub type MockNodeTypes = reth_node_types::AnyNodeTypesWithEngine<
(),
reth_ethereum_engine_primitives::EthEngineTypes,
reth_chainspec::ChainSpec,
reth_trie_db::MerklePatriciaTrie,
>;

/// Mock [`reth_node_types::NodeTypesWithDB`] for testing.
Expand Down
18 changes: 18 additions & 0 deletions crates/trie/common/src/key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use alloy_primitives::B256;
use revm_primitives::keccak256;

/// Trait for hashing keys in state.
pub trait KeyHasher: Default + Clone + Send + Sync + 'static {
/// Hashes the given bytes into a 256-bit hash.
fn hash_key<T: AsRef<[u8]>>(bytes: T) -> B256;
}

/// A key hasher that uses the Keccak-256 hash function.
#[derive(Clone, Debug, Default)]
pub struct KeccakKeyHasher;

impl KeyHasher for KeccakKeyHasher {
fn hash_key<T: AsRef<[u8]>>(bytes: T) -> B256 {
keccak256(bytes)
}
}
3 changes: 3 additions & 0 deletions crates/trie/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ pub mod hash_builder;
mod account;
pub use account::TrieAccount;

mod key;
pub use key::{KeccakKeyHasher, KeyHasher};

mod nibbles;
pub use nibbles::{Nibbles, StoredNibbles, StoredNibblesSubKey};

Expand Down
39 changes: 39 additions & 0 deletions crates/trie/db/src/commitment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use crate::{
DatabaseHashedCursorFactory, DatabaseProof, DatabaseStateRoot, DatabaseStorageRoot,
DatabaseTrieCursorFactory, DatabaseTrieWitness,
};
use reth_db::transaction::DbTx;
use reth_trie::{
proof::Proof, witness::TrieWitness, KeccakKeyHasher, KeyHasher, StateRoot, StorageRoot,
};

/// The `StateCommitment` trait provides associated types for state commitment operations.
pub trait StateCommitment: std::fmt::Debug + Send + Sync + Unpin + 'static {
/// The state root type.
type StateRoot<'a, TX: DbTx + 'a>: DatabaseStateRoot<'a, TX>;
/// The storage root type.
type StorageRoot<'a, TX: DbTx + 'a>: DatabaseStorageRoot<'a, TX>;
/// The state proof type.
type StateProof<'a, TX: DbTx + 'a>: DatabaseProof<'a, TX>;
/// The state witness type.
type StateWitness<'a, TX: DbTx + 'a>: DatabaseTrieWitness<'a, TX>;
Comment on lines +12 to +19
Copy link
Member

Choose a reason for hiding this comment

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

I'm a bit confused as to why these require DbTx bounds? Is it just because these must implement the Database* traits?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a consequence of the impl of DatabaseStateRoot on StateRoot. As we see below we have a DbTx bound on TX which is required for certain methods used in the implementation.

impl<'a, TX: DbTx> DatabaseStateRoot<'a, TX>
for StateRoot<DatabaseTrieCursorFactory<'a, TX>, DatabaseHashedCursorFactory<'a, TX>>

As a consequence of this in the implementation of StateCommitment for the MerklePatriciaTrie we must also have a DbTx bound on the StateRoot type as seen below:

impl StateCommitment for MerklePatriciaTrie {
    type StateRoot<'a, TX: DbTx + 'a> =
        StateRoot<DatabaseTrieCursorFactory<'a, TX>, DatabaseHashedCursorFactory<'a, TX>>;
        ...
}

Rust does not allow for an impl of a trait to have more strict bounds than the trait itself and therefore me must propagate the bound to the trait itself. The above rationale is also applicable for the other types in StateCommitment.

Copy link
Member

Choose a reason for hiding this comment

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

I just added this issue: #12216

note that it should not block any of this work, but eventually these traits could be simplified

/// The key hasher type.
type KeyHasher: KeyHasher;
}

/// The state commitment type for Ethereum's Merkle Patricia Trie.
#[derive(Debug)]
#[non_exhaustive]
pub struct MerklePatriciaTrie;
joshieDo marked this conversation as resolved.
Show resolved Hide resolved

impl StateCommitment for MerklePatriciaTrie {
type StateRoot<'a, TX: DbTx + 'a> =
StateRoot<DatabaseTrieCursorFactory<'a, TX>, DatabaseHashedCursorFactory<'a, TX>>;
type StorageRoot<'a, TX: DbTx + 'a> =
StorageRoot<DatabaseTrieCursorFactory<'a, TX>, DatabaseHashedCursorFactory<'a, TX>>;
type StateProof<'a, TX: DbTx + 'a> =
Proof<DatabaseTrieCursorFactory<'a, TX>, DatabaseHashedCursorFactory<'a, TX>>;
type StateWitness<'a, TX: DbTx + 'a> =
TrieWitness<DatabaseTrieCursorFactory<'a, TX>, DatabaseHashedCursorFactory<'a, TX>>;
type KeyHasher = KeccakKeyHasher;
}
2 changes: 2 additions & 0 deletions crates/trie/db/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! An integration of [`reth-trie`] with [`reth-db`].
mod commitment;
mod hashed_cursor;
mod prefix_set;
mod proof;
Expand All @@ -8,6 +9,7 @@ mod storage;
mod trie_cursor;
mod witness;

pub use commitment::{MerklePatriciaTrie, StateCommitment};
pub use hashed_cursor::{
DatabaseHashedAccountCursor, DatabaseHashedCursorFactory, DatabaseHashedStorageCursor,
};
Expand Down
1 change: 1 addition & 0 deletions examples/custom-engine-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ reth-basic-payload-builder.workspace = true
reth-ethereum-payload-builder.workspace = true
reth-node-ethereum = { workspace = true, features = ["test-utils"] }
reth-tracing.workspace = true
reth-trie-db.workspace = true
alloy-genesis.workspace = true
alloy-rpc-types = { workspace = true, features = ["engine"] }
alloy-primitives.workspace = true
Expand Down
2 changes: 2 additions & 0 deletions examples/custom-engine-types/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ use reth_payload_builder::{
};
use reth_primitives::Withdrawals;
use reth_tracing::{RethTracer, Tracer};
use reth_trie_db::MerklePatriciaTrie;

/// A custom payload attributes type.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
Expand Down Expand Up @@ -228,6 +229,7 @@ struct MyCustomNode;
impl NodeTypes for MyCustomNode {
type Primitives = ();
type ChainSpec = ChainSpec;
type StateCommitment = MerklePatriciaTrie;
}

/// Configure the node types with the custom engine types
Expand Down
Loading