From cd00498595d6904fa23081218c7a3158b5d50e03 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Sat, 1 Mar 2025 09:43:26 +0100 Subject: [PATCH] feat: add signabletx impl for typedtx (#462) this is quite useful and we don't expect this to be used for deposits --- crates/consensus/src/transaction/typed.rs | 64 +++++++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/crates/consensus/src/transaction/typed.rs b/crates/consensus/src/transaction/typed.rs index 05096f7e..b9ac870e 100644 --- a/crates/consensus/src/transaction/typed.rs +++ b/crates/consensus/src/transaction/typed.rs @@ -1,9 +1,12 @@ use crate::{OpTxEnvelope, OpTxType, TxDeposit}; use alloy_consensus::{ - SignableTransaction, Transaction, TxEip1559, TxEip2930, TxEip7702, TxLegacy, Typed2718, + transaction::RlpEcdsaTx, SignableTransaction, Signed, Transaction, TxEip1559, TxEip2930, + TxEip7702, TxLegacy, Typed2718, }; use alloy_eips::eip2930::AccessList; -use alloy_primitives::{Address, Bytes, TxKind, B256}; +use alloy_primitives::{ + bytes::BufMut, Address, Bytes, ChainId, PrimitiveSignature as Signature, TxHash, TxKind, B256, +}; /// The TypedTransaction enum represents all Ethereum transaction request types, modified for the OP /// Stack. @@ -93,7 +96,7 @@ impl OpTypedTransaction { /// Calculates the signing hash for the transaction. /// /// Returns `None` if the tx is a deposit transaction. - pub fn signature_hash(&self) -> Option { + pub fn checked_signature_hash(&self) -> Option { match self { Self::Legacy(tx) => Some(tx.signature_hash()), Self::Eip2930(tx) => Some(tx.signature_hash()), @@ -139,6 +142,19 @@ impl OpTypedTransaction { pub const fn is_deposit(&self) -> bool { matches!(self, Self::Deposit(_)) } + + /// Calculate the transaction hash for the given signature. + /// + /// Note: Returns the regular tx hash if this is a deposit variant + pub fn tx_hash(&self, signature: &Signature) -> TxHash { + match self { + Self::Legacy(tx) => tx.tx_hash(signature), + Self::Eip2930(tx) => tx.tx_hash(signature), + Self::Eip1559(tx) => tx.tx_hash(signature), + Self::Eip7702(tx) => tx.tx_hash(signature), + Self::Deposit(tx) => tx.tx_hash(), + } + } } impl Typed2718 for OpTypedTransaction { @@ -314,7 +330,7 @@ impl Transaction for OpTypedTransaction { } } - fn blob_versioned_hashes(&self) -> Option<&[alloy_primitives::B256]> { + fn blob_versioned_hashes(&self) -> Option<&[B256]> { match self { Self::Legacy(tx) => tx.blob_versioned_hashes(), Self::Eip2930(tx) => tx.blob_versioned_hashes(), @@ -335,6 +351,46 @@ impl Transaction for OpTypedTransaction { } } +impl SignableTransaction for OpTypedTransaction { + fn set_chain_id(&mut self, chain_id: ChainId) { + match self { + Self::Legacy(tx) => tx.set_chain_id(chain_id), + Self::Eip2930(tx) => tx.set_chain_id(chain_id), + Self::Eip1559(tx) => tx.set_chain_id(chain_id), + Self::Eip7702(tx) => tx.set_chain_id(chain_id), + Self::Deposit(_) => {} + } + } + + fn encode_for_signing(&self, out: &mut dyn BufMut) { + match self { + Self::Legacy(tx) => tx.encode_for_signing(out), + Self::Eip2930(tx) => tx.encode_for_signing(out), + Self::Eip1559(tx) => tx.encode_for_signing(out), + Self::Eip7702(tx) => tx.encode_for_signing(out), + Self::Deposit(_) => {} + } + } + + fn payload_len_for_signature(&self) -> usize { + match self { + Self::Legacy(tx) => tx.payload_len_for_signature(), + Self::Eip2930(tx) => tx.payload_len_for_signature(), + Self::Eip1559(tx) => tx.payload_len_for_signature(), + Self::Eip7702(tx) => tx.payload_len_for_signature(), + Self::Deposit(_) => 0, + } + } + + fn into_signed(self, signature: Signature) -> Signed + where + Self: Sized, + { + let hash = self.tx_hash(&signature); + Signed::new_unchecked(self, signature, hash) + } +} + #[cfg(feature = "serde")] mod serde_from { //! NB: Why do we need this?