Skip to content

Commit

Permalink
Merge branch 'main' into matt/docs-forkid
Browse files Browse the repository at this point in the history
  • Loading branch information
mattsse committed Dec 12, 2024
2 parents 466e819 + 1535664 commit adcecc0
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 111 deletions.
29 changes: 15 additions & 14 deletions Cargo.lock

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

10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -477,11 +477,11 @@ alloy-transport-ipc = { version = "0.8.0", default-features = false }
alloy-transport-ws = { version = "0.8.0", default-features = false }

# op
op-alloy-rpc-types = "0.8.1"
op-alloy-rpc-types-engine = "0.8.1"
op-alloy-rpc-jsonrpsee = "0.8.1"
op-alloy-network = "0.8.1"
op-alloy-consensus = "0.8.1"
op-alloy-rpc-types = "0.8.2"
op-alloy-rpc-types-engine = "0.8.2"
op-alloy-rpc-jsonrpsee = "0.8.2"
op-alloy-network = "0.8.2"
op-alloy-consensus = "0.8.2"

# misc
aquamarine = "0.6"
Expand Down
1 change: 1 addition & 0 deletions crates/optimism/chainspec/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ alloy-eips.workspace = true

# op
op-alloy-rpc-types.workspace = true
op-alloy-consensus.workspace = true

