Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(sdk): improve usability tx primitive traits #12437

Merged
merged 23 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion crates/primitives-traits/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<T> MaybeArbitrary for T where T: for<'a> arbitrary::Arbitrary<'a> {}
#[cfg(not(any(feature = "test-utils", feature = "arbitrary")))]
impl<T> MaybeArbitrary for T {}
72 changes: 38 additions & 34 deletions crates/primitives-traits/src/transaction/mod.rs
Original file line number Diff line number Diff line change
@@ -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<T> FullTransaction for T where T: Transaction + Compact {}

#[allow(dead_code)]
/// Abstraction of a transaction.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we still need this?
unclear why we need 3 traits now if this trait is now just a default

Copy link
Member Author

@emhane emhane Nov 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about moving the rlp encoding traits to FullTransaction...to make primitive traits more lightweight. I'm also good with removing the Full-traits for the data primitive traits and adding Compact as a super trait always. wdyt? @mattsse

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pub trait Transaction:
Send
Expand All @@ -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<u64>) -> 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<T> 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<T> 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")
}
}
29 changes: 21 additions & 8 deletions crates/primitives-traits/src/transaction/signed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Transaction: Compact> + Compact {}
pub trait FullSignedTx: SignedTransaction<Transaction: FullTransaction> + Compact {}

impl<T> FullSignedTx for T where T: SignedTransaction<Transaction: Compact> + Compact {}
impl<T> FullSignedTx for T where T: SignedTransaction<Transaction: FullTransaction> + Compact {}

/// A signed transaction.
pub trait SignedTransaction:
Expand All @@ -31,6 +32,8 @@ pub trait SignedTransaction:
+ alloy_rlp::Decodable
+ Encodable2718
+ Decodable2718
+ TransactionExt
+ MaybeArbitrary
{
/// Transaction type that is signed.
type Transaction: Transaction;
Expand All @@ -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.
///
Expand All @@ -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.
Expand All @@ -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<T: SignedTransaction> TransactionExt for T {
type Type = <T::Transaction as TransactionExt>::Type;

fn signature_hash(&self) -> B256 {
self.transaction().signature_hash()
}
Comment on lines +89 to +91
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo we can add SigneableTransaction as super trait like I did initially, since all the tx types we now import from alloy, already impl this trait @mattsse

}
18 changes: 8 additions & 10 deletions crates/primitives-traits/src/tx_type.rs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -26,11 +24,11 @@ pub trait TxType:
+ PartialEq<u8>
+ Into<u8>
+ Into<U8>
+ TryFrom<u8, Error = Eip2718Error>
+ TryFrom<u64>
+ TryFrom<u8, Error: fmt::Debug>
+ TryFrom<u64, Error: fmt::Debug>
+ TryFrom<U64>
+ Encodable
+ Decodable
+ alloy_rlp::Encodable
+ alloy_rlp::Decodable
{
}

Expand All @@ -48,10 +46,10 @@ impl<T> TxType for T where
+ PartialEq<u8>
+ Into<u8>
+ Into<U8>
+ TryFrom<u8, Error = Eip2718Error>
+ TryFrom<u64>
+ TryFrom<u8, Error: fmt::Debug>
+ TryFrom<u64, Error: fmt::Debug>
+ TryFrom<U64>
+ Encodable
+ Decodable
+ alloy_rlp::Encodable
+ alloy_rlp::Decodable
{
}
1 change: 1 addition & 0 deletions crates/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
18 changes: 17 additions & 1 deletion crates/primitives/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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`].
Expand Down
21 changes: 20 additions & 1 deletion crates/primitives/src/transaction/tx_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
}

Expand Down
Loading