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:
@ -27,6 +27,7 @@ reth-optimism-forks.workspace = true
|
||||
reth-optimism-chainspec.workspace = true
|
||||
# remove this after feature cleanup
|
||||
reth-optimism-primitives = { workspace = true, features = ["serde", "reth-codec"] }
|
||||
reth-optimism-storage.workspace = true
|
||||
|
||||
# ethereum
|
||||
alloy-eips.workspace = true
|
||||
@ -65,6 +66,7 @@ std = [
|
||||
"reth-storage-api/std",
|
||||
"reth-storage-errors/std",
|
||||
"reth-trie-common/std",
|
||||
"reth-optimism-storage/std",
|
||||
"alloy-chains/std",
|
||||
"alloy-eips/std",
|
||||
"alloy-primitives/std",
|
||||
|
||||
@ -3,10 +3,9 @@
|
||||
use crate::OpConsensusError;
|
||||
use alloy_consensus::BlockHeader;
|
||||
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_trie_common::HashedStorage;
|
||||
use revm::database::BundleAccount;
|
||||
use revm::database::BundleState;
|
||||
|
||||
/// Verifies that `withdrawals_root` (i.e. `l2tol1-msg-passer` storage root since Isthmus) field is
|
||||
/// 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>.
|
||||
pub fn verify_withdrawals_storage_root<DB, H>(
|
||||
predeploy_account_updates: Option<&BundleAccount>,
|
||||
state_updates: &BundleState,
|
||||
state: DB,
|
||||
header: H,
|
||||
) -> Result<(), OpConsensusError>
|
||||
@ -34,17 +33,7 @@ where
|
||||
let header_storage_root =
|
||||
header.withdrawals_root().ok_or(OpConsensusError::L2WithdrawalsRootMissing)?;
|
||||
|
||||
// if block contained l2 withdrawals transactions, use predeploy storage updates from
|
||||
// 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())
|
||||
let storage_root = withdrawals_root(state_updates, state)
|
||||
.map_err(OpConsensusError::L2WithdrawalsRootCalculationFail)?;
|
||||
|
||||
if header_storage_root != storage_root {
|
||||
@ -68,12 +57,13 @@ mod test {
|
||||
use reth_db_common::init::init_genesis;
|
||||
use reth_optimism_chainspec::OpChainSpecBuilder;
|
||||
use reth_optimism_node::OpNode;
|
||||
use reth_optimism_primitives::ADDRESS_L2_TO_L1_MESSAGE_PASSER;
|
||||
use reth_provider::{
|
||||
providers::BlockchainProvider, test_utils::create_test_provider_factory_with_node_types,
|
||||
StateWriter,
|
||||
};
|
||||
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;
|
||||
|
||||
#[test]
|
||||
@ -118,7 +108,7 @@ mod test {
|
||||
|
||||
// validate block against existing state by passing empty state updates
|
||||
verify_withdrawals_storage_root(
|
||||
None,
|
||||
&BundleState::default(),
|
||||
state_provider_factory.latest().expect("load state"),
|
||||
&header,
|
||||
)
|
||||
|
||||
@ -27,13 +27,13 @@ reth-payload-util.workspace = true
|
||||
reth-payload-primitives = { workspace = true, features = ["op"] }
|
||||
reth-basic-payload-builder.workspace = true
|
||||
reth-chain-state.workspace = true
|
||||
reth-trie.workspace = true
|
||||
|
||||
# op-reth
|
||||
reth-optimism-consensus.workspace = true
|
||||
reth-optimism-evm.workspace = true
|
||||
reth-optimism-forks.workspace = true
|
||||
reth-optimism-primitives.workspace = true
|
||||
reth-optimism-storage.workspace = true
|
||||
|
||||
# ethereum
|
||||
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_evm::{OpReceiptBuilder, ReceiptBuilderCtx};
|
||||
use reth_optimism_forks::OpHardforks;
|
||||
use reth_optimism_primitives::{
|
||||
transaction::signed::OpTransaction, ADDRESS_L2_TO_L1_MESSAGE_PASSER,
|
||||
};
|
||||
use reth_optimism_primitives::transaction::signed::OpTransaction;
|
||||
use reth_optimism_storage::predeploys;
|
||||
use reth_payload_builder_primitives::PayloadBuilderError;
|
||||
use reth_payload_primitives::PayloadBuilderAttributes;
|
||||
use reth_payload_util::{BestPayloadTransactions, NoopPayloadTransactions, PayloadTransactions};
|
||||
@ -49,7 +48,6 @@ use reth_revm::{
|
||||
witness::ExecutionWitnessRecord,
|
||||
};
|
||||
use reth_transaction_pool::{BestTransactionsAttributes, PoolTransaction, TransactionPool};
|
||||
use reth_trie::HashedStorage;
|
||||
use revm::{
|
||||
context_interface::{
|
||||
result::{ExecutionResult, ResultAndState},
|
||||
@ -400,22 +398,9 @@ impl<Txs> OpBuilder<'_, Txs> {
|
||||
state.merge_transitions(BundleRetention::Reverts);
|
||||
|
||||
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
|
||||
// `l2tol1-message-passer`
|
||||
Some(state.database.as_ref().storage_root(
|
||||
ADDRESS_L2_TO_L1_MESSAGE_PASSER,
|
||||
hashed_storage_updates.unwrap_or_default(),
|
||||
)?)
|
||||
Some(predeploys::withdrawals_root(&state.bundle_state, state.database.as_ref())?)
|
||||
} else if ctx.is_canyon_active() {
|
||||
Some(EMPTY_WITHDRAWALS)
|
||||
} else {
|
||||
|
||||
@ -11,10 +11,29 @@ repository.workspace = true
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
# reth
|
||||
reth-primitives.workspace = true
|
||||
reth-trie-common.workspace = true
|
||||
reth-storage-api.workspace = true
|
||||
|
||||
# ethereum
|
||||
alloy-primitives.workspace = true
|
||||
revm.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
reth-codecs.workspace = true
|
||||
reth-db-api.workspace = true
|
||||
reth-prune-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/"
|
||||
)]
|
||||
#![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)]
|
||||
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
|
||||
pub mod provider;
|
||||
pub use provider::{ProviderError, ProviderResult};
|
||||
|
||||
/// Writer error
|
||||
pub mod writer;
|
||||
|
||||
Reference in New Issue
Block a user