# io
serde_json.workspace = true
Expand Down
47 changes: 6 additions & 41 deletions crates/optimism/chainspec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub use dev::OP_DEV;
#[cfg(not(feature = "std"))]
pub(crate) use once_cell::sync::Lazy as LazyLock;
pub use op::OP_MAINNET;
use op_alloy_consensus::{decode_holocene_extra_data, EIP1559ParamError};
pub use op_sepolia::OP_SEPOLIA;
use reth_chainspec::{
BaseFeeParams, BaseFeeParamsKind, ChainSpec, ChainSpecBuilder, DepositContract, EthChainSpec,
Expand Down Expand Up @@ -201,8 +202,8 @@ impl OpChainSpec {
&self,
parent: &Header,
timestamp: u64,
) -> Result<u64, DecodeError> {
let (denominator, elasticity) = decode_holocene_1559_params(&parent.extra_data)?;
) -> Result<u64, EIP1559ParamError> {
let (denominator, elasticity) = decode_holocene_extra_data(&parent.extra_data)?;
let base_fee = if elasticity == 0 && denominator == 0 {
parent
.next_block_base_fee(self.base_fee_params_at_timestamp(timestamp))
Expand All @@ -221,13 +222,11 @@ impl OpChainSpec {
&self,
parent: &Header,
timestamp: u64,
) -> Result<U256, DecodeError> {
) -> Result<U256, EIP1559ParamError> {
// > if Holocene is active in parent_header.timestamp, then the parameters from
// > parent_header.extraData are used.
let is_holocene_activated = self.inner.is_fork_active_at_timestamp(
reth_optimism_forks::OpHardfork::Holocene,
parent.timestamp,
);
let is_holocene_activated =
self.inner.is_fork_active_at_timestamp(OpHardfork::Holocene, parent.timestamp);

// If we are in the Holocene, we need to use the base fee params
// from the parent block's extra data.
Expand All @@ -244,40 +243,6 @@ impl OpChainSpec {
}
}

#[derive(Clone, Debug, Display, Eq, PartialEq)]
/// Error type for decoding Holocene 1559 parameters
pub enum DecodeError {
#[display("Insufficient data to decode")]
/// Insufficient data to decode
InsufficientData,
#[display("Invalid denominator parameter")]
/// Invalid denominator parameter
InvalidDenominator,
#[display("Invalid elasticity parameter")]
/// Invalid elasticity parameter
InvalidElasticity,
}

impl core::error::Error for DecodeError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
// None of the errors have sub-errors
None
}
}

/// 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>
pub fn decode_holocene_1559_params(extra_data: &[u8]) -> Result<(u32, u32), DecodeError> {
if extra_data.len() < 9 {
return Err(DecodeError::InsufficientData);
}
let denominator: [u8; 4] =
extra_data[1..5].try_into().map_err(|_| DecodeError::InvalidDenominator)?;
let elasticity: [u8; 4] =
extra_data[5..9].try_into().map_err(|_| DecodeError::InvalidElasticity)?;
Ok((u32::from_be_bytes(denominator), u32::from_be_bytes(elasticity)))
}

impl EthChainSpec for OpChainSpec {
type Header = Header;

Expand Down
5 changes: 3 additions & 2 deletions crates/optimism/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ extern crate alloc;
use alloc::{sync::Arc, vec::Vec};
use alloy_consensus::Header;
use alloy_primitives::{Address, U256};
use op_alloy_consensus::EIP1559ParamError;
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes};
use reth_optimism_chainspec::{DecodeError, OpChainSpec};
use reth_optimism_chainspec::OpChainSpec;
use reth_primitives::{transaction::FillTxEnv, Head, TransactionSigned};
use reth_revm::{
inspector_handle_register,
Expand Down Expand Up @@ -58,7 +59,7 @@ impl OpEvmConfig {
impl ConfigureEvmEnv for OpEvmConfig {
type Header = Header;
type Transaction = TransactionSigned;
type Error = DecodeError;
type Error = EIP1559ParamError;

fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) {
transaction.fill_tx_env(tx_env, sender);
Expand Down
4 changes: 2 additions & 2 deletions crates/optimism/payload/src/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use alloy_eips::{
use alloy_primitives::{keccak256, Address, Bytes, B256, B64, U256};
use alloy_rlp::Encodable;
use alloy_rpc_types_engine::{ExecutionPayloadEnvelopeV2, ExecutionPayloadV1, PayloadId};
use op_alloy_consensus::{decode_holocene_extra_data, EIP1559ParamError};
use op_alloy_consensus::{encode_holocene_extra_data, EIP1559ParamError};
/// Re-export for use in downstream arguments.
pub use op_alloy_rpc_types_engine::OpPayloadAttributes;
use op_alloy_rpc_types_engine::{OpExecutionPayloadEnvelopeV3, OpExecutionPayloadEnvelopeV4};
Expand Down Expand Up @@ -45,7 +45,7 @@ impl OpPayloadBuilderAttributes {
default_base_fee_params: BaseFeeParams,
) -> Result<Bytes, EIP1559ParamError> {
self.eip_1559_params
.map(|params| decode_holocene_extra_data(params, default_base_fee_params))
.map(|params| encode_holocene_extra_data(params, default_base_fee_params))
.ok_or(EIP1559ParamError::NoEIP1559Params)?
}
}
Expand Down
56 changes: 47 additions & 9 deletions crates/primitives-traits/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,47 @@ pub const SECP256K1N_HALF: U256 = U256::from_be_bytes([
]);

/// Secp256k1 utility functions.
#[cfg(feature = "secp256k1")]
pub mod secp256k1 {
pub use super::impl_secp256k1::*;
}
use super::*;
use revm_primitives::{Address, B256};

/// Secp256k1 utility functions.
#[cfg(not(feature = "secp256k1"))]
pub mod secp256k1 {
pub use super::impl_k256::*;
#[cfg(not(feature = "secp256k1"))]
use super::impl_k256 as imp;
#[cfg(feature = "secp256k1")]
use super::impl_secp256k1 as imp;

pub use imp::{public_key_to_address, sign_message};

/// Recover signer from message hash, _without ensuring that the signature has a low `s`
/// value_.
///
/// Using this for signature validation will succeed, even if the signature is malleable or not
/// compliant with EIP-2. This is provided for compatibility with old signatures which have
/// large `s` values.
pub fn recover_signer_unchecked(signature: &Signature, hash: B256) -> Option<Address> {
let mut sig: [u8; 65] = [0; 65];

sig[0..32].copy_from_slice(&signature.r().to_be_bytes::<32>());
sig[32..64].copy_from_slice(&signature.s().to_be_bytes::<32>());
sig[64] = signature.v() as u8;

// NOTE: we are removing error from underlying crypto library as it will restrain primitive
// errors and we care only if recovery is passing or not.
imp::recover_signer_unchecked(&sig, &hash.0).ok()
}

/// Recover signer address from message hash. This ensures that the signature S value is
/// greater than `secp256k1n / 2`, as specified in
/// [EIP-2](https://eips.ethereum.org/EIPS/eip-2).
///
/// If the S value is too large, then this will return `None`
pub fn recover_signer(signature: &Signature, hash: B256) -> Option<Address> {
if signature.s() > SECP256K1N_HALF {
return None
}

recover_signer_unchecked(signature, hash)
}
}

#[cfg(feature = "secp256k1")]
Expand All @@ -41,7 +73,10 @@ mod impl_secp256k1 {
///
/// This does not ensure that the `s` value in the signature is low, and _just_ wraps the
/// underlying secp256k1 library.
pub fn recover_signer_unchecked(sig: &[u8; 65], msg: &[u8; 32]) -> Result<Address, Error> {
pub(crate) fn recover_signer_unchecked(
sig: &[u8; 65],
msg: &[u8; 32],
) -> Result<Address, Error> {
let sig =
RecoverableSignature::from_compact(&sig[0..64], RecoveryId::from_i32(sig[64] as i32)?)?;

Expand Down Expand Up @@ -87,7 +122,10 @@ mod impl_k256 {
///
/// This does not ensure that the `s` value in the signature is low, and _just_ wraps the
/// underlying secp256k1 library.
pub fn recover_signer_unchecked(sig: &[u8; 65], msg: &[u8; 32]) -> Result<Address, Error> {
pub(crate) fn recover_signer_unchecked(
sig: &[u8; 65],
msg: &[u8; 32],
) -> Result<Address, Error> {
let mut signature = k256::ecdsa::Signature::from_slice(&sig[0..64])?;
let mut recid = sig[64];

Expand Down
43 changes: 5 additions & 38 deletions crates/primitives/src/transaction/signature.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::transaction::util::secp256k1;
use alloy_consensus::transaction::from_eip155_value;
use alloy_primitives::{Address, PrimitiveSignature as Signature, B256, U256};
use alloy_primitives::{PrimitiveSignature as Signature, U256};
use alloy_rlp::Decodable;
use reth_primitives_traits::crypto::SECP256K1N_HALF;

pub use reth_primitives_traits::crypto::secp256k1::{recover_signer, recover_signer_unchecked};

pub(crate) fn decode_with_eip155_chain_id(
buf: &mut &[u8],
Expand All @@ -26,43 +26,10 @@ pub(crate) fn decode_with_eip155_chain_id(
Ok((Signature::new(r, s, parity), chain_id))
}

/// Recover signer from message hash, _without ensuring that the signature has a low `s`
/// value_.
///
/// Using this for signature validation will succeed, even if the signature is malleable or not
/// compliant with EIP-2. This is provided for compatibility with old signatures which have
/// large `s` values.
pub fn recover_signer_unchecked(signature: &Signature, hash: B256) -> Option<Address> {
let mut sig: [u8; 65] = [0; 65];

sig[0..32].copy_from_slice(&signature.r().to_be_bytes::<32>());
sig[32..64].copy_from_slice(&signature.s().to_be_bytes::<32>());
sig[64] = signature.v() as u8;

// NOTE: we are removing error from underlying crypto library as it will restrain primitive
// errors and we care only if recovery is passing or not.
secp256k1::recover_signer_unchecked(&sig, &hash.0).ok()
}

/// Recover signer address from message hash. This ensures that the signature S value is
/// greater than `secp256k1n / 2`, as specified in
/// [EIP-2](https://eips.ethereum.org/EIPS/eip-2).
///
/// If the S value is too large, then this will return `None`
pub fn recover_signer(signature: &Signature, hash: B256) -> Option<Address> {
if signature.s() > SECP256K1N_HALF {
return None
}

recover_signer_unchecked(signature, hash)
}

#[cfg(test)]
mod tests {
use crate::transaction::signature::{
recover_signer, recover_signer_unchecked, SECP256K1N_HALF,
};
use alloy_eips::eip2718::Decodable2718;
use crate::transaction::signature::{recover_signer, recover_signer_unchecked};
use alloy_eips::{eip2718::Decodable2718, eip7702::constants::SECP256K1N_HALF};
use alloy_primitives::{hex, Address, PrimitiveSignature as Signature, B256, U256};
use reth_primitives_traits::SignedTransaction;
use std::str::FromStr;
Expand Down

0 comments on commit adcecc0

Please sign in to comment.