chore(sdk): define OpTransactionSigned (#11433)

This commit is contained in:
Emilia Hane
2024-12-03 00:47:46 -06:00
committed by GitHub
parent 9ed9fa241d
commit ea82cbdc60
13 changed files with 572 additions and 29 deletions

6
Cargo.lock generated
View File

@ -8464,14 +8464,20 @@ dependencies = [
"alloy-consensus",
"alloy-eips",
"alloy-primitives",
"alloy-rlp",
"arbitrary",
"bytes",
"derive_more 1.0.0",
"op-alloy-consensus",
"proptest",
"proptest-arbitrary-interop",
"rand 0.8.5",
"reth-codecs",
"reth-primitives",
"reth-primitives-traits",
"revm-primitives",
"rstest",
"secp256k1",
"serde",
]

View File

@ -44,7 +44,8 @@ optimism = [
"reth-optimism-evm/optimism",
"reth-optimism-payload-builder/optimism",
"reth-optimism-rpc/optimism",
"reth-provider/optimism"
"reth-provider/optimism",
"reth-optimism-primitives/op",
]
dev = [

View File

@ -95,6 +95,7 @@ optimism = [
"reth-execution-types/optimism",
"reth-db/optimism",
"reth-db-api/optimism",
"reth-optimism-primitives/op",
"reth-downloaders/optimism"
]
asm-keccak = [

View File

@ -64,6 +64,7 @@ std = [
"alloy-primitives/std",
"revm-primitives/std",
"revm/std",
"reth-optimism-primitives/std",
"reth-ethereum-forks/std",
"derive_more/std",
"reth-optimism-forks/std"
@ -73,5 +74,6 @@ optimism = [
"reth-execution-types/optimism",
"reth-optimism-consensus/optimism",
"revm/optimism",
"revm-primitives/optimism"
"revm-primitives/optimism",
"reth-optimism-primitives/op",
]

View File

@ -41,7 +41,7 @@ reth-optimism-rpc.workspace = true
reth-optimism-chainspec.workspace = true
reth-optimism-consensus.workspace = true
reth-optimism-forks.workspace = true
reth-optimism-primitives.workspace = true
reth-optimism-primitives = { workspace = true, features = ["serde"] }
# revm with required optimism features
revm = { workspace = true, features = ["secp256k1", "blst", "c-kzg"] }
@ -96,7 +96,8 @@ optimism = [
"reth-optimism-consensus/optimism",
"reth-db/optimism",
"reth-optimism-node/optimism",
"reth-node-core/optimism"
"reth-node-core/optimism",
"reth-optimism-primitives/op",
]
asm-keccak = [
"reth-primitives/asm-keccak",

View File

@ -20,45 +20,60 @@ reth-codecs = { workspace = true, optional = true, features = ["op"] }
# ethereum
alloy-primitives.workspace = true
alloy-consensus.workspace = true
alloy-rlp.workspace = true
alloy-eips.workspace = true
revm-primitives.workspace = true
secp256k1 = { workspace = true, optional = true }
# op
op-alloy-consensus.workspace = true
# codec
bytes.workspace = true
bytes = { workspace = true, optional = true }
serde = { workspace = true, optional = true }
# misc
derive_more.workspace = true
derive_more = { workspace = true, features = ["deref", "from", "into", "constructor"] }
rand = { workspace = true, optional = true }
# test
arbitrary = { workspace = true, features = ["derive"], optional = true }
proptest = { workspace = true, optional = true }
[dev-dependencies]
proptest-arbitrary-interop.workspace = true
reth-codecs = { workspace = true, features = ["test-utils", "op"] }
rstest.workspace = true
arbitrary.workspace = true
proptest.workspace = true
[features]
default = ["std", "reth-codec"]
default = ["std"]
std = [
"reth-primitives-traits/std",
"reth-primitives/std",
"reth-codecs/std",
"reth-codecs?/std",
"alloy-consensus/std",
"alloy-eips/std",
"alloy-primitives/std",
"serde/std",
"bytes/std",
"derive_more/std"
"serde?/std",
"bytes?/std",
"derive_more/std",
"revm-primitives/std",
"secp256k1?/std",
"alloy-rlp/std",
]
reth-codec = [
"dep:reth-codecs",
"std",
"rand",
"dep:proptest",
"dep:arbitrary",
"reth-primitives/reth-codec",
"reth-primitives-traits/reth-codec",
"reth-codecs?/op",
"reth-primitives/reth-codec"
"reth-primitives/reth-codec",
"dep:bytes",
]
serde = [
"dep:serde",
@ -66,12 +81,16 @@ serde = [
"alloy-primitives/serde",
"alloy-consensus/serde",
"alloy-eips/serde",
"bytes/serde",
"bytes?/serde",
"reth-codecs?/serde",
"op-alloy-consensus/serde",
"rand?/serde",
"revm-primitives/serde",
"secp256k1?/serde",
]
arbitrary = [
"dep:arbitrary",
"dep:secp256k1",
"reth-primitives-traits/arbitrary",
"reth-primitives/arbitrary",
"reth-codecs?/arbitrary",
@ -79,4 +98,9 @@ arbitrary = [
"alloy-consensus/arbitrary",
"alloy-eips/arbitrary",
"alloy-primitives/arbitrary",
"revm-primitives/arbitrary",
"rand",
]
op = [
"revm-primitives/optimism",
]

View File

@ -6,17 +6,20 @@
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
// The `optimism` feature must be enabled to use this crate.
#![cfg(feature = "op")]
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
pub mod bedrock;
pub mod transaction;
use reth_primitives::EthPrimitives;
pub use transaction::{tx_type::OpTxType, OpTransaction};
pub use transaction::{signed::OpTransactionSigned, tx_type::OpTxType, OpTransaction};
/// Optimism primitive types.
pub type OpPrimitives = EthPrimitives;
pub type OpPrimitives = reth_primitives::EthPrimitives;
// TODO: once we are ready for separating primitive types, introduce a separate `NodePrimitives`
// implementation used exclusively by legacy engine.

View File

@ -1,14 +1,21 @@
//! Wrapper of [`OpTypedTransaction`], that implements reth database encoding [`Compact`].
pub mod signed;
pub mod tx_type;
use alloy_primitives::{bytes, Bytes, TxKind, Uint, B256};
use alloy_consensus::{constants::EIP7702_TX_TYPE_ID, TxLegacy};
#[cfg(any(test, feature = "reth-codec"))]
use alloy_consensus::constants::EIP7702_TX_TYPE_ID;
use alloy_consensus::{SignableTransaction, TxLegacy};
use alloy_eips::{eip2930::AccessList, eip7702::SignedAuthorization};
use derive_more::{Deref, From};
use op_alloy_consensus::{OpTypedTransaction, DEPOSIT_TX_TYPE_ID};
use derive_more::{Constructor, Deref, From};
use op_alloy_consensus::OpTypedTransaction;
#[cfg(any(test, feature = "reth-codec"))]
use op_alloy_consensus::DEPOSIT_TX_TYPE_ID;
#[cfg(any(test, feature = "reth-codec"))]
use reth_codecs::Compact;
#[cfg(any(test, feature = "reth-codec"))]
use reth_primitives::transaction::{
COMPACT_EXTENDED_IDENTIFIER_FLAG, COMPACT_IDENTIFIER_EIP1559, COMPACT_IDENTIFIER_EIP2930,
COMPACT_IDENTIFIER_LEGACY,
@ -17,16 +24,31 @@ use reth_primitives_traits::InMemorySize;
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Deref, Hash, From)]
#[derive(Debug, Clone, PartialEq, Eq, Deref, Hash, From, Constructor)]
/// Optimistic transaction.
pub struct OpTransaction(OpTypedTransaction);
impl OpTransaction {
/// This encodes the transaction _without_ the signature, and is only suitable for creating a
/// hash intended for signing.
pub fn encode_for_signing(&self, out: &mut dyn bytes::BufMut) {
match self.deref() {
OpTypedTransaction::Legacy(tx) => tx.encode_for_signing(out),
OpTypedTransaction::Eip2930(tx) => tx.encode_for_signing(out),
OpTypedTransaction::Eip1559(tx) => tx.encode_for_signing(out),
OpTypedTransaction::Eip7702(tx) => tx.encode_for_signing(out),
OpTypedTransaction::Deposit(_) => {}
}
}
}
impl Default for OpTransaction {
fn default() -> Self {
Self(OpTypedTransaction::Legacy(TxLegacy::default()))
}
}
#[cfg(any(test, feature = "reth-codec"))]
impl Compact for OpTransaction {
fn to_compact<B>(&self, out: &mut B) -> usize
where

View File

@ -0,0 +1,479 @@
//! A signed Optimism transaction.
use alloc::vec::Vec;
use core::{
hash::{Hash, Hasher},
mem,
};
#[cfg(feature = "std")]
use std::sync::OnceLock;
use alloy_consensus::{
transaction::RlpEcdsaTx, SignableTransaction, Transaction, TxEip1559, TxEip2930, TxEip7702,
};
use alloy_eips::{
eip2718::{Decodable2718, Eip2718Error, Eip2718Result, Encodable2718},
eip2930::AccessList,
eip7702::SignedAuthorization,
};
use alloy_primitives::{
keccak256, Address, Bytes, PrimitiveSignature as Signature, TxHash, TxKind, Uint, B256, U256,
};
use alloy_rlp::Header;
use derive_more::{AsRef, Deref};
#[cfg(not(feature = "std"))]
use once_cell::sync::OnceCell as OnceLock;
use op_alloy_consensus::{OpTypedTransaction, TxDeposit};
#[cfg(any(test, feature = "reth-codec"))]
use proptest as _;
use reth_primitives::{
transaction::{recover_signer, recover_signer_unchecked},
TransactionSigned,
};
use reth_primitives_traits::{FillTxEnv, InMemorySize, SignedTransaction};
use revm_primitives::{AuthorizationList, OptimismFields, TxEnv};
use crate::{OpTransaction, OpTxType};
/// Signed transaction.
#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(rlp))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Eq, AsRef, Deref)]
pub struct OpTransactionSigned {
/// Transaction hash
#[serde(skip)]
pub hash: OnceLock<TxHash>,
/// The transaction signature values
pub signature: Signature,
/// Raw transaction info
#[deref]
#[as_ref]
pub transaction: OpTransaction,
}
impl OpTransactionSigned {
/// Calculates hash of given transaction and signature and returns new instance.
pub fn new(transaction: OpTypedTransaction, signature: Signature) -> Self {
let signed_tx = Self::new_unhashed(transaction, signature);
if !matches!(signed_tx.tx_type(), OpTxType::Deposit) {
signed_tx.hash.get_or_init(|| signed_tx.recalculate_hash());
}
signed_tx
}
/// Creates a new signed transaction from the given transaction and signature without the hash.
///
/// Note: this only calculates the hash on the first [`TransactionSigned::hash`] call.
pub fn new_unhashed(transaction: OpTypedTransaction, signature: Signature) -> Self {
Self { hash: Default::default(), signature, transaction: OpTransaction::new(transaction) }
}
}
impl SignedTransaction for OpTransactionSigned {
type Type = OpTxType;
fn tx_hash(&self) -> &TxHash {
self.hash.get_or_init(|| self.recalculate_hash())
}
fn signature(&self) -> &Signature {
&self.signature
}
fn recover_signer(&self) -> Option<Address> {
// Optimism's Deposit transaction does not have a signature. Directly return the
// `from` address.
if let OpTypedTransaction::Deposit(TxDeposit { from, .. }) = *self.transaction {
return Some(from)
}
let Self { transaction, signature, .. } = self;
let signature_hash = signature_hash(transaction);
recover_signer(signature, signature_hash)
}
fn recover_signer_unchecked(&self) -> Option<Address> {
// Optimism's Deposit transaction does not have a signature. Directly return the
// `from` address.
if let OpTypedTransaction::Deposit(TxDeposit { from, .. }) = *self.transaction {
return Some(from)
}
let Self { transaction, signature, .. } = self;
let signature_hash = signature_hash(transaction);
recover_signer_unchecked(signature, signature_hash)
}
fn recalculate_hash(&self) -> B256 {
keccak256(self.encoded_2718())
}
fn recover_signer_unchecked_with_buf(&self, buf: &mut Vec<u8>) -> Option<Address> {
// Optimism's Deposit transaction does not have a signature. Directly return the
// `from` address.
if let OpTypedTransaction::Deposit(TxDeposit { from, .. }) = *self.transaction {
return Some(from)
}
self.encode_for_signing(buf);
let signature_hash = keccak256(buf);
recover_signer_unchecked(&self.signature, signature_hash)
}
}
impl FillTxEnv for OpTransactionSigned {
fn fill_tx_env(&self, tx_env: &mut TxEnv, sender: Address) {
let envelope = self.encoded_2718();
tx_env.caller = sender;
match self.transaction.deref() {
OpTypedTransaction::Legacy(tx) => {
tx_env.gas_limit = tx.gas_limit;
tx_env.gas_price = U256::from(tx.gas_price);
tx_env.gas_priority_fee = None;
tx_env.transact_to = tx.to;
tx_env.value = tx.value;
tx_env.data = tx.input.clone();
tx_env.chain_id = tx.chain_id;
tx_env.nonce = Some(tx.nonce);
tx_env.access_list.clear();
tx_env.blob_hashes.clear();
tx_env.max_fee_per_blob_gas.take();
tx_env.authorization_list = None;
}
OpTypedTransaction::Eip2930(tx) => {
tx_env.gas_limit = tx.gas_limit;
tx_env.gas_price = U256::from(tx.gas_price);
tx_env.gas_priority_fee = None;
tx_env.transact_to = tx.to;
tx_env.value = tx.value;
tx_env.data = tx.input.clone();
tx_env.chain_id = Some(tx.chain_id);
tx_env.nonce = Some(tx.nonce);
tx_env.access_list.clone_from(&tx.access_list.0);
tx_env.blob_hashes.clear();
tx_env.max_fee_per_blob_gas.take();
tx_env.authorization_list = None;
}
OpTypedTransaction::Eip1559(tx) => {
tx_env.gas_limit = tx.gas_limit;
tx_env.gas_price = U256::from(tx.max_fee_per_gas);
tx_env.gas_priority_fee = Some(U256::from(tx.max_priority_fee_per_gas));
tx_env.transact_to = tx.to;
tx_env.value = tx.value;
tx_env.data = tx.input.clone();
tx_env.chain_id = Some(tx.chain_id);
tx_env.nonce = Some(tx.nonce);
tx_env.access_list.clone_from(&tx.access_list.0);
tx_env.blob_hashes.clear();
tx_env.max_fee_per_blob_gas.take();
tx_env.authorization_list = None;
}
OpTypedTransaction::Eip7702(tx) => {
tx_env.gas_limit = tx.gas_limit;
tx_env.gas_price = U256::from(tx.max_fee_per_gas);
tx_env.gas_priority_fee = Some(U256::from(tx.max_priority_fee_per_gas));
tx_env.transact_to = tx.to.into();
tx_env.value = tx.value;
tx_env.data = tx.input.clone();
tx_env.chain_id = Some(tx.chain_id);
tx_env.nonce = Some(tx.nonce);
tx_env.access_list.clone_from(&tx.access_list.0);
tx_env.blob_hashes.clear();
tx_env.max_fee_per_blob_gas.take();
tx_env.authorization_list =
Some(AuthorizationList::Signed(tx.authorization_list.clone()));
}
OpTypedTransaction::Deposit(tx) => {
tx_env.access_list.clear();
tx_env.gas_limit = tx.gas_limit;
tx_env.gas_price = U256::ZERO;
tx_env.gas_priority_fee = None;
tx_env.transact_to = tx.to;
tx_env.value = tx.value;
tx_env.data = tx.input.clone();
tx_env.chain_id = None;
tx_env.nonce = None;
tx_env.authorization_list = None;
tx_env.optimism = OptimismFields {
source_hash: Some(tx.source_hash),
mint: tx.mint,
is_system_transaction: Some(tx.is_system_transaction),
enveloped_tx: Some(envelope.into()),
};
return
}
}
tx_env.optimism = OptimismFields {
source_hash: None,
mint: None,
is_system_transaction: Some(false),
enveloped_tx: Some(envelope.into()),
}
}
}
impl InMemorySize for OpTransactionSigned {
#[inline]
fn size(&self) -> usize {
mem::size_of::<TxHash>() + self.transaction.size() + mem::size_of::<Signature>()
}
}
impl alloy_rlp::Encodable for OpTransactionSigned {
/// See [`alloy_rlp::Encodable`] impl for [`TransactionSigned`].
fn encode(&self, out: &mut dyn alloy_rlp::bytes::BufMut) {
self.network_encode(out);
}
fn length(&self) -> usize {
let mut payload_length = self.encode_2718_len();
if !self.is_legacy() {
payload_length += Header { list: false, payload_length }.length();
}
payload_length
}
}
impl alloy_rlp::Decodable for OpTransactionSigned {
/// See [`alloy_rlp::Decodable`] impl for [`TransactionSigned`].
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
Self::network_decode(buf).map_err(Into::into)
}
}
impl Encodable2718 for OpTransactionSigned {
fn type_flag(&self) -> Option<u8> {
match self.tx_type() {
op_alloy_consensus::OpTxType::Legacy => None,
tx_type => Some(tx_type as u8),
}
}
fn encode_2718_len(&self) -> usize {
match self.transaction.deref() {
OpTypedTransaction::Legacy(legacy_tx) => {
legacy_tx.eip2718_encoded_length(&self.signature)
}
OpTypedTransaction::Eip2930(access_list_tx) => {
access_list_tx.eip2718_encoded_length(&self.signature)
}
OpTypedTransaction::Eip1559(dynamic_fee_tx) => {
dynamic_fee_tx.eip2718_encoded_length(&self.signature)
}
OpTypedTransaction::Eip7702(set_code_tx) => {
set_code_tx.eip2718_encoded_length(&self.signature)
}
OpTypedTransaction::Deposit(deposit_tx) => deposit_tx.eip2718_encoded_length(),
}
}
fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) {
let Self { transaction, signature, .. } = self;
match transaction.deref() {
OpTypedTransaction::Legacy(legacy_tx) => {
// do nothing w/ with_header
legacy_tx.eip2718_encode(signature, out)
}
OpTypedTransaction::Eip2930(access_list_tx) => {
access_list_tx.eip2718_encode(signature, out)
}
OpTypedTransaction::Eip1559(dynamic_fee_tx) => {
dynamic_fee_tx.eip2718_encode(signature, out)
}
OpTypedTransaction::Eip7702(set_code_tx) => set_code_tx.eip2718_encode(signature, out),
OpTypedTransaction::Deposit(deposit_tx) => deposit_tx.encode_2718(out),
}
}
}
impl Decodable2718 for OpTransactionSigned {
fn typed_decode(ty: u8, buf: &mut &[u8]) -> Eip2718Result<Self> {
match ty.try_into().map_err(|_| Eip2718Error::UnexpectedType(ty))? {
op_alloy_consensus::OpTxType::Legacy => Err(Eip2718Error::UnexpectedType(0)),
op_alloy_consensus::OpTxType::Eip2930 => {
let (tx, signature, hash) = TxEip2930::rlp_decode_signed(buf)?.into_parts();
let signed_tx = Self::new_unhashed(OpTypedTransaction::Eip2930(tx), signature);
signed_tx.hash.get_or_init(|| hash);
Ok(signed_tx)
}
op_alloy_consensus::OpTxType::Eip1559 => {
let (tx, signature, hash) = TxEip1559::rlp_decode_signed(buf)?.into_parts();
let signed_tx = Self::new_unhashed(OpTypedTransaction::Eip1559(tx), signature);
signed_tx.hash.get_or_init(|| hash);
Ok(signed_tx)
}
op_alloy_consensus::OpTxType::Eip7702 => {
let (tx, signature, hash) = TxEip7702::rlp_decode_signed(buf)?.into_parts();
let signed_tx = Self::new_unhashed(OpTypedTransaction::Eip7702(tx), signature);
signed_tx.hash.get_or_init(|| hash);
Ok(signed_tx)
}
op_alloy_consensus::OpTxType::Deposit => Ok(Self::new_unhashed(
OpTypedTransaction::Deposit(TxDeposit::rlp_decode(buf)?),
TxDeposit::signature(),
)),
}
}
fn fallback_decode(buf: &mut &[u8]) -> Eip2718Result<Self> {
let (transaction, hash, signature) =
TransactionSigned::decode_rlp_legacy_transaction_tuple(buf)?;
let signed_tx = Self::new_unhashed(OpTypedTransaction::Legacy(transaction), signature);
signed_tx.hash.get_or_init(|| hash);
Ok(signed_tx)
}
}
impl Transaction for OpTransactionSigned {
fn chain_id(&self) -> Option<u64> {
self.deref().chain_id()
}
fn nonce(&self) -> u64 {
self.deref().nonce()
}
fn gas_limit(&self) -> u64 {
self.deref().gas_limit()
}
fn gas_price(&self) -> Option<u128> {
self.deref().gas_price()
}
fn max_fee_per_gas(&self) -> u128 {
self.deref().max_fee_per_gas()
}
fn max_priority_fee_per_gas(&self) -> Option<u128> {
self.deref().max_priority_fee_per_gas()
}
fn max_fee_per_blob_gas(&self) -> Option<u128> {
self.deref().max_fee_per_blob_gas()
}
fn priority_fee_or_price(&self) -> u128 {
self.deref().priority_fee_or_price()
}
fn kind(&self) -> TxKind {
self.deref().kind()
}
fn is_create(&self) -> bool {
self.deref().is_create()
}
fn value(&self) -> Uint<256, 4> {
self.deref().value()
}
fn input(&self) -> &Bytes {
self.deref().input()
}
fn ty(&self) -> u8 {
self.deref().ty()
}
fn access_list(&self) -> Option<&AccessList> {
self.deref().access_list()
}
fn blob_versioned_hashes(&self) -> Option<&[B256]> {
self.deref().blob_versioned_hashes()
}
fn authorization_list(&self) -> Option<&[SignedAuthorization]> {
self.deref().authorization_list()
}
fn is_dynamic_fee(&self) -> bool {
self.deref().is_dynamic_fee()
}
fn effective_gas_price(&self, base_fee: Option<u64>) -> u128 {
self.deref().effective_gas_price(base_fee)
}
fn effective_tip_per_gas(&self, base_fee: u64) -> Option<u128> {
self.deref().effective_tip_per_gas(base_fee)
}
}
impl Default for OpTransactionSigned {
fn default() -> Self {
Self {
hash: Default::default(),
signature: Signature::test_signature(),
transaction: OpTransaction::new(OpTypedTransaction::Legacy(Default::default())),
}
}
}
impl PartialEq for OpTransactionSigned {
fn eq(&self, other: &Self) -> bool {
self.signature == other.signature &&
self.transaction == other.transaction &&
self.tx_hash() == other.tx_hash()
}
}
impl Hash for OpTransactionSigned {
fn hash<H: Hasher>(&self, state: &mut H) {
self.signature.hash(state);
self.transaction.hash(state);
}
}
#[cfg(any(test, feature = "arbitrary"))]
impl<'a> arbitrary::Arbitrary<'a> for OpTransactionSigned {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
#[allow(unused_mut)]
let mut transaction = OpTypedTransaction::arbitrary(u)?;
let secp = secp256k1::Secp256k1::new();
let key_pair = secp256k1::Keypair::new(&secp, &mut rand::thread_rng());
let signature = reth_primitives::transaction::util::secp256k1::sign_message(
B256::from_slice(&key_pair.secret_bytes()[..]),
signature_hash(&transaction),
)
.unwrap();
// Both `Some(0)` and `None` values are encoded as empty string byte. This introduces
// ambiguity in roundtrip tests. Patch the mint value of deposit transaction here, so that
// it's `None` if zero.
if let OpTypedTransaction::Deposit(ref mut tx_deposit) = transaction {
if tx_deposit.mint == Some(0) {
tx_deposit.mint = None;
}
}
let signature = if is_deposit(&transaction) { TxDeposit::signature() } else { signature };
Ok(Self::new(transaction, signature))
}
}
/// Calculates the signing hash for the transaction.
pub fn signature_hash(tx: &OpTypedTransaction) -> B256 {
match tx {
OpTypedTransaction::Legacy(tx) => tx.signature_hash(),
OpTypedTransaction::Eip2930(tx) => tx.signature_hash(),
OpTypedTransaction::Eip1559(tx) => tx.signature_hash(),
OpTypedTransaction::Eip7702(tx) => tx.signature_hash(),
OpTypedTransaction::Deposit(_) => B256::ZERO,
}
}
/// Returns `true` if transaction is deposit transaction.
pub const fn is_deposit(tx: &OpTypedTransaction) -> bool {
matches!(tx, OpTypedTransaction::Deposit(_))
}

View File

@ -72,5 +72,6 @@ optimism = [
"reth-provider/optimism",
"revm/optimism",
"reth-optimism-consensus/optimism",
"reth-optimism-payload-builder/optimism"
"reth-optimism-payload-builder/optimism",
"reth-optimism-primitives/op",
]

View File

@ -42,6 +42,11 @@ pub use sidecar::BlobTransaction;
pub use signature::{recover_signer, recover_signer_unchecked};
pub use tx_type::TxType;
/// Handling transaction signature operations, including signature recovery,
/// applying chain IDs, and EIP-2 validation.
pub mod signature;
pub mod util;
pub(crate) mod access_list;
mod compat;
mod error;
@ -50,12 +55,6 @@ mod pooled;
mod sidecar;
mod tx_type;
/// Handling transaction signature operations, including signature recovery,
/// applying chain IDs, and EIP-2 validation.
pub mod signature;
pub(crate) mod util;
#[cfg(any(test, feature = "reth-codec"))]
pub use tx_type::{
COMPACT_EXTENDED_IDENTIFIER_FLAG, COMPACT_IDENTIFIER_EIP1559, COMPACT_IDENTIFIER_EIP2930,
@ -1178,7 +1177,7 @@ impl TransactionSigned {
///
/// Refer to the docs for [`Self::decode_rlp_legacy_transaction`] for details on the exact
/// format expected.
pub(crate) fn decode_rlp_legacy_transaction_tuple(
pub fn decode_rlp_legacy_transaction_tuple(
data: &mut &[u8],
) -> alloy_rlp::Result<(TxLegacy, TxHash, Signature)> {
// keep this around, so we can use it to calculate the hash

View File

@ -1,7 +1,10 @@
//! Utility functions for signature.
use alloy_primitives::{Address, PrimitiveSignature as Signature};
/// Secp256k1 utility functions.
#[cfg(feature = "secp256k1")]
pub(crate) mod secp256k1 {
pub mod secp256k1 {
pub use super::impl_secp256k1::*;
}

View File

@ -96,6 +96,7 @@ optimism = [
"reth-db/optimism",
"reth-db-api/optimism",
"revm/optimism",
"reth-optimism-primitives/op",
]
serde = [
"dashmap/serde",