mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(l2-withdrawals): Move l2 withdrawals root computation into reth-optimism-storage (#14610)
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -8561,6 +8561,7 @@ dependencies = [
|
|||||||
"reth-optimism-forks",
|
"reth-optimism-forks",
|
||||||
"reth-optimism-node",
|
"reth-optimism-node",
|
||||||
"reth-optimism-primitives",
|
"reth-optimism-primitives",
|
||||||
|
"reth-optimism-storage",
|
||||||
"reth-primitives-traits",
|
"reth-primitives-traits",
|
||||||
"reth-provider",
|
"reth-provider",
|
||||||
"reth-revm",
|
"reth-revm",
|
||||||
@ -8695,6 +8696,7 @@ dependencies = [
|
|||||||
"reth-optimism-evm",
|
"reth-optimism-evm",
|
||||||
"reth-optimism-forks",
|
"reth-optimism-forks",
|
||||||
"reth-optimism-primitives",
|
"reth-optimism-primitives",
|
||||||
|
"reth-optimism-storage",
|
||||||
"reth-payload-builder",
|
"reth-payload-builder",
|
||||||
"reth-payload-builder-primitives",
|
"reth-payload-builder-primitives",
|
||||||
"reth-payload-primitives",
|
"reth-payload-primitives",
|
||||||
@ -8704,7 +8706,6 @@ dependencies = [
|
|||||||
"reth-provider",
|
"reth-provider",
|
||||||
"reth-revm",
|
"reth-revm",
|
||||||
"reth-transaction-pool",
|
"reth-transaction-pool",
|
||||||
"reth-trie",
|
|
||||||
"revm",
|
"revm",
|
||||||
"sha2 0.10.8",
|
"sha2 0.10.8",
|
||||||
"thiserror 2.0.11",
|
"thiserror 2.0.11",
|
||||||
@ -8797,11 +8798,15 @@ dependencies = [
|
|||||||
name = "reth-optimism-storage"
|
name = "reth-optimism-storage"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"alloy-primitives",
|
||||||
"reth-codecs",
|
"reth-codecs",
|
||||||
"reth-db-api",
|
"reth-db-api",
|
||||||
"reth-primitives",
|
"reth-primitives",
|
||||||
"reth-prune-types",
|
"reth-prune-types",
|
||||||
"reth-stages-types",
|
"reth-stages-types",
|
||||||
|
"reth-storage-api",
|
||||||
|
"reth-trie-common",
|
||||||
|
"revm",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@ -27,6 +27,7 @@ reth-optimism-forks.workspace = true
|
|||||||
reth-optimism-chainspec.workspace = true
|
reth-optimism-chainspec.workspace = true
|
||||||
# remove this after feature cleanup
|
# remove this after feature cleanup
|
||||||
reth-optimism-primitives = { workspace = true, features = ["serde", "reth-codec"] }
|
reth-optimism-primitives = { workspace = true, features = ["serde", "reth-codec"] }
|
||||||
|
reth-optimism-storage.workspace = true
|
||||||
|
|
||||||
# ethereum
|
# ethereum
|
||||||
alloy-eips.workspace = true
|
alloy-eips.workspace = true
|
||||||
@ -65,6 +66,7 @@ std = [
|
|||||||
"reth-storage-api/std",
|
"reth-storage-api/std",
|
||||||
"reth-storage-errors/std",
|
"reth-storage-errors/std",
|
||||||
"reth-trie-common/std",
|
"reth-trie-common/std",
|
||||||
|
"reth-optimism-storage/std",
|
||||||
"alloy-chains/std",
|
"alloy-chains/std",
|
||||||
"alloy-eips/std",
|
"alloy-eips/std",
|
||||||
"alloy-primitives/std",
|
"alloy-primitives/std",
|
||||||
|
|||||||
@ -3,10 +3,9 @@
|
|||||||
use crate::OpConsensusError;
|
use crate::OpConsensusError;
|
||||||
use alloy_consensus::BlockHeader;
|
use alloy_consensus::BlockHeader;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use reth_optimism_primitives::predeploys::ADDRESS_L2_TO_L1_MESSAGE_PASSER;
|
use reth_optimism_storage::predeploys::withdrawals_root;
|
||||||
use reth_storage_api::StorageRootProvider;
|
use reth_storage_api::StorageRootProvider;
|
||||||
use reth_trie_common::HashedStorage;
|
use revm::database::BundleState;
|
||||||
use revm::database::BundleAccount;
|
|
||||||
|
|
||||||
/// Verifies that `withdrawals_root` (i.e. `l2tol1-msg-passer` storage root since Isthmus) field is
|
/// Verifies that `withdrawals_root` (i.e. `l2tol1-msg-passer` storage root since Isthmus) field is
|
||||||
/// set in block header.
|
/// set in block header.
|
||||||
@ -23,7 +22,7 @@ pub fn ensure_withdrawals_storage_root_is_some<H: BlockHeader>(
|
|||||||
///
|
///
|
||||||
/// See <https://specs.optimism.io/protocol/isthmus/exec-engine.html#l2tol1messagepasser-storage-root-in-header>.
|
/// See <https://specs.optimism.io/protocol/isthmus/exec-engine.html#l2tol1messagepasser-storage-root-in-header>.
|
||||||
pub fn verify_withdrawals_storage_root<DB, H>(
|
pub fn verify_withdrawals_storage_root<DB, H>(
|
||||||
predeploy_account_updates: Option<&BundleAccount>,
|
state_updates: &BundleState,
|
||||||
state: DB,
|
state: DB,
|
||||||
header: H,
|
header: H,
|
||||||
) -> Result<(), OpConsensusError>
|
) -> Result<(), OpConsensusError>
|
||||||
@ -34,17 +33,7 @@ where
|
|||||||
let header_storage_root =
|
let header_storage_root =
|
||||||
header.withdrawals_root().ok_or(OpConsensusError::L2WithdrawalsRootMissing)?;
|
header.withdrawals_root().ok_or(OpConsensusError::L2WithdrawalsRootMissing)?;
|
||||||
|
|
||||||
// if block contained l2 withdrawals transactions, use predeploy storage updates from
|
let storage_root = withdrawals_root(state_updates, state)
|
||||||
// execution
|
|
||||||
let hashed_storage_updates = predeploy_account_updates.map(|acc| {
|
|
||||||
HashedStorage::from_plain_storage(
|
|
||||||
acc.status,
|
|
||||||
acc.storage.iter().map(|(slot, value)| (slot, &value.present_value)),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let storage_root = state
|
|
||||||
.storage_root(ADDRESS_L2_TO_L1_MESSAGE_PASSER, hashed_storage_updates.unwrap_or_default())
|
|
||||||
.map_err(OpConsensusError::L2WithdrawalsRootCalculationFail)?;
|
.map_err(OpConsensusError::L2WithdrawalsRootCalculationFail)?;
|
||||||
|
|
||||||
if header_storage_root != storage_root {
|
if header_storage_root != storage_root {
|
||||||
@ -68,12 +57,13 @@ mod test {
|
|||||||
use reth_db_common::init::init_genesis;
|
use reth_db_common::init::init_genesis;
|
||||||
use reth_optimism_chainspec::OpChainSpecBuilder;
|
use reth_optimism_chainspec::OpChainSpecBuilder;
|
||||||
use reth_optimism_node::OpNode;
|
use reth_optimism_node::OpNode;
|
||||||
|
use reth_optimism_primitives::ADDRESS_L2_TO_L1_MESSAGE_PASSER;
|
||||||
use reth_provider::{
|
use reth_provider::{
|
||||||
providers::BlockchainProvider, test_utils::create_test_provider_factory_with_node_types,
|
providers::BlockchainProvider, test_utils::create_test_provider_factory_with_node_types,
|
||||||
StateWriter,
|
StateWriter,
|
||||||
};
|
};
|
||||||
use reth_storage_api::StateProviderFactory;
|
use reth_storage_api::StateProviderFactory;
|
||||||
use reth_trie::test_utils::storage_root_prehashed;
|
use reth_trie::{test_utils::storage_root_prehashed, HashedStorage};
|
||||||
use reth_trie_common::HashedPostState;
|
use reth_trie_common::HashedPostState;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -118,7 +108,7 @@ mod test {
|
|||||||
|
|
||||||
// validate block against existing state by passing empty state updates
|
// validate block against existing state by passing empty state updates
|
||||||
verify_withdrawals_storage_root(
|
verify_withdrawals_storage_root(
|
||||||
None,
|
&BundleState::default(),
|
||||||
state_provider_factory.latest().expect("load state"),
|
state_provider_factory.latest().expect("load state"),
|
||||||
&header,
|
&header,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -27,13 +27,13 @@ reth-payload-util.workspace = true
|
|||||||
reth-payload-primitives = { workspace = true, features = ["op"] }
|
reth-payload-primitives = { workspace = true, features = ["op"] }
|
||||||
reth-basic-payload-builder.workspace = true
|
reth-basic-payload-builder.workspace = true
|
||||||
reth-chain-state.workspace = true
|
reth-chain-state.workspace = true
|
||||||
reth-trie.workspace = true
|
|
||||||
|
|
||||||
# op-reth
|
# op-reth
|
||||||
reth-optimism-consensus.workspace = true
|
reth-optimism-consensus.workspace = true
|
||||||
reth-optimism-evm.workspace = true
|
reth-optimism-evm.workspace = true
|
||||||
reth-optimism-forks.workspace = true
|
reth-optimism-forks.workspace = true
|
||||||
reth-optimism-primitives.workspace = true
|
reth-optimism-primitives.workspace = true
|
||||||
|
reth-optimism-storage.workspace = true
|
||||||
|
|
||||||
# ethereum
|
# ethereum
|
||||||
revm.workspace = true
|
revm.workspace = true
|
||||||
|
|||||||
@ -28,9 +28,8 @@ use reth_execution_types::ExecutionOutcome;
|
|||||||
use reth_optimism_consensus::calculate_receipt_root_no_memo_optimism;
|
use reth_optimism_consensus::calculate_receipt_root_no_memo_optimism;
|
||||||
use reth_optimism_evm::{OpReceiptBuilder, ReceiptBuilderCtx};
|
use reth_optimism_evm::{OpReceiptBuilder, ReceiptBuilderCtx};
|
||||||
use reth_optimism_forks::OpHardforks;
|
use reth_optimism_forks::OpHardforks;
|
||||||
use reth_optimism_primitives::{
|
use reth_optimism_primitives::transaction::signed::OpTransaction;
|
||||||
transaction::signed::OpTransaction, ADDRESS_L2_TO_L1_MESSAGE_PASSER,
|
use reth_optimism_storage::predeploys;
|
||||||
};
|
|
||||||
use reth_payload_builder_primitives::PayloadBuilderError;
|
use reth_payload_builder_primitives::PayloadBuilderError;
|
||||||
use reth_payload_primitives::PayloadBuilderAttributes;
|
use reth_payload_primitives::PayloadBuilderAttributes;
|
||||||
use reth_payload_util::{BestPayloadTransactions, NoopPayloadTransactions, PayloadTransactions};
|
use reth_payload_util::{BestPayloadTransactions, NoopPayloadTransactions, PayloadTransactions};
|
||||||
@ -49,7 +48,6 @@ use reth_revm::{
|
|||||||
witness::ExecutionWitnessRecord,
|
witness::ExecutionWitnessRecord,
|
||||||
};
|
};
|
||||||
use reth_transaction_pool::{BestTransactionsAttributes, PoolTransaction, TransactionPool};
|
use reth_transaction_pool::{BestTransactionsAttributes, PoolTransaction, TransactionPool};
|
||||||
use reth_trie::HashedStorage;
|
|
||||||
use revm::{
|
use revm::{
|
||||||
context_interface::{
|
context_interface::{
|
||||||
result::{ExecutionResult, ResultAndState},
|
result::{ExecutionResult, ResultAndState},
|
||||||
@ -400,22 +398,9 @@ impl<Txs> OpBuilder<'_, Txs> {
|
|||||||
state.merge_transitions(BundleRetention::Reverts);
|
state.merge_transitions(BundleRetention::Reverts);
|
||||||
|
|
||||||
let withdrawals_root = if ctx.is_isthmus_active() {
|
let withdrawals_root = if ctx.is_isthmus_active() {
|
||||||
let hashed_storage_updates =
|
|
||||||
state.bundle_state.state().get(&ADDRESS_L2_TO_L1_MESSAGE_PASSER).map(|account| {
|
|
||||||
// block contained withdrawals transactions, use predeploy storage updates from
|
|
||||||
// execution
|
|
||||||
HashedStorage::from_plain_storage(
|
|
||||||
account.status,
|
|
||||||
account.storage.iter().map(|(slot, value)| (slot, &value.present_value)),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
// withdrawals root field in block header is used for storage root of L2 predeploy
|
// withdrawals root field in block header is used for storage root of L2 predeploy
|
||||||
// `l2tol1-message-passer`
|
// `l2tol1-message-passer`
|
||||||
Some(state.database.as_ref().storage_root(
|
Some(predeploys::withdrawals_root(&state.bundle_state, state.database.as_ref())?)
|
||||||
ADDRESS_L2_TO_L1_MESSAGE_PASSER,
|
|
||||||
hashed_storage_updates.unwrap_or_default(),
|
|
||||||
)?)
|
|
||||||
} else if ctx.is_canyon_active() {
|
} else if ctx.is_canyon_active() {
|
||||||
Some(EMPTY_WITHDRAWALS)
|
Some(EMPTY_WITHDRAWALS)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -11,10 +11,29 @@ repository.workspace = true
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
# reth
|
||||||
reth-primitives.workspace = true
|
reth-primitives.workspace = true
|
||||||
|
reth-trie-common.workspace = true
|
||||||
|
reth-storage-api.workspace = true
|
||||||
|
|
||||||
|
# ethereum
|
||||||
|
alloy-primitives.workspace = true
|
||||||
|
revm.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
reth-codecs.workspace = true
|
reth-codecs.workspace = true
|
||||||
reth-db-api.workspace = true
|
reth-db-api.workspace = true
|
||||||
reth-prune-types.workspace = true
|
reth-prune-types.workspace = true
|
||||||
reth-stages-types.workspace = true
|
reth-stages-types.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["std"]
|
||||||
|
std = [
|
||||||
|
"reth-primitives/std",
|
||||||
|
"reth-trie-common/std",
|
||||||
|
"reth-storage-api/std",
|
||||||
|
"alloy-primitives/std",
|
||||||
|
"revm/std",
|
||||||
|
"reth-prune-types/std",
|
||||||
|
"reth-stages-types/std",
|
||||||
|
]
|
||||||
|
|||||||
@ -6,6 +6,10 @@
|
|||||||
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
|
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
|
||||||
)]
|
)]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
|
pub mod predeploys;
|
||||||
|
pub use predeploys::withdrawals_root;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|||||||
29
crates/optimism/storage/src/predeploys.rs
Normal file
29
crates/optimism/storage/src/predeploys.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
//! Utilities for accessing Optimism predeploy state
|
||||||
|
|
||||||
|
use alloy_primitives::{address, Address, B256};
|
||||||
|
use reth_storage_api::{errors::ProviderResult, StorageRootProvider};
|
||||||
|
use reth_trie_common::HashedStorage;
|
||||||
|
use revm::database::BundleState;
|
||||||
|
|
||||||
|
/// The L2 contract `L2ToL1MessagePasser`, stores commitments to withdrawal transactions.
|
||||||
|
pub const ADDRESS_L2_TO_L1_MESSAGE_PASSER: Address =
|
||||||
|
address!("4200000000000000000000000000000000000016");
|
||||||
|
|
||||||
|
/// Computes the storage root of predeploy `L2ToL1MessagePasser.sol` with state updates from block
|
||||||
|
/// execution.
|
||||||
|
pub fn withdrawals_root<DB: StorageRootProvider>(
|
||||||
|
state_updates: &BundleState,
|
||||||
|
state: DB,
|
||||||
|
) -> ProviderResult<B256> {
|
||||||
|
// if l2 withdrawals transactions were executed, use predeploy storage updates in storage root
|
||||||
|
// computation
|
||||||
|
let hashed_storage_updates =
|
||||||
|
state_updates.state().get(&ADDRESS_L2_TO_L1_MESSAGE_PASSER).map(|acc| {
|
||||||
|
HashedStorage::from_plain_storage(
|
||||||
|
acc.status,
|
||||||
|
acc.storage.iter().map(|(slot, value)| (slot, &value.present_value)),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
state.storage_root(ADDRESS_L2_TO_L1_MESSAGE_PASSER, hashed_storage_updates.unwrap_or_default())
|
||||||
|
}
|
||||||
@ -19,6 +19,7 @@ pub mod lockfile;
|
|||||||
|
|
||||||
/// Provider error
|
/// Provider error
|
||||||
pub mod provider;
|
pub mod provider;
|
||||||
|
pub use provider::{ProviderError, ProviderResult};
|
||||||
|
|
||||||
/// Writer error
|
/// Writer error
|
||||||
pub mod writer;
|
pub mod writer;
|
||||||
|
|||||||
Reference in New Issue
Block a user