diff --git a/crates/optimism/primitives/src/lib.rs b/crates/optimism/primitives/src/lib.rs index 2eedf2453..b2b9e60e5 100644 --- a/crates/optimism/primitives/src/lib.rs +++ b/crates/optimism/primitives/src/lib.rs @@ -16,7 +16,7 @@ extern crate alloc; pub mod bedrock; pub mod transaction; -pub use transaction::{signed::OpTransactionSigned, tx_type::OpTxType, OpTransaction}; +pub use transaction::{signed::OpTransactionSigned, tx_type::OpTxType}; mod receipt; pub use receipt::OpReceipt; diff --git a/crates/optimism/primitives/src/transaction/mod.rs b/crates/optimism/primitives/src/transaction/mod.rs index 214814dd8..ab45ec9ea 100644 --- a/crates/optimism/primitives/src/transaction/mod.rs +++ b/crates/optimism/primitives/src/transaction/mod.rs @@ -1,201 +1,4 @@ -//! Wrapper of [`OpTypedTransaction`], that implements reth database encoding [`Compact`]. +//! Optimism transaction types pub mod signed; pub mod tx_type; - -use alloy_primitives::{bytes, Bytes, TxKind, Uint, B256}; - -#[cfg(any(test, feature = "reth-codec"))] -use alloy_consensus::constants::EIP7702_TX_TYPE_ID; -use alloy_consensus::{SignableTransaction, TxLegacy, Typed2718}; -use alloy_eips::{eip2930::AccessList, eip7702::SignedAuthorization}; -use derive_more::{Constructor, Deref, From}; -use op_alloy_consensus::OpTypedTransaction; -#[cfg(any(test, feature = "reth-codec"))] -use op_alloy_consensus::DEPOSIT_TX_TYPE_ID; -#[cfg(any(test, feature = "reth-codec"))] -use reth_codecs::Compact; -#[cfg(any(test, feature = "reth-codec"))] -use reth_primitives::transaction::{ - COMPACT_EXTENDED_IDENTIFIER_FLAG, COMPACT_IDENTIFIER_EIP1559, COMPACT_IDENTIFIER_EIP2930, - COMPACT_IDENTIFIER_LEGACY, -}; -use reth_primitives_traits::InMemorySize; - -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Debug, Clone, PartialEq, Eq, Deref, Hash, From, Constructor)] -/// Optimistic transaction. -pub struct OpTransaction(OpTypedTransaction); - -impl OpTransaction { - /// This encodes the transaction _without_ the signature, and is only suitable for creating a - /// hash intended for signing. - pub fn encode_for_signing(&self, out: &mut dyn bytes::BufMut) { - match self.deref() { - OpTypedTransaction::Legacy(tx) => tx.encode_for_signing(out), - OpTypedTransaction::Eip2930(tx) => tx.encode_for_signing(out), - OpTypedTransaction::Eip1559(tx) => tx.encode_for_signing(out), - OpTypedTransaction::Eip7702(tx) => tx.encode_for_signing(out), - OpTypedTransaction::Deposit(_) => {} - } - } -} - -impl Default for OpTransaction { - fn default() -> Self { - Self(OpTypedTransaction::Legacy(TxLegacy::default())) - } -} - -#[cfg(any(test, feature = "reth-codec"))] -impl Compact for OpTransaction { - fn to_compact(&self, out: &mut B) -> usize - where - B: bytes::BufMut + AsMut<[u8]>, - { - match &self.0 { - OpTypedTransaction::Legacy(tx) => tx.to_compact(out), - OpTypedTransaction::Eip2930(tx) => tx.to_compact(out), - OpTypedTransaction::Eip1559(tx) => tx.to_compact(out), - OpTypedTransaction::Eip7702(tx) => tx.to_compact(out), - OpTypedTransaction::Deposit(tx) => tx.to_compact(out), - } - } - - fn from_compact(mut buf: &[u8], identifier: usize) -> (Self, &[u8]) { - use bytes::Buf; - - match identifier { - COMPACT_IDENTIFIER_LEGACY => { - let (tx, buf) = TxLegacy::from_compact(buf, buf.len()); - (Self(OpTypedTransaction::Legacy(tx)), buf) - } - COMPACT_IDENTIFIER_EIP2930 => { - let (tx, buf) = - alloy_consensus::transaction::TxEip2930::from_compact(buf, buf.len()); - (Self(OpTypedTransaction::Eip2930(tx)), buf) - } - COMPACT_IDENTIFIER_EIP1559 => { - let (tx, buf) = - alloy_consensus::transaction::TxEip1559::from_compact(buf, buf.len()); - (Self(OpTypedTransaction::Eip1559(tx)), buf) - } - COMPACT_EXTENDED_IDENTIFIER_FLAG => { - // An identifier of 3 indicates that the transaction type did not fit into - // the backwards compatible 2 bit identifier, their transaction types are - // larger than 2 bits (eg. 4844 and Deposit Transactions). In this case, - // we need to read the concrete transaction type from the buffer by - // reading the full 8 bits (single byte) and match on this transaction type. - let identifier = buf.get_u8(); - match identifier { - EIP7702_TX_TYPE_ID => { - let (tx, buf) = - alloy_consensus::transaction::TxEip7702::from_compact(buf, buf.len()); - (Self(OpTypedTransaction::Eip7702(tx)), buf) - } - DEPOSIT_TX_TYPE_ID => { - let (tx, buf) = op_alloy_consensus::TxDeposit::from_compact(buf, buf.len()); - (Self(OpTypedTransaction::Deposit(tx)), buf) - } - _ => unreachable!( - "Junk data in database: unknown Transaction variant: {identifier}" - ), - } - } - _ => unreachable!("Junk data in database: unknown Transaction variant: {identifier}"), - } - } -} - -impl alloy_consensus::Transaction for OpTransaction { - fn chain_id(&self) -> Option { - self.0.chain_id() - } - - fn nonce(&self) -> u64 { - self.0.nonce() - } - - fn gas_limit(&self) -> u64 { - self.0.gas_limit() - } - - fn gas_price(&self) -> Option { - self.0.gas_price() - } - - fn max_fee_per_gas(&self) -> u128 { - self.0.max_fee_per_gas() - } - - fn max_priority_fee_per_gas(&self) -> Option { - self.0.max_priority_fee_per_gas() - } - - fn max_fee_per_blob_gas(&self) -> Option { - self.0.max_fee_per_blob_gas() - } - - fn priority_fee_or_price(&self) -> u128 { - self.0.priority_fee_or_price() - } - - fn kind(&self) -> TxKind { - self.0.kind() - } - - fn is_create(&self) -> bool { - self.0.is_create() - } - - fn value(&self) -> Uint<256, 4> { - self.0.value() - } - - fn input(&self) -> &Bytes { - self.0.input() - } - - fn access_list(&self) -> Option<&AccessList> { - self.0.access_list() - } - - fn blob_versioned_hashes(&self) -> Option<&[B256]> { - self.0.blob_versioned_hashes() - } - - fn authorization_list(&self) -> Option<&[SignedAuthorization]> { - self.0.authorization_list() - } - - fn is_dynamic_fee(&self) -> bool { - self.0.is_dynamic_fee() - } - - fn effective_gas_price(&self, base_fee: Option) -> u128 { - self.0.effective_gas_price(base_fee) - } - - fn effective_tip_per_gas(&self, base_fee: u64) -> Option { - self.0.effective_tip_per_gas(base_fee) - } -} - -impl InMemorySize for OpTransaction { - fn size(&self) -> usize { - match &self.0 { - OpTypedTransaction::Legacy(tx) => tx.size(), - OpTypedTransaction::Eip2930(tx) => tx.size(), - OpTypedTransaction::Eip1559(tx) => tx.size(), - OpTypedTransaction::Eip7702(tx) => tx.size(), - OpTypedTransaction::Deposit(tx) => tx.size(), - } - } -} - -impl Typed2718 for OpTransaction { - fn ty(&self) -> u8 { - self.0.ty() - } -} diff --git a/crates/optimism/primitives/src/transaction/signed.rs b/crates/optimism/primitives/src/transaction/signed.rs index 796a33cf3..0d4c20447 100644 --- a/crates/optimism/primitives/src/transaction/signed.rs +++ b/crates/optimism/primitives/src/transaction/signed.rs @@ -1,6 +1,6 @@ //! A signed Optimism transaction. -use crate::{OpTransaction, OpTxType}; +use crate::OpTxType; use alloc::vec::Vec; use alloy_consensus::{ transaction::RlpEcdsaTx, SignableTransaction, Transaction, TxEip1559, TxEip2930, TxEip7702, @@ -47,7 +47,7 @@ pub struct OpTransactionSigned { /// Raw transaction info #[deref] #[as_ref] - pub transaction: OpTransaction, + pub transaction: OpTypedTransaction, } impl OpTransactionSigned { @@ -65,7 +65,7 @@ impl OpTransactionSigned { /// /// Note: this only calculates the hash on the first [`TransactionSigned::hash`] call. pub fn new_unhashed(transaction: OpTypedTransaction, signature: Signature) -> Self { - Self { hash: Default::default(), signature, transaction: OpTransaction::new(transaction) } + Self { hash: Default::default(), signature, transaction } } } @@ -81,7 +81,7 @@ impl SignedTransaction for OpTransactionSigned { fn recover_signer(&self) -> Option
{ // Optimism's Deposit transaction does not have a signature. Directly return the // `from` address. - if let OpTypedTransaction::Deposit(TxDeposit { from, .. }) = *self.transaction { + if let OpTypedTransaction::Deposit(TxDeposit { from, .. }) = self.transaction { return Some(from) } @@ -93,8 +93,8 @@ impl SignedTransaction for OpTransactionSigned { fn recover_signer_unchecked(&self) -> Option
{ // Optimism's Deposit transaction does not have a signature. Directly return the // `from` address. - if let OpTypedTransaction::Deposit(TxDeposit { from, .. }) = *self.transaction { - return Some(from) + if let OpTypedTransaction::Deposit(TxDeposit { from, .. }) = &self.transaction { + return Some(*from) } let Self { transaction, signature, .. } = self; @@ -103,14 +103,16 @@ impl SignedTransaction for OpTransactionSigned { } fn recover_signer_unchecked_with_buf(&self, buf: &mut Vec) -> Option
{ - // Optimism's Deposit transaction does not have a signature. Directly return the - // `from` address. - if let OpTypedTransaction::Deposit(TxDeposit { from, .. }) = *self.transaction { - return Some(from) - } - self.encode_for_signing(buf); - let signature_hash = keccak256(buf); - recover_signer_unchecked(&self.signature, signature_hash) + match &self.transaction { + // Optimism's Deposit transaction does not have a signature. Directly return the + // `from` address. + OpTypedTransaction::Deposit(tx) => return Some(tx.from), + OpTypedTransaction::Legacy(tx) => tx.encode_for_signing(buf), + OpTypedTransaction::Eip2930(tx) => tx.encode_for_signing(buf), + OpTypedTransaction::Eip1559(tx) => tx.encode_for_signing(buf), + OpTypedTransaction::Eip7702(tx) => tx.encode_for_signing(buf), + }; + recover_signer_unchecked(&self.signature, keccak256(buf)) } fn recalculate_hash(&self) -> B256 { @@ -123,7 +125,7 @@ impl FillTxEnv for OpTransactionSigned { let envelope = self.encoded_2718(); tx_env.caller = sender; - match self.transaction.deref() { + match &self.transaction { OpTypedTransaction::Legacy(tx) => { tx_env.gas_limit = tx.gas_limit; tx_env.gas_price = U256::from(tx.gas_price); @@ -252,7 +254,7 @@ impl Encodable2718 for OpTransactionSigned { } fn encode_2718_len(&self) -> usize { - match self.transaction.deref() { + match &self.transaction { OpTypedTransaction::Legacy(legacy_tx) => { legacy_tx.eip2718_encoded_length(&self.signature) } @@ -272,7 +274,7 @@ impl Encodable2718 for OpTransactionSigned { fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) { let Self { transaction, signature, .. } = self; - match transaction.deref() { + match &transaction { OpTypedTransaction::Legacy(legacy_tx) => { // do nothing w/ with_header legacy_tx.eip2718_encode(signature, out) @@ -408,16 +410,6 @@ impl Typed2718 for OpTransactionSigned { } } -impl Default for OpTransactionSigned { - fn default() -> Self { - Self { - hash: Default::default(), - signature: Signature::test_signature(), - transaction: OpTransaction::new(OpTypedTransaction::Legacy(Default::default())), - } - } -} - impl PartialEq for OpTransactionSigned { fn eq(&self, other: &Self) -> bool { self.signature == other.signature && @@ -463,7 +455,7 @@ impl<'a> arbitrary::Arbitrary<'a> for OpTransactionSigned { } /// Calculates the signing hash for the transaction. -pub fn signature_hash(tx: &OpTypedTransaction) -> B256 { +fn signature_hash(tx: &OpTypedTransaction) -> B256 { match tx { OpTypedTransaction::Legacy(tx) => tx.signature_hash(), OpTypedTransaction::Eip2930(tx) => tx.signature_hash(), diff --git a/crates/primitives-traits/src/size.rs b/crates/primitives-traits/src/size.rs index be19ae812..c9706aa65 100644 --- a/crates/primitives-traits/src/size.rs +++ b/crates/primitives-traits/src/size.rs @@ -69,6 +69,19 @@ impl InMemorySize for op_alloy_consensus::OpDepositReceipt { } } +#[cfg(feature = "op")] +impl InMemorySize for op_alloy_consensus::OpTypedTransaction { + fn size(&self) -> usize { + match self { + Self::Legacy(tx) => tx.size(), + Self::Eip2930(tx) => tx.size(), + Self::Eip1559(tx) => tx.size(), + Self::Eip7702(tx) => tx.size(), + Self::Deposit(tx) => tx.size(), + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/storage/codecs/src/alloy/transaction/optimism.rs b/crates/storage/codecs/src/alloy/transaction/optimism.rs index 631f5c406..ea06ae6b0 100644 --- a/crates/storage/codecs/src/alloy/transaction/optimism.rs +++ b/crates/storage/codecs/src/alloy/transaction/optimism.rs @@ -3,7 +3,7 @@ use alloy_consensus::constants::EIP7702_TX_TYPE_ID; use crate::Compact; use alloy_primitives::{Address, Bytes, TxKind, B256, U256}; -use op_alloy_consensus::{OpTxType, TxDeposit as AlloyTxDeposit}; +use op_alloy_consensus::{OpTxType, OpTypedTransaction, TxDeposit as AlloyTxDeposit, DEPOSIT_TX_TYPE_ID}; use reth_codecs_derive::add_arbitrary_tests; use crate::txtype::{COMPACT_EXTENDED_IDENTIFIER_FLAG, COMPACT_IDENTIFIER_EIP1559, COMPACT_IDENTIFIER_EIP2930, COMPACT_IDENTIFIER_LEGACY}; @@ -114,4 +114,60 @@ impl crate::Compact for OpTxType { buf, ) } -} \ No newline at end of file +} + +impl Compact for OpTypedTransaction { + fn to_compact(&self, out: &mut B) -> usize + where + B: bytes::BufMut + AsMut<[u8]>, + { + match self { + Self::Legacy(tx) => tx.to_compact(out), + Self::Eip2930(tx) => tx.to_compact(out), + Self::Eip1559(tx) => tx.to_compact(out), + Self::Eip7702(tx) => tx.to_compact(out), + Self::Deposit(tx) => tx.to_compact(out), + } + } + + fn from_compact(mut buf: &[u8], identifier: usize) -> (Self, &[u8]) { + use bytes::Buf; + + match identifier { + COMPACT_IDENTIFIER_LEGACY => { + let (tx, buf) = Compact::from_compact(buf, buf.len()); + (Self::Legacy(tx), buf) + } + COMPACT_IDENTIFIER_EIP2930 => { + let (tx, buf) = Compact::from_compact(buf, buf.len()); + (Self::Eip2930(tx), buf) + } + COMPACT_IDENTIFIER_EIP1559 => { + let (tx, buf) = Compact::from_compact(buf, buf.len()); + (Self::Eip1559(tx), buf) + } + COMPACT_EXTENDED_IDENTIFIER_FLAG => { + // An identifier of 3 indicates that the transaction type did not fit into + // the backwards compatible 2 bit identifier, their transaction types are + // larger than 2 bits (eg. 4844 and Deposit Transactions). In this case, + // we need to read the concrete transaction type from the buffer by + // reading the full 8 bits (single byte) and match on this transaction type. + let identifier = buf.get_u8(); + match identifier { + EIP7702_TX_TYPE_ID => { + let (tx, buf) = Compact::from_compact(buf, buf.len()); + (Self::Eip7702(tx), buf) + } + DEPOSIT_TX_TYPE_ID => { + let (tx, buf) = Compact::from_compact(buf, buf.len()); + (Self::Deposit(tx), buf) + } + _ => unreachable!( + "Junk data in database: unknown Transaction variant: {identifier}" + ), + } + } + _ => unreachable!("Junk data in database: unknown Transaction variant: {identifier}"), + } + } +}