chore: use OpTypedTransaction directly (#13350)

This commit is contained in:
Arsenii Kulikov
2024-12-12 18:31:37 +04:00
committed by GitHub
parent 59fb0e210d
commit aef9023781
5 changed files with 93 additions and 229 deletions

View File

@ -16,7 +16,7 @@ extern crate alloc;
pub mod bedrock; pub mod bedrock;
pub mod transaction; pub mod transaction;
pub use transaction::{signed::OpTransactionSigned, tx_type::OpTxType, OpTransaction}; pub use transaction::{signed::OpTransactionSigned, tx_type::OpTxType};
mod receipt; mod receipt;
pub use receipt::OpReceipt; pub use receipt::OpReceipt;

View File

@ -1,201 +1,4 @@
//! Wrapper of [`OpTypedTransaction`], that implements reth database encoding [`Compact`]. //! Optimism transaction types
pub mod signed; pub mod signed;
pub mod tx_type; 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<B>(&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<u64> {
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<u128> {
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<u128> {
self.0.max_priority_fee_per_gas()
}
fn max_fee_per_blob_gas(&self) -> Option<u128> {
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<u64>) -> u128 {
self.0.effective_gas_price(base_fee)
}
fn effective_tip_per_gas(&self, base_fee: u64) -> Option<u128> {
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()
}
}

View File

@ -1,6 +1,6 @@
//! A signed Optimism transaction. //! A signed Optimism transaction.
use crate::{OpTransaction, OpTxType}; use crate::OpTxType;
use alloc::vec::Vec; use alloc::vec::Vec;
use alloy_consensus::{ use alloy_consensus::{
transaction::RlpEcdsaTx, SignableTransaction, Transaction, TxEip1559, TxEip2930, TxEip7702, transaction::RlpEcdsaTx, SignableTransaction, Transaction, TxEip1559, TxEip2930, TxEip7702,
@ -47,7 +47,7 @@ pub struct OpTransactionSigned {
/// Raw transaction info /// Raw transaction info
#[deref] #[deref]
#[as_ref] #[as_ref]
pub transaction: OpTransaction, pub transaction: OpTypedTransaction,
} }
impl OpTransactionSigned { impl OpTransactionSigned {
@ -65,7 +65,7 @@ impl OpTransactionSigned {
/// ///
/// Note: this only calculates the hash on the first [`TransactionSigned::hash`] call. /// Note: this only calculates the hash on the first [`TransactionSigned::hash`] call.
pub fn new_unhashed(transaction: OpTypedTransaction, signature: Signature) -> Self { 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<Address> { fn recover_signer(&self) -> 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.
if let OpTypedTransaction::Deposit(TxDeposit { from, .. }) = *self.transaction { if let OpTypedTransaction::Deposit(TxDeposit { from, .. }) = self.transaction {
return Some(from) return Some(from)
} }
@ -93,8 +93,8 @@ impl SignedTransaction for OpTransactionSigned {
fn recover_signer_unchecked(&self) -> Option<Address> { fn recover_signer_unchecked(&self) -> 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.
if let OpTypedTransaction::Deposit(TxDeposit { from, .. }) = *self.transaction { if let OpTypedTransaction::Deposit(TxDeposit { from, .. }) = &self.transaction {
return Some(from) return Some(*from)
} }
let Self { transaction, signature, .. } = self; let Self { transaction, signature, .. } = self;
@ -103,14 +103,16 @@ impl SignedTransaction for OpTransactionSigned {
} }
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 match &self.transaction {
// `from` address. // Optimism's Deposit transaction does not have a signature. Directly return the
if let OpTypedTransaction::Deposit(TxDeposit { from, .. }) = *self.transaction { // `from` address.
return Some(from) OpTypedTransaction::Deposit(tx) => return Some(tx.from),
} OpTypedTransaction::Legacy(tx) => tx.encode_for_signing(buf),
self.encode_for_signing(buf); OpTypedTransaction::Eip2930(tx) => tx.encode_for_signing(buf),
let signature_hash = keccak256(buf); OpTypedTransaction::Eip1559(tx) => tx.encode_for_signing(buf),
recover_signer_unchecked(&self.signature, signature_hash) OpTypedTransaction::Eip7702(tx) => tx.encode_for_signing(buf),
};
recover_signer_unchecked(&self.signature, keccak256(buf))
} }
fn recalculate_hash(&self) -> B256 { fn recalculate_hash(&self) -> B256 {
@ -123,7 +125,7 @@ impl FillTxEnv for OpTransactionSigned {
let envelope = self.encoded_2718(); let envelope = self.encoded_2718();
tx_env.caller = sender; tx_env.caller = sender;
match self.transaction.deref() { match &self.transaction {
OpTypedTransaction::Legacy(tx) => { OpTypedTransaction::Legacy(tx) => {
tx_env.gas_limit = tx.gas_limit; tx_env.gas_limit = tx.gas_limit;
tx_env.gas_price = U256::from(tx.gas_price); tx_env.gas_price = U256::from(tx.gas_price);
@ -252,7 +254,7 @@ impl Encodable2718 for OpTransactionSigned {
} }
fn encode_2718_len(&self) -> usize { fn encode_2718_len(&self) -> usize {
match self.transaction.deref() { match &self.transaction {
OpTypedTransaction::Legacy(legacy_tx) => { OpTypedTransaction::Legacy(legacy_tx) => {
legacy_tx.eip2718_encoded_length(&self.signature) 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) { fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) {
let Self { transaction, signature, .. } = self; let Self { transaction, signature, .. } = self;
match transaction.deref() { match &transaction {
OpTypedTransaction::Legacy(legacy_tx) => { OpTypedTransaction::Legacy(legacy_tx) => {
// do nothing w/ with_header // do nothing w/ with_header
legacy_tx.eip2718_encode(signature, out) 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 { impl PartialEq for OpTransactionSigned {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.signature == other.signature && self.signature == other.signature &&
@ -463,7 +455,7 @@ impl<'a> arbitrary::Arbitrary<'a> for OpTransactionSigned {
} }
/// Calculates the signing hash for the transaction. /// Calculates the signing hash for the transaction.
pub fn signature_hash(tx: &OpTypedTransaction) -> B256 { fn signature_hash(tx: &OpTypedTransaction) -> B256 {
match tx { match tx {
OpTypedTransaction::Legacy(tx) => tx.signature_hash(), OpTypedTransaction::Legacy(tx) => tx.signature_hash(),
OpTypedTransaction::Eip2930(tx) => tx.signature_hash(), OpTypedTransaction::Eip2930(tx) => tx.signature_hash(),

View File

@ -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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -3,7 +3,7 @@
use alloy_consensus::constants::EIP7702_TX_TYPE_ID; use alloy_consensus::constants::EIP7702_TX_TYPE_ID;
use crate::Compact; use crate::Compact;
use alloy_primitives::{Address, Bytes, TxKind, B256, U256}; 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 reth_codecs_derive::add_arbitrary_tests;
use crate::txtype::{COMPACT_EXTENDED_IDENTIFIER_FLAG, COMPACT_IDENTIFIER_EIP1559, COMPACT_IDENTIFIER_EIP2930, COMPACT_IDENTIFIER_LEGACY}; use crate::txtype::{COMPACT_EXTENDED_IDENTIFIER_FLAG, COMPACT_IDENTIFIER_EIP1559, COMPACT_IDENTIFIER_EIP2930, COMPACT_IDENTIFIER_LEGACY};
@ -115,3 +115,59 @@ impl crate::Compact for OpTxType {
) )
} }
} }
impl Compact for OpTypedTransaction {
fn to_compact<B>(&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}"),
}
}
}