diff --git a/crates/primitives-traits/src/lib.rs b/crates/primitives-traits/src/lib.rs index 6848da45814c..ab3985158d87 100644 --- a/crates/primitives-traits/src/lib.rs +++ b/crates/primitives-traits/src/lib.rs @@ -27,7 +27,7 @@ pub use receipt::{FullReceipt, Receipt}; pub mod transaction; pub use transaction::{ signed::{FullSignedTx, SignedTransaction}, - FullTransaction, Transaction, + FullTransaction, Transaction, TransactionExt, }; mod integer_list; @@ -80,3 +80,15 @@ pub use size::InMemorySize; /// Node traits pub mod node; pub use node::{FullNodePrimitives, NodePrimitives}; + +/// Helper trait that requires arbitrary implementation if the feature is enabled. +#[cfg(any(feature = "test-utils", feature = "arbitrary"))] +pub trait MaybeArbitrary: for<'a> arbitrary::Arbitrary<'a> {} +/// Helper trait that requires arbitrary implementation if the feature is enabled. +#[cfg(not(any(feature = "test-utils", feature = "arbitrary")))] +pub trait MaybeArbitrary {} + +#[cfg(any(feature = "test-utils", feature = "arbitrary"))] +impl MaybeArbitrary for T where T: for<'a> arbitrary::Arbitrary<'a> {} +#[cfg(not(any(feature = "test-utils", feature = "arbitrary")))] +impl MaybeArbitrary for T {} diff --git a/crates/primitives-traits/src/transaction/mod.rs b/crates/primitives-traits/src/transaction/mod.rs index d5061ca3909f..bb6f6a711e3e 100644 --- a/crates/primitives-traits/src/transaction/mod.rs +++ b/crates/primitives-traits/src/transaction/mod.rs @@ -1,17 +1,20 @@ //! Transaction abstraction -use core::{fmt, hash::Hash}; +pub mod signed; -use alloy_primitives::{TxKind, B256}; +use core::{fmt, hash::Hash}; +use alloy_primitives::B256; use reth_codecs::Compact; use serde::{Deserialize, Serialize}; -use crate::InMemorySize; +use crate::{InMemorySize, MaybeArbitrary, TxType}; -pub mod signed; +/// Helper trait that unifies all behaviour required by transaction to support full node operations. +pub trait FullTransaction: Transaction + Compact {} + +impl FullTransaction for T where T: Transaction + Compact {} -#[allow(dead_code)] /// Abstraction of a transaction. pub trait Transaction: Send @@ -24,41 +27,42 @@ pub trait Transaction: + PartialEq + Hash + Serialize - + alloy_rlp::Encodable - + alloy_rlp::Decodable + for<'de> Deserialize<'de> - + alloy_consensus::Transaction + + TransactionExt + InMemorySize + MaybeArbitrary { - /// Heavy operation that return signature hash over rlp encoded transaction. - /// It is only for signature signing or signer recovery. - fn signature_hash(&self) -> B256; - - /// Gets the transaction's [`TxKind`], which is the address of the recipient or - /// [`TxKind::Create`] if the transaction is a contract creation. - fn kind(&self) -> TxKind; - - /// Returns true if the tx supports dynamic fees - fn is_dynamic_fee(&self) -> bool; - - /// Returns the effective gas price for the given base fee. - fn effective_gas_price(&self, base_fee: Option) -> u128; - - /// This encodes the transaction _without_ the signature, and is only suitable for creating a - /// hash intended for signing. - fn encode_without_signature(&self, out: &mut dyn bytes::BufMut); } -#[cfg(not(feature = "arbitrary"))] -/// Helper trait that requires arbitrary implementation if the feature is enabled. -pub trait MaybeArbitrary {} +impl Transaction for T where + T: Send + + Sync + + Unpin + + Clone + + Default + + fmt::Debug + + Eq + + PartialEq + + Hash + + Serialize + + for<'de> Deserialize<'de> + + TransactionExt + + InMemorySize + + MaybeArbitrary +{ +} -#[cfg(feature = "arbitrary")] -/// Helper trait that requires arbitrary implementation if the feature is enabled. -pub trait MaybeArbitrary: for<'a> arbitrary::Arbitrary<'a> {} +/// Extension trait of [`alloy_consensus::Transaction`]. +pub trait TransactionExt: alloy_consensus::Transaction { + /// Transaction envelope type ID. + type Type: TxType; -/// Helper trait that unifies all behaviour required by transaction to support full node operations. -pub trait FullTransaction: Transaction + Compact {} + /// Heavy operation that return signature hash over rlp encoded transaction. + /// It is only for signature signing or signer recovery. + fn signature_hash(&self) -> B256; -impl FullTransaction for T where T: Transaction + Compact {} + /// Returns the transaction type. + fn tx_type(&self) -> Self::Type { + Self::Type::try_from(self.ty()).expect("should decode tx type id") + } +} diff --git a/crates/primitives-traits/src/transaction/signed.rs b/crates/primitives-traits/src/transaction/signed.rs index 02e908aec6cf..455a9886eb8f 100644 --- a/crates/primitives-traits/src/transaction/signed.rs +++ b/crates/primitives-traits/src/transaction/signed.rs @@ -2,17 +2,18 @@ use alloc::fmt; use core::hash::Hash; -use reth_codecs::Compact; -use alloy_consensus::Transaction; use alloy_eips::eip2718::{Decodable2718, Encodable2718}; -use alloy_primitives::{keccak256, Address, PrimitiveSignature as Signature, TxHash, B256}; +use alloy_primitives::{keccak256, Address, PrimitiveSignature, TxHash, B256}; +use reth_codecs::Compact; use revm_primitives::TxEnv; +use crate::{transaction::TransactionExt, FullTransaction, MaybeArbitrary, Transaction}; + /// Helper trait that unifies all behaviour required by block to support full node operations. -pub trait FullSignedTx: SignedTransaction + Compact {} +pub trait FullSignedTx: SignedTransaction + Compact {} -impl FullSignedTx for T where T: SignedTransaction + Compact {} +impl FullSignedTx for T where T: SignedTransaction + Compact {} /// A signed transaction. pub trait SignedTransaction: @@ -31,6 +32,8 @@ pub trait SignedTransaction: + alloy_rlp::Decodable + Encodable2718 + Decodable2718 + + TransactionExt + + MaybeArbitrary { /// Transaction type that is signed. type Transaction: Transaction; @@ -42,7 +45,7 @@ pub trait SignedTransaction: fn transaction(&self) -> &Self::Transaction; /// Returns reference to signature. - fn signature(&self) -> &Signature; + fn signature(&self) -> &PrimitiveSignature; /// Recover signer from signature and hash. /// @@ -65,8 +68,10 @@ pub trait SignedTransaction: /// Create a new signed transaction from a transaction and its signature. /// /// This will also calculate the transaction hash using its encoding. - fn from_transaction_and_signature(transaction: Self::Transaction, signature: Signature) - -> Self; + fn from_transaction_and_signature( + transaction: Self::Transaction, + signature: PrimitiveSignature, + ) -> Self; /// Calculate transaction hash, eip2728 transaction does not contain rlp header and start with /// tx type. @@ -77,3 +82,11 @@ pub trait SignedTransaction: /// Fills [`TxEnv`] with an [`Address`] and transaction. fn fill_tx_env(&self, tx_env: &mut TxEnv, sender: Address); } + +impl TransactionExt for T { + type Type = ::Type; + + fn signature_hash(&self) -> B256 { + self.transaction().signature_hash() + } +} diff --git a/crates/primitives-traits/src/tx_type.rs b/crates/primitives-traits/src/tx_type.rs index e0bf28d2a995..078d8ac947ba 100644 --- a/crates/primitives-traits/src/tx_type.rs +++ b/crates/primitives-traits/src/tx_type.rs @@ -1,8 +1,6 @@ use core::fmt; -use alloy_eips::eip2718::Eip2718Error; use alloy_primitives::{U64, U8}; -use alloy_rlp::{Decodable, Encodable}; use reth_codecs::Compact; /// Helper trait that unifies all behaviour required by transaction type ID to support full node @@ -26,11 +24,11 @@ pub trait TxType: + PartialEq + Into + Into - + TryFrom - + TryFrom + + TryFrom + + TryFrom + TryFrom - + Encodable - + Decodable + + alloy_rlp::Encodable + + alloy_rlp::Decodable { } @@ -48,10 +46,10 @@ impl TxType for T where + PartialEq + Into + Into - + TryFrom - + TryFrom + + TryFrom + + TryFrom + TryFrom - + Encodable - + Decodable + + alloy_rlp::Encodable + + alloy_rlp::Decodable { } diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 1a4c33c71809..34d04c94edcd 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -150,6 +150,7 @@ test-utils = [ "reth-chainspec/test-utils", "reth-codecs?/test-utils", "reth-trie-common/test-utils", + "arbitrary", ] serde-bincode-compat = [ "alloy-consensus/serde-bincode-compat", diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index f0caa2863aa6..d1a95b09be24 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -68,7 +68,7 @@ use tx_type::{ }; use alloc::vec::Vec; -use reth_primitives_traits::SignedTransaction; +use reth_primitives_traits::{transaction::TransactionExt, SignedTransaction}; use revm_primitives::{AuthorizationList, TxEnv}; /// Either a transaction hash or number. @@ -846,6 +846,22 @@ impl alloy_consensus::Transaction for Transaction { } } +impl TransactionExt for Transaction { + type Type = TxType; + + fn signature_hash(&self) -> B256 { + match self { + Self::Legacy(tx) => tx.signature_hash(), + Self::Eip2930(tx) => tx.signature_hash(), + Self::Eip1559(tx) => tx.signature_hash(), + Self::Eip4844(tx) => tx.signature_hash(), + Self::Eip7702(tx) => tx.signature_hash(), + #[cfg(feature = "optimism")] + _ => todo!("use op type for op"), + } + } +} + /// Signed transaction without its Hash. Used type for inserting into the DB. /// /// This can by converted to [`TransactionSigned`] by calling [`TransactionSignedNoHash::hash`]. diff --git a/crates/primitives/src/transaction/tx_type.rs b/crates/primitives/src/transaction/tx_type.rs index 0cfb2ff9d67e..46e370861133 100644 --- a/crates/primitives/src/transaction/tx_type.rs +++ b/crates/primitives/src/transaction/tx_type.rs @@ -4,6 +4,7 @@ use alloy_consensus::constants::{ }; use alloy_primitives::{U64, U8}; use alloy_rlp::{Decodable, Encodable}; +use derive_more::Display; use serde::{Deserialize, Serialize}; /// Identifier parameter for legacy transaction @@ -36,24 +37,42 @@ pub const DEPOSIT_TX_TYPE_ID: u8 = 126; /// /// Other required changes when adding a new type can be seen on [PR#3953](https://github.com/paradigmxyz/reth/pull/3953/files). #[derive( - Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize, Hash, + Clone, + Copy, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Default, + Serialize, + Deserialize, + Hash, + Display, )] #[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))] #[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))] +#[display("tx type: {_variant}")] pub enum TxType { /// Legacy transaction pre EIP-2929 #[default] + #[display("legacy (0)")] Legacy = 0_isize, /// AccessList transaction + #[display("eip2930 (1)")] Eip2930 = 1_isize, /// Transaction with Priority fee + #[display("eip1559 (2)")] Eip1559 = 2_isize, /// Shard Blob Transactions - EIP-4844 + #[display("eip4844 (3)")] Eip4844 = 3_isize, /// EOA Contract Code Transactions - EIP-7702 + #[display("eip7702 (4)")] Eip7702 = 4_isize, /// Optimism Deposit transaction. #[cfg(feature = "optimism")] + #[display("deposit (126)")] Deposit = 126_isize, }