From 2a2c56dbc670962220c0f41e89c060faf62de3f5 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Thu, 29 Feb 2024 22:18:46 +0100 Subject: [PATCH] Compute min length mempool transactions message by type (#6853) --- crates/primitives/src/transaction/mod.rs | 136 +++++++++++++++++++++-- 1 file changed, 127 insertions(+), 9 deletions(-) diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 565b88c553..bf0594ea8c 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -69,6 +69,18 @@ pub(crate) static PARALLEL_SENDER_RECOVERY_THRESHOLD: Lazy = _ => 5, }); +/// Minimum length of a rlp-encoded legacy transaction. +pub const MIN_LENGTH_LEGACY_TX_ENCODED: usize = 10; +/// Minimum length of a rlp-encoded eip2930 transaction. +pub const MIN_LENGTH_EIP2930_TX_ENCODED: usize = 14; +/// Minimum length of a rlp-encoded eip1559 transaction. +pub const MIN_LENGTH_EIP1559_TX_ENCODED: usize = 15; +/// Minimum length of a rlp-encoded eip4844 transaction. +pub const MIN_LENGTH_EIP4844_TX_ENCODED: usize = 17; +/// Minimum length of a rlp-encoded deposit transaction. +#[cfg(feature = "optimism")] +pub const MIN_LENGTH_DEPOSIT_TX_ENCODED: usize = 65; + /// A raw transaction. /// /// Transaction types were introduced in [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718). @@ -1233,7 +1245,8 @@ impl TransactionSigned { data: &mut &[u8], ) -> alloy_rlp::Result { // keep this around so we can use it to calculate the hash - let original_encoding = *data; + let original_encoding_without_header = *data; + let tx_type = *data.first().ok_or(RlpError::InputTooShort)?; data.advance(1); @@ -1249,20 +1262,23 @@ impl TransactionSigned { let tx_length = 1 + header.length() + header.payload_length; // decode common fields + let Ok(tx_type) = TxType::try_from(tx_type) else { + return Err(RlpError::Custom("unsupported typed transaction type")) + }; let transaction = match tx_type { - 1 => Transaction::Eip2930(TxEip2930::decode_inner(data)?), - 2 => Transaction::Eip1559(TxEip1559::decode_inner(data)?), - 3 => Transaction::Eip4844(TxEip4844::decode_inner(data)?), + TxType::EIP2930 => Transaction::Eip2930(TxEip2930::decode_inner(data)?), + TxType::EIP1559 => Transaction::Eip1559(TxEip1559::decode_inner(data)?), + TxType::EIP4844 => Transaction::Eip4844(TxEip4844::decode_inner(data)?), #[cfg(feature = "optimism")] - 0x7E => Transaction::Deposit(TxDeposit::decode_inner(data)?), - _ => return Err(RlpError::Custom("unsupported typed transaction type")), + TxType::DEPOSIT => Transaction::Deposit(TxDeposit::decode_inner(data)?), + TxType::Legacy => unreachable!("path for legacy tx has diverged before this method"), }; #[cfg(not(feature = "optimism"))] let signature = Signature::decode(data)?; #[cfg(feature = "optimism")] - let signature = if tx_type == DEPOSIT_TX_TYPE_ID { + let signature = if let TxType::DEPOSIT = tx_type { Signature::optimism_deposit_tx_signature() } else { Signature::decode(data)? @@ -1273,7 +1289,7 @@ impl TransactionSigned { return Err(RlpError::UnexpectedLength) } - let hash = keccak256(&original_encoding[..tx_length]); + let hash = keccak256(&original_encoding_without_header[..tx_length]); let signed = TransactionSigned { transaction, hash, signature }; Ok(signed) } @@ -1579,9 +1595,12 @@ mod tests { hex, sign_message, transaction::{ signature::Signature, TransactionKind, TxEip1559, TxLegacy, + MIN_LENGTH_EIP1559_TX_ENCODED, MIN_LENGTH_EIP2930_TX_ENCODED, + MIN_LENGTH_EIP4844_TX_ENCODED, MIN_LENGTH_LEGACY_TX_ENCODED, PARALLEL_SENDER_RECOVERY_THRESHOLD, }, - Address, Bytes, Transaction, TransactionSigned, TransactionSignedEcRecovered, B256, U256, + Address, Bytes, Transaction, TransactionSigned, TransactionSignedEcRecovered, TxEip2930, + TxEip4844, B256, U256, }; use alloy_primitives::{address, b256, bytes}; use alloy_rlp::{Decodable, Encodable, Error as RlpError}; @@ -1926,4 +1945,103 @@ mod tests { let encoded = tx.envelope_encoded(); assert_eq!(encoded.as_ref(), data.as_slice()); } + + #[test] + fn min_length_encoded_legacy_transaction() { + let transaction = TxLegacy::default(); + let signature = Signature::default(); + + let signed_tx = TransactionSigned::from_transaction_and_signature( + Transaction::Legacy(transaction), + signature, + ); + + let mut encoded = BytesMut::new(); + signed_tx.encode(&mut encoded); + + assert_eq!(hex!("c98080808080801b8080"), &encoded[..]); + assert_eq!(MIN_LENGTH_LEGACY_TX_ENCODED, encoded.len()); + + TransactionSigned::decode(&mut &encoded[..]).unwrap(); + } + + #[test] + fn min_length_encoded_eip2930_transaction() { + let transaction = TxEip2930::default(); + let signature = Signature::default(); + + let signed_tx = TransactionSigned::from_transaction_and_signature( + Transaction::Eip2930(transaction), + signature, + ); + + let mut encoded = BytesMut::new(); + signed_tx.encode(&mut encoded); + + assert_eq!(hex!("8d01cb80808080808080c0808080"), &encoded[..]); + assert_eq!(MIN_LENGTH_EIP2930_TX_ENCODED, encoded.len()); + + TransactionSigned::decode(&mut &encoded[..]).unwrap(); + } + + #[test] + fn min_length_encoded_eip1559_transaction() { + let transaction = TxEip1559::default(); + let signature = Signature::default(); + + let signed_tx = TransactionSigned::from_transaction_and_signature( + Transaction::Eip1559(transaction), + signature, + ); + + let mut encoded = BytesMut::new(); + signed_tx.encode(&mut encoded); + + assert_eq!(hex!("8e02cc8080808080808080c0808080"), &encoded[..]); + assert_eq!(MIN_LENGTH_EIP1559_TX_ENCODED, encoded.len()); + + TransactionSigned::decode(&mut &encoded[..]).unwrap(); + } + + #[test] + fn min_length_encoded_eip4844_transaction() { + let transaction = TxEip4844::default(); + let signature = Signature::default(); + + let signed_tx = TransactionSigned::from_transaction_and_signature( + Transaction::Eip4844(transaction), + signature, + ); + + let mut encoded = BytesMut::new(); + signed_tx.encode(&mut encoded); + + assert_eq!(hex!("9003ce8080808080808080c080c0808080"), &encoded[..]); + assert_eq!(MIN_LENGTH_EIP4844_TX_ENCODED, encoded.len()); + + TransactionSigned::decode(&mut &encoded[..]).unwrap(); + } + + #[cfg(feature = "optimism")] + #[test] + fn min_length_encoded_deposit_transaction() { + use super::MIN_LENGTH_DEPOSIT_TX_ENCODED; + use crate::TxDeposit; + + let transaction = TxDeposit::default(); + let signature = Signature::default(); + + let signed_tx = TransactionSigned::from_transaction_and_signature( + Transaction::Deposit(transaction), + signature, + ); + + let mut encoded = BytesMut::new(); + signed_tx.encode(&mut encoded); + + assert_eq!(b"\xb8?~\xf8<\xa0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x94\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\x80\x80\x80\x80\x80", &encoded[..]); + assert_eq!(MIN_LENGTH_DEPOSIT_TX_ENCODED, encoded.len()); + + TransactionSigned::decode(&mut &encoded[..]).unwrap(); + } }