mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
fix(op): add missing op consensus validation check (#13122)
This commit is contained in:
@ -45,7 +45,7 @@ optimism = [
|
|||||||
"reth-optimism-payload-builder/optimism",
|
"reth-optimism-payload-builder/optimism",
|
||||||
"reth-optimism-rpc/optimism",
|
"reth-optimism-rpc/optimism",
|
||||||
"reth-provider/optimism",
|
"reth-provider/optimism",
|
||||||
"reth-optimism-primitives/op",
|
"reth-optimism-primitives/optimism",
|
||||||
]
|
]
|
||||||
|
|
||||||
dev = [
|
dev = [
|
||||||
|
|||||||
@ -21,7 +21,7 @@ use alloc::{boxed::Box, vec, vec::Vec};
|
|||||||
use alloy_chains::Chain;
|
use alloy_chains::Chain;
|
||||||
use alloy_consensus::Header;
|
use alloy_consensus::Header;
|
||||||
use alloy_genesis::Genesis;
|
use alloy_genesis::Genesis;
|
||||||
use alloy_primitives::{Bytes, B256, U256};
|
use alloy_primitives::{B256, U256};
|
||||||
pub use base::BASE_MAINNET;
|
pub use base::BASE_MAINNET;
|
||||||
pub use base_sepolia::BASE_SEPOLIA;
|
pub use base_sepolia::BASE_SEPOLIA;
|
||||||
use derive_more::{Constructor, Deref, Display, From, Into};
|
use derive_more::{Constructor, Deref, Display, From, Into};
|
||||||
@ -185,6 +185,28 @@ pub struct OpChainSpec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OpChainSpec {
|
impl OpChainSpec {
|
||||||
|
/// Extracts the Holcene 1599 parameters from the encoded extradata from the parent header.
|
||||||
|
///
|
||||||
|
/// Caution: Caller must ensure that holocene is active in the parent header.
|
||||||
|
///
|
||||||
|
/// See also [Base fee computation](https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#base-fee-computation)
|
||||||
|
pub fn decode_holocene_base_fee(
|
||||||
|
&self,
|
||||||
|
parent: &Header,
|
||||||
|
timestamp: u64,
|
||||||
|
) -> Result<u64, DecodeError> {
|
||||||
|
let (denominator, elasticity) = decode_holocene_1559_params(&parent.extra_data)?;
|
||||||
|
let base_fee = if elasticity == 0 && denominator == 0 {
|
||||||
|
parent
|
||||||
|
.next_block_base_fee(self.base_fee_params_at_timestamp(timestamp))
|
||||||
|
.unwrap_or_default()
|
||||||
|
} else {
|
||||||
|
let base_fee_params = BaseFeeParams::new(denominator as u128, elasticity as u128);
|
||||||
|
parent.next_block_base_fee(base_fee_params).unwrap_or_default()
|
||||||
|
};
|
||||||
|
Ok(base_fee)
|
||||||
|
}
|
||||||
|
|
||||||
/// Read from parent to determine the base fee for the next block
|
/// Read from parent to determine the base fee for the next block
|
||||||
///
|
///
|
||||||
/// See also [Base fee computation](https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#base-fee-computation)
|
/// See also [Base fee computation](https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#base-fee-computation)
|
||||||
@ -204,16 +226,7 @@ impl OpChainSpec {
|
|||||||
// from the parent block's extra data.
|
// from the parent block's extra data.
|
||||||
// Else, use the base fee params (default values) from chainspec
|
// Else, use the base fee params (default values) from chainspec
|
||||||
if is_holocene_activated {
|
if is_holocene_activated {
|
||||||
let (denominator, elasticity) = decode_holocene_1559_params(parent.extra_data.clone())?;
|
Ok(U256::from(self.decode_holocene_base_fee(parent, timestamp)?))
|
||||||
if elasticity == 0 && denominator == 0 {
|
|
||||||
return Ok(U256::from(
|
|
||||||
parent
|
|
||||||
.next_block_base_fee(self.base_fee_params_at_timestamp(timestamp))
|
|
||||||
.unwrap_or_default(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let base_fee_params = BaseFeeParams::new(denominator as u128, elasticity as u128);
|
|
||||||
Ok(U256::from(parent.next_block_base_fee(base_fee_params).unwrap_or_default()))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(U256::from(
|
Ok(U256::from(
|
||||||
parent
|
parent
|
||||||
@ -247,7 +260,7 @@ impl core::error::Error for DecodeError {
|
|||||||
|
|
||||||
/// Extracts the Holcene 1599 parameters from the encoded form:
|
/// Extracts the Holcene 1599 parameters from the encoded form:
|
||||||
/// <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#eip1559params-encoding>
|
/// <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#eip1559params-encoding>
|
||||||
pub fn decode_holocene_1559_params(extra_data: Bytes) -> Result<(u32, u32), DecodeError> {
|
pub fn decode_holocene_1559_params(extra_data: &[u8]) -> Result<(u32, u32), DecodeError> {
|
||||||
if extra_data.len() < 9 {
|
if extra_data.len() < 9 {
|
||||||
return Err(DecodeError::InsufficientData);
|
return Err(DecodeError::InsufficientData);
|
||||||
}
|
}
|
||||||
@ -492,7 +505,7 @@ mod tests {
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use alloy_genesis::{ChainConfig, Genesis};
|
use alloy_genesis::{ChainConfig, Genesis};
|
||||||
use alloy_primitives::b256;
|
use alloy_primitives::{b256, Bytes};
|
||||||
use reth_chainspec::{test_fork_ids, BaseFeeParams, BaseFeeParamsKind};
|
use reth_chainspec::{test_fork_ids, BaseFeeParams, BaseFeeParamsKind};
|
||||||
use reth_ethereum_forks::{EthereumHardfork, ForkCondition, ForkHash, ForkId, Head};
|
use reth_ethereum_forks::{EthereumHardfork, ForkCondition, ForkHash, ForkId, Head};
|
||||||
use reth_optimism_forks::{OpHardfork, OpHardforks};
|
use reth_optimism_forks::{OpHardfork, OpHardforks};
|
||||||
|
|||||||
@ -95,7 +95,7 @@ optimism = [
|
|||||||
"reth-execution-types/optimism",
|
"reth-execution-types/optimism",
|
||||||
"reth-db/optimism",
|
"reth-db/optimism",
|
||||||
"reth-db-api/optimism",
|
"reth-db-api/optimism",
|
||||||
"reth-optimism-primitives/op",
|
"reth-optimism-primitives/optimism",
|
||||||
"reth-downloaders/optimism"
|
"reth-downloaders/optimism"
|
||||||
]
|
]
|
||||||
asm-keccak = [
|
asm-keccak = [
|
||||||
|
|||||||
@ -22,7 +22,8 @@ reth-trie-common.workspace = true
|
|||||||
# op-reth
|
# op-reth
|
||||||
reth-optimism-forks.workspace = true
|
reth-optimism-forks.workspace = true
|
||||||
reth-optimism-chainspec.workspace = true
|
reth-optimism-chainspec.workspace = true
|
||||||
reth-optimism-primitives.workspace = true
|
# TODO: remove this after feature cleanup
|
||||||
|
reth-optimism-primitives = { workspace = true, features = ["serde"] }
|
||||||
|
|
||||||
# ethereum
|
# ethereum
|
||||||
alloy-primitives.workspace = true
|
alloy-primitives.workspace = true
|
||||||
@ -36,4 +37,4 @@ alloy-primitives.workspace = true
|
|||||||
reth-optimism-chainspec.workspace = true
|
reth-optimism-chainspec.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
optimism = ["reth-primitives/optimism"]
|
optimism = ["reth-primitives/optimism", "reth-optimism-primitives/optimism"]
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
// The `optimism` feature must be enabled to use this crate.
|
// The `optimism` feature must be enabled to use this crate.
|
||||||
#![cfg(feature = "optimism")]
|
#![cfg(feature = "optimism")]
|
||||||
|
|
||||||
use alloy_consensus::{Header, EMPTY_OMMER_ROOT_HASH};
|
use alloy_consensus::{BlockHeader, Header, EMPTY_OMMER_ROOT_HASH};
|
||||||
use alloy_primitives::{B64, U256};
|
use alloy_primitives::{B64, U256};
|
||||||
use reth_chainspec::EthereumHardforks;
|
use reth_chainspec::EthereumHardforks;
|
||||||
use reth_consensus::{
|
use reth_consensus::{
|
||||||
@ -112,11 +112,30 @@ impl HeaderValidator for OpBeaconConsensus {
|
|||||||
validate_against_parent_timestamp(header.header(), parent.header())?;
|
validate_against_parent_timestamp(header.header(), parent.header())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
validate_against_parent_eip1559_base_fee(
|
// EIP1559 base fee validation
|
||||||
header.header(),
|
// <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#base-fee-computation>
|
||||||
parent.header(),
|
// > if Holocene is active in parent_header.timestamp, then the parameters from
|
||||||
&self.chain_spec,
|
// > parent_header.extraData are used.
|
||||||
)?;
|
if self.chain_spec.is_holocene_active_at_timestamp(parent.timestamp) {
|
||||||
|
let header_base_fee =
|
||||||
|
header.base_fee_per_gas().ok_or(ConsensusError::BaseFeeMissing)?;
|
||||||
|
let expected_base_fee = self
|
||||||
|
.chain_spec
|
||||||
|
.decode_holocene_base_fee(parent, header.timestamp)
|
||||||
|
.map_err(|_| ConsensusError::BaseFeeMissing)?;
|
||||||
|
if expected_base_fee != header_base_fee {
|
||||||
|
return Err(ConsensusError::BaseFeeDiff(GotExpected {
|
||||||
|
expected: expected_base_fee,
|
||||||
|
got: header_base_fee,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
validate_against_parent_eip1559_base_fee(
|
||||||
|
header.header(),
|
||||||
|
parent.header(),
|
||||||
|
&self.chain_spec,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
// ensure that the blob gas fields for this block
|
// ensure that the blob gas fields for this block
|
||||||
if self.chain_spec.is_cancun_active_at_timestamp(header.timestamp) {
|
if self.chain_spec.is_cancun_active_at_timestamp(header.timestamp) {
|
||||||
|
|||||||
@ -75,5 +75,5 @@ optimism = [
|
|||||||
"reth-optimism-consensus/optimism",
|
"reth-optimism-consensus/optimism",
|
||||||
"revm/optimism",
|
"revm/optimism",
|
||||||
"revm-primitives/optimism",
|
"revm-primitives/optimism",
|
||||||
"reth-optimism-primitives/op",
|
"reth-optimism-primitives/optimism",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -97,7 +97,7 @@ optimism = [
|
|||||||
"reth-db/optimism",
|
"reth-db/optimism",
|
||||||
"reth-optimism-node/optimism",
|
"reth-optimism-node/optimism",
|
||||||
"reth-node-core/optimism",
|
"reth-node-core/optimism",
|
||||||
"reth-optimism-primitives/op",
|
"reth-optimism-primitives/optimism",
|
||||||
]
|
]
|
||||||
asm-keccak = [
|
asm-keccak = [
|
||||||
"reth-primitives/asm-keccak",
|
"reth-primitives/asm-keccak",
|
||||||
|
|||||||
@ -101,6 +101,7 @@ arbitrary = [
|
|||||||
"revm-primitives/arbitrary",
|
"revm-primitives/arbitrary",
|
||||||
"rand",
|
"rand",
|
||||||
]
|
]
|
||||||
op = [
|
optimism = [
|
||||||
"revm-primitives/optimism",
|
"revm-primitives/optimism",
|
||||||
|
"reth-primitives/optimism"
|
||||||
]
|
]
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
)]
|
)]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||||
// The `optimism` feature must be enabled to use this crate.
|
// The `optimism` feature must be enabled to use this crate.
|
||||||
#![cfg(feature = "op")]
|
#![cfg(feature = "optimism")]
|
||||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,7 @@
|
|||||||
//! A signed Optimism transaction.
|
//! A signed Optimism transaction.
|
||||||
|
|
||||||
|
use crate::{OpTransaction, OpTxType};
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::{
|
|
||||||
hash::{Hash, Hasher},
|
|
||||||
mem,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use std::sync::OnceLock;
|
|
||||||
|
|
||||||
use alloy_consensus::{
|
use alloy_consensus::{
|
||||||
transaction::RlpEcdsaTx, SignableTransaction, Transaction, TxEip1559, TxEip2930, TxEip7702,
|
transaction::RlpEcdsaTx, SignableTransaction, Transaction, TxEip1559, TxEip2930, TxEip7702,
|
||||||
};
|
};
|
||||||
@ -20,6 +14,10 @@ use alloy_primitives::{
|
|||||||
keccak256, Address, Bytes, PrimitiveSignature as Signature, TxHash, TxKind, Uint, B256, U256,
|
keccak256, Address, Bytes, PrimitiveSignature as Signature, TxHash, TxKind, Uint, B256, U256,
|
||||||
};
|
};
|
||||||
use alloy_rlp::Header;
|
use alloy_rlp::Header;
|
||||||
|
use core::{
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
mem,
|
||||||
|
};
|
||||||
use derive_more::{AsRef, Deref};
|
use derive_more::{AsRef, Deref};
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
use once_cell::sync::OnceCell as OnceLock;
|
use once_cell::sync::OnceCell as OnceLock;
|
||||||
@ -32,8 +30,8 @@ use reth_primitives::{
|
|||||||
};
|
};
|
||||||
use reth_primitives_traits::{FillTxEnv, InMemorySize, SignedTransaction};
|
use reth_primitives_traits::{FillTxEnv, InMemorySize, SignedTransaction};
|
||||||
use revm_primitives::{AuthorizationList, OptimismFields, TxEnv};
|
use revm_primitives::{AuthorizationList, OptimismFields, TxEnv};
|
||||||
|
#[cfg(feature = "std")]
|
||||||
use crate::{OpTransaction, OpTxType};
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
/// Signed transaction.
|
/// Signed transaction.
|
||||||
#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(rlp))]
|
#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(rlp))]
|
||||||
@ -105,10 +103,6 @@ impl SignedTransaction for OpTransactionSigned {
|
|||||||
recover_signer_unchecked(signature, signature_hash)
|
recover_signer_unchecked(signature, signature_hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recalculate_hash(&self) -> B256 {
|
|
||||||
keccak256(self.encoded_2718())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recover_signer_unchecked_with_buf(&self, buf: &mut Vec<u8>) -> Option<Address> {
|
fn recover_signer_unchecked_with_buf(&self, buf: &mut Vec<u8>) -> Option<Address> {
|
||||||
// Optimism's Deposit transaction does not have a signature. Directly return the
|
// Optimism's Deposit transaction does not have a signature. Directly return the
|
||||||
// `from` address.
|
// `from` address.
|
||||||
@ -119,6 +113,10 @@ impl SignedTransaction for OpTransactionSigned {
|
|||||||
let signature_hash = keccak256(buf);
|
let signature_hash = keccak256(buf);
|
||||||
recover_signer_unchecked(&self.signature, signature_hash)
|
recover_signer_unchecked(&self.signature, signature_hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn recalculate_hash(&self) -> B256 {
|
||||||
|
keccak256(self.encoded_2718())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FillTxEnv for OpTransactionSigned {
|
impl FillTxEnv for OpTransactionSigned {
|
||||||
|
|||||||
@ -73,5 +73,5 @@ optimism = [
|
|||||||
"revm/optimism",
|
"revm/optimism",
|
||||||
"reth-optimism-consensus/optimism",
|
"reth-optimism-consensus/optimism",
|
||||||
"reth-optimism-payload-builder/optimism",
|
"reth-optimism-payload-builder/optimism",
|
||||||
"reth-optimism-primitives/op",
|
"reth-optimism-primitives/optimism",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -96,7 +96,7 @@ optimism = [
|
|||||||
"reth-db/optimism",
|
"reth-db/optimism",
|
||||||
"reth-db-api/optimism",
|
"reth-db-api/optimism",
|
||||||
"revm/optimism",
|
"revm/optimism",
|
||||||
"reth-optimism-primitives/op",
|
"reth-optimism-primitives/optimism",
|
||||||
]
|
]
|
||||||
serde = [
|
serde = [
|
||||||
"dashmap/serde",
|
"dashmap/serde",
|
||||||
|
|||||||
Reference in New Issue
Block a user