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

This commit is contained in:
Emilia Hane
2024-11-13 14:35:59 +01:00
committed by GitHub
parent 9313737dbb
commit 9e77d916e1
7 changed files with 124 additions and 61 deletions

View File

@ -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<T> MaybeArbitrary for T where T: for<'a> arbitrary::Arbitrary<'a> {}
#[cfg(not(any(feature = "test-utils", feature = "arbitrary")))]
impl<T> MaybeArbitrary for T {}

View File

@ -1,17 +1,20 @@
//! Transaction abstraction
use core::{fmt, hash::Hash};
use alloy_primitives::{TxKind, B256};
use reth_codecs::Compact;
use serde::{Deserialize, Serialize};
use crate::InMemorySize;
pub mod signed;
#[allow(dead_code)]
use core::{fmt, hash::Hash};
use alloy_primitives::B256;
use reth_codecs::Compact;
use serde::{Deserialize, Serialize};
use crate::{InMemorySize, MaybeArbitrary, TxType};
/// 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 {}
/// 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
{
}
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
{
}
/// Extension trait of [`alloy_consensus::Transaction`].
pub trait TransactionExt: alloy_consensus::Transaction {
/// Transaction envelope type ID.
type Type: TxType;
/// 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);
/// Returns the transaction type.
fn tx_type(&self) -> Self::Type {
Self::Type::try_from(self.ty()).expect("should decode tx type id")
}
}
#[cfg(not(feature = "arbitrary"))]
/// Helper trait that requires arbitrary implementation if the feature is enabled.
pub trait MaybeArbitrary {}
#[cfg(feature = "arbitrary")]
/// Helper trait that requires arbitrary implementation if the feature is enabled.
pub trait MaybeArbitrary: for<'a> arbitrary::Arbitrary<'a> {}
/// 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 {}

View File

@ -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;
/// Helper trait that unifies all behaviour required by block to support full node operations.
pub trait FullSignedTx: SignedTransaction<Transaction: Compact> + Compact {}
use crate::{transaction::TransactionExt, FullTransaction, MaybeArbitrary, Transaction};
impl<T> FullSignedTx for T where T: SignedTransaction<Transaction: Compact> + Compact {}
/// Helper trait that unifies all behaviour required by block to support full node operations.
pub trait FullSignedTx: SignedTransaction<Transaction: FullTransaction> + Compact {}
impl<T> FullSignedTx for T where T: SignedTransaction<Transaction: FullTransaction> + 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<T: SignedTransaction> TransactionExt for T {
type Type = <T::Transaction as TransactionExt>::Type;
fn signature_hash(&self) -> B256 {
self.transaction().signature_hash()
}
}

View File

@ -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<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
{
}
@ -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
{
}

View File

@ -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",

View File

@ -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`].

View File

@ -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,
}