feat: use reth-ethereum-primitives (#13830)

This commit is contained in:
Arsenii Kulikov
2025-01-17 04:22:21 +04:00
committed by GitHub
parent 7e972ea23d
commit 8efe441cc0
67 changed files with 941 additions and 3025 deletions

25
Cargo.lock generated
View File

@ -3050,6 +3050,7 @@ dependencies = [
"reth-node-ethereum",
"reth-node-types",
"reth-primitives",
"reth-primitives-traits",
"reth-provider",
]
@ -5453,7 +5454,6 @@ dependencies = [
"alloy-primitives",
"alloy-rpc-types-eth",
"alloy-serde",
"arbitrary",
"derive_more",
"op-alloy-consensus",
"serde",
@ -7444,9 +7444,13 @@ version = "1.1.5"
dependencies = [
"alloy-consensus",
"alloy-eips",
"alloy-network",
"alloy-primitives",
"alloy-rlp",
"alloy-rpc-types",
"alloy-serde",
"arbitrary",
"bincode",
"derive_more",
"modular-bitfield",
"once_cell",
@ -7455,7 +7459,9 @@ dependencies = [
"rand 0.8.5",
"reth-codecs",
"reth-primitives-traits",
"reth-testing-utils",
"reth-zstd-compressors",
"revm-primitives",
"secp256k1",
"serde",
"test-fuzz",
@ -8552,42 +8558,27 @@ dependencies = [
"alloy-consensus",
"alloy-eips",
"alloy-genesis",
"alloy-network",
"alloy-primitives",
"alloy-rlp",
"alloy-rpc-types",
"alloy-serde",
"alloy-trie",
"arbitrary",
"assert_matches",
"bincode",
"bytes",
"c-kzg",
"codspeed-criterion-compat",
"derive_more",
"modular-bitfield",
"once_cell",
"op-alloy-consensus",
"op-alloy-rpc-types",
"pprof",
"proptest",
"proptest-arbitrary-interop",
"rand 0.8.5",
"reth-chainspec",
"reth-codecs",
"reth-ethereum-forks",
"reth-ethereum-primitives",
"reth-primitives-traits",
"reth-static-file-types",
"reth-testing-utils",
"reth-trie-common",
"reth-zstd-compressors",
"revm-primitives",
"rstest",
"secp256k1",
"serde",
"serde_json",
"serde_with",
"test-fuzz",
]
[[package]]

View File

@ -96,7 +96,7 @@ min-info-logs = ["tracing/release_max_level_info"]
min-debug-logs = ["tracing/release_max_level_debug"]
min-trace-logs = ["tracing/release_max_level_trace"]
optimism = ["reth-primitives/optimism", "reth-node-core/optimism"]
optimism = ["reth-node-core/optimism"]
# no-op feature flag for switching between the `optimism` and default functionality in CI matrices
ethereum = []

View File

@ -24,8 +24,11 @@ use reth_execution_types::ExecutionOutcome;
use reth_fs_util as fs;
use reth_node_api::{BlockTy, EngineApiMessageVersion, PayloadBuilderAttributes};
use reth_node_ethereum::{consensus::EthBeaconConsensus, EthEvmConfig, EthExecutorProvider};
use reth_primitives::{EthPrimitives, SealedBlock, SealedHeader, Transaction, TransactionSigned};
use reth_primitives_traits::Block as _;
use reth_primitives::{
transaction::SignedTransactionIntoRecoveredExt, EthPrimitives, SealedBlock, SealedHeader,
Transaction, TransactionSigned,
};
use reth_primitives_traits::{Block as _, SignedTransaction};
use reth_provider::{
providers::{BlockchainProvider, ProviderNodeTypes},
BlockHashReader, BlockReader, BlockWriter, ChainSpecProvider, ProviderFactory,
@ -163,7 +166,7 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
for tx_bytes in &self.transactions {
debug!(target: "reth::cli", bytes = ?tx_bytes, "Decoding transaction");
let transaction = TransactionSigned::decode(&mut &Bytes::from_str(tx_bytes)?[..])?
.into_ecrecovered()
.try_ecrecovered()
.ok_or_else(|| eyre::eyre!("failed to recover tx"))?;
let encoded_length = match &transaction.transaction {
@ -183,7 +186,7 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
let encoded_length = pooled.encode_2718_len();
// insert the blob into the store
blob_store.insert(transaction.hash(), sidecar)?;
blob_store.insert(*transaction.tx_hash(), sidecar)?;
encoded_length
}

View File

@ -4,7 +4,9 @@ use crate::{
in_memory::ExecutedBlock, CanonStateNotification, CanonStateNotifications,
CanonStateSubscriptions,
};
use alloy_consensus::{Header, Transaction as _, TxEip1559, EMPTY_ROOT_HASH};
use alloy_consensus::{
Header, SignableTransaction, Transaction as _, TxEip1559, TxReceipt, EMPTY_ROOT_HASH,
};
use alloy_eips::{
eip1559::{ETHEREUM_BLOCK_GAS_LIMIT, INITIAL_BASE_FEE},
eip7685::Requests,
@ -17,6 +19,7 @@ use reth_chainspec::{ChainSpec, EthereumHardfork, MIN_TRANSACTION_GAS};
use reth_execution_types::{Chain, ExecutionOutcome};
use reth_primitives::{
proofs::{calculate_receipt_root, calculate_transaction_root, calculate_withdrawals_root},
transaction::SignedTransactionIntoRecoveredExt,
BlockBody, EthPrimitives, NodePrimitives, Receipt, Receipts, RecoveredBlock, RecoveredTx,
SealedBlock, SealedHeader, Transaction, TransactionSigned,
};
@ -131,7 +134,7 @@ impl<N: NodePrimitives> TestBlockBuilder<N> {
cumulative_gas_used: (idx as u64 + 1) * MIN_TRANSACTION_GAS,
..Default::default()
}
.with_bloom()
.into_with_bloom()
})
.collect::<Vec<_>>();

View File

@ -52,7 +52,6 @@ tracing.workspace = true
[features]
optimism = [
"reth-primitives/optimism",
"reth-provider/optimism",
"revm-primitives/optimism",
]

View File

@ -21,7 +21,7 @@ use reth_payload_validator::ExecutionPayloadValidator;
use reth_primitives::{
proofs, transaction::SignedTransactionIntoRecoveredExt, Block, BlockBody, Receipt, Receipts,
};
use reth_primitives_traits::block::Block as _;
use reth_primitives_traits::{block::Block as _, SignedTransaction};
use reth_provider::{BlockReader, ExecutionOutcome, ProviderError, StateProviderFactory};
use reth_revm::{
database::StateProviderDatabase,
@ -329,19 +329,19 @@ where
let exec_result = match evm.transact() {
Ok(result) => result,
error @ Err(EVMError::Transaction(_) | EVMError::Header(_)) => {
trace!(target: "engine::stream::reorg", hash = %tx.hash(), ?error, "Error executing transaction from next block");
trace!(target: "engine::stream::reorg", hash = %tx.tx_hash(), ?error, "Error executing transaction from next block");
continue
}
// Treat error as fatal
Err(error) => {
return Err(RethError::Execution(BlockExecutionError::Validation(
BlockValidationError::EVM { hash: tx.hash(), error: Box::new(error) },
BlockValidationError::EVM { hash: *tx.tx_hash(), error: Box::new(error) },
)))
}
};
evm.db_mut().commit(exec_result.state);
if let Some(blob_tx) = tx.transaction.as_eip4844() {
if let Some(blob_tx) = tx.as_eip4844() {
sum_blob_gas_used += blob_tx.blob_gas();
versioned_hashes.extend(blob_tx.blob_versioned_hashes.clone());
}

View File

@ -22,7 +22,7 @@ use reth_evm::{
ConfigureEvm, TxEnvOverrides,
};
use reth_primitives::{EthPrimitives, Receipt, RecoveredBlock};
use reth_primitives_traits::BlockBody;
use reth_primitives_traits::{BlockBody, SignedTransaction};
use reth_revm::db::State;
use revm_primitives::{
db::{Database, DatabaseCommit},

View File

@ -9,7 +9,7 @@
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#![allow(clippy::useless_let_if_seq)]
use alloy_consensus::{Header, EMPTY_OMMER_ROOT_HASH};
use alloy_consensus::{Header, Transaction, Typed2718, EMPTY_OMMER_ROOT_HASH};
use alloy_eips::{
eip4844::MAX_DATA_GAS_PER_BLOCK, eip6110, eip7685::Requests, eip7840::BlobParams,
merge::BEACON_NONCE,
@ -33,7 +33,7 @@ use reth_primitives::{
Block, BlockBody, EthereumHardforks, InvalidTransactionError, Receipt, RecoveredBlock,
TransactionSigned,
};
use reth_primitives_traits::Block as _;
use reth_primitives_traits::{Block as _, SignedTransaction};
use reth_revm::database::StateProviderDatabase;
use reth_storage_api::StateProviderFactory;
use reth_transaction_pool::{
@ -250,7 +250,7 @@ where
// There's only limited amount of blob space available per block, so we need to check if
// the EIP-4844 can still fit in the block
if let Some(blob_tx) = tx.transaction.as_eip4844() {
if let Some(blob_tx) = tx.as_eip4844() {
let tx_blob_gas = blob_tx.blob_gas();
if sum_blob_gas_used + tx_blob_gas > MAX_DATA_GAS_PER_BLOCK {
// we can't fit this _blob_ transaction into the block, so we mark it as
@ -306,7 +306,7 @@ where
evm.db_mut().commit(state);
// add to the total blob gas used if the transaction successfully executed
if let Some(blob_tx) = tx.transaction.as_eip4844() {
if let Some(blob_tx) = tx.as_eip4844() {
let tx_blob_gas = blob_tx.blob_gas();
sum_blob_gas_used += tx_blob_gas;
@ -332,9 +332,8 @@ where
}));
// update add to total fees
let miner_fee = tx
.effective_tip_per_gas(Some(base_fee))
.expect("fee is always valid; execution succeeded");
let miner_fee =
tx.effective_tip_per_gas(base_fee).expect("fee is always valid; execution succeeded");
total_fees += U256::from(miner_fee) * U256::from(gas_used);
// append sender and transaction to the respective lists
@ -419,7 +418,7 @@ where
// grab the blob sidecars from the executed txs
blob_sidecars = pool
.get_all_blobs_exact(
executed_txs.iter().filter(|tx| tx.is_eip4844()).map(|tx| tx.hash()).collect(),
executed_txs.iter().filter(|tx| tx.is_eip4844()).map(|tx| *tx.tx_hash()).collect(),
)
.map_err(PayloadBuilderError::other)?;

View File

@ -20,8 +20,12 @@ reth-zstd-compressors = { workspace = true, optional = true }
# ethereum
alloy-eips.workspace = true
alloy-primitives.workspace = true
alloy-network = { workspace = true, optional = true }
alloy-consensus = { workspace = true, features = ["serde"] }
alloy-serde = { workspace = true, optional = true }
alloy-rlp.workspace = true
alloy-rpc-types = { workspace = true, optional = true }
revm-primitives.workspace = true
# misc
arbitrary = { workspace = true, optional = true, features = ["derive"] }
@ -34,16 +38,20 @@ serde.workspace = true
[dev-dependencies]
arbitrary.workspace = true
bincode.workspace = true
proptest.workspace = true
proptest-arbitrary-interop.workspace = true
rand.workspace = true
reth-codecs.workspace = true
reth-codecs = { workspace = true, features = ["test-utils"] }
reth-testing-utils.workspace = true
reth-zstd-compressors.workspace = true
secp256k1.workspace = true
secp256k1 = { workspace = true, features = ["rand"] }
test-fuzz.workspace = true
alloy-consensus = { workspace = true, features = ["serde", "arbitrary"] }
[features]
default = ["std"]
alloy-compat = ["dep:alloy-network", "dep:alloy-serde", "dep:alloy-rpc-types"]
std = [
"alloy-consensus/std",
"alloy-primitives/std",
@ -54,7 +62,9 @@ std = [
"alloy-eips/std",
"derive_more/std",
"secp256k1?/std",
"once_cell/std"
"once_cell/std",
"revm-primitives/std",
"alloy-serde?/std"
]
reth-codec = [
"std",
@ -70,5 +80,13 @@ arbitrary = [
"alloy-primitives/arbitrary",
"reth-codecs?/arbitrary",
"reth-primitives-traits/arbitrary",
"alloy-eips/arbitrary"
"alloy-eips/arbitrary",
"revm-primitives/arbitrary",
"alloy-rpc-types?/arbitrary",
"alloy-serde?/arbitrary"
]
serde-bincode-compat = [
"alloy-consensus/serde-bincode-compat",
"alloy-eips/serde-bincode-compat",
"reth-primitives-traits/serde-bincode-compat"
]

View File

@ -0,0 +1,44 @@
//! Common conversions from alloy types.
use crate::{Transaction, TransactionSigned};
use alloc::string::ToString;
use alloy_consensus::TxEnvelope;
use alloy_network::{AnyRpcTransaction, AnyTxEnvelope};
use alloy_serde::WithOtherFields;
impl TryFrom<AnyRpcTransaction> for TransactionSigned {
type Error = alloy_rpc_types::ConversionError;
fn try_from(tx: AnyRpcTransaction) -> Result<Self, Self::Error> {
use alloy_rpc_types::ConversionError;
let WithOtherFields { inner: tx, other: _ } = tx;
#[allow(unreachable_patterns)]
let (transaction, signature, hash) = match tx.inner {
AnyTxEnvelope::Ethereum(TxEnvelope::Legacy(tx)) => {
let (tx, signature, hash) = tx.into_parts();
(Transaction::Legacy(tx), signature, hash)
}
AnyTxEnvelope::Ethereum(TxEnvelope::Eip2930(tx)) => {
let (tx, signature, hash) = tx.into_parts();
(Transaction::Eip2930(tx), signature, hash)
}
AnyTxEnvelope::Ethereum(TxEnvelope::Eip1559(tx)) => {
let (tx, signature, hash) = tx.into_parts();
(Transaction::Eip1559(tx), signature, hash)
}
AnyTxEnvelope::Ethereum(TxEnvelope::Eip4844(tx)) => {
let (tx, signature, hash) = tx.into_parts();
(Transaction::Eip4844(tx.into()), signature, hash)
}
AnyTxEnvelope::Ethereum(TxEnvelope::Eip7702(tx)) => {
let (tx, signature, hash) = tx.into_parts();
(Transaction::Eip7702(tx), signature, hash)
}
_ => return Err(ConversionError::Custom("unknown transaction type".to_string())),
};
Ok(Self { transaction, signature, hash: hash.into() })
}
}

View File

@ -16,3 +16,6 @@ pub use receipt::*;
mod transaction;
pub use transaction::*;
#[cfg(feature = "alloy-compat")]
mod alloy_compat;

View File

@ -184,3 +184,139 @@ impl InMemorySize for Receipt {
}
impl reth_primitives_traits::Receipt for Receipt {}
#[cfg(test)]
mod tests {
use super::*;
use alloy_eips::eip2718::Encodable2718;
use alloy_primitives::{address, b256, bytes, hex_literal::hex, Bytes};
use reth_codecs::Compact;
#[test]
fn test_decode_receipt() {
reth_codecs::test_utils::test_decode::<Receipt>(&hex!(
"c428b52ffd23fc42696156b10200f034792b6a94c3850215c2fef7aea361a0c31b79d9a32652eefc0d4e2e730036061cff7344b6fc6132b50cda0ed810a991ae58ef013150c12b2522533cb3b3a8b19b7786a8b5ff1d3cdc84225e22b02def168c8858df"
));
}
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
#[test]
fn encode_legacy_receipt() {
let expected = hex!("f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff");
let mut data = Vec::with_capacity(expected.length());
let receipt = ReceiptWithBloom {
receipt: Receipt {
tx_type: TxType::Legacy,
cumulative_gas_used: 0x1u64,
logs: vec![Log::new_unchecked(
address!("0000000000000000000000000000000000000011"),
vec![
b256!("000000000000000000000000000000000000000000000000000000000000dead"),
b256!("000000000000000000000000000000000000000000000000000000000000beef"),
],
bytes!("0100ff"),
)],
success: false,
},
logs_bloom: [0; 256].into(),
};
receipt.encode(&mut data);
// check that the rlp length equals the length of the expected rlp
assert_eq!(receipt.length(), expected.len());
assert_eq!(data, expected);
}
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
#[test]
fn decode_legacy_receipt() {
let data = hex!("f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff");
// EIP658Receipt
let expected = ReceiptWithBloom {
receipt: Receipt {
tx_type: TxType::Legacy,
cumulative_gas_used: 0x1u64,
logs: vec![Log::new_unchecked(
address!("0000000000000000000000000000000000000011"),
vec![
b256!("000000000000000000000000000000000000000000000000000000000000dead"),
b256!("000000000000000000000000000000000000000000000000000000000000beef"),
],
bytes!("0100ff"),
)],
success: false,
},
logs_bloom: [0; 256].into(),
};
let receipt = ReceiptWithBloom::decode(&mut &data[..]).unwrap();
assert_eq!(receipt, expected);
}
#[test]
fn gigantic_receipt() {
let receipt = Receipt {
cumulative_gas_used: 16747627,
success: true,
tx_type: TxType::Legacy,
logs: vec![
Log::new_unchecked(
address!("4bf56695415f725e43c3e04354b604bcfb6dfb6e"),
vec![b256!("c69dc3d7ebff79e41f525be431d5cd3cc08f80eaf0f7819054a726eeb7086eb9")],
Bytes::from(vec![1; 0xffffff]),
),
Log::new_unchecked(
address!("faca325c86bf9c2d5b413cd7b90b209be92229c2"),
vec![b256!("8cca58667b1e9ffa004720ac99a3d61a138181963b294d270d91c53d36402ae2")],
Bytes::from(vec![1; 0xffffff]),
),
],
};
let mut data = vec![];
receipt.to_compact(&mut data);
let (decoded, _) = Receipt::from_compact(&data[..], data.len());
assert_eq!(decoded, receipt);
}
#[test]
fn test_encode_2718_length() {
let receipt = ReceiptWithBloom {
receipt: Receipt {
tx_type: TxType::Eip1559,
success: true,
cumulative_gas_used: 21000,
logs: vec![],
},
logs_bloom: Bloom::default(),
};
let encoded = receipt.encoded_2718();
assert_eq!(
encoded.len(),
receipt.encode_2718_len(),
"Encoded length should match the actual encoded data length"
);
// Test for legacy receipt as well
let legacy_receipt = ReceiptWithBloom {
receipt: Receipt {
tx_type: TxType::Legacy,
success: true,
cumulative_gas_used: 21000,
logs: vec![],
},
logs_bloom: Bloom::default(),
};
let legacy_encoded = legacy_receipt.encoded_2718();
assert_eq!(
legacy_encoded.len(),
legacy_receipt.encode_2718_len(),
"Encoded length for legacy receipt should match the actual encoded data length"
);
}
}

View File

@ -1,7 +1,8 @@
use alloc::vec::Vec;
use alloy_consensus::{
transaction::RlpEcdsaTx, SignableTransaction, Signed, TxEip1559, TxEip2930, TxEip4844,
TxEip7702, TxLegacy, TxType, Typed2718,
transaction::{PooledTransaction, RlpEcdsaTx},
BlobTransactionSidecar, SignableTransaction, Signed, TxEip1559, TxEip2930, TxEip4844,
TxEip4844WithSidecar, TxEip7702, TxLegacy, TxType, Typed2718, TypedTransaction,
};
use alloy_eips::{
eip2718::{Decodable2718, Eip2718Error, Eip2718Result, Encodable2718},
@ -18,8 +19,10 @@ use once_cell as _;
use once_cell::sync::OnceCell as OnceLock;
use reth_primitives_traits::{
crypto::secp256k1::{recover_signer, recover_signer_unchecked},
InMemorySize, SignedTransaction,
transaction::error::TransactionConversionError,
FillTxEnv, InMemorySize, SignedTransaction,
};
use revm_primitives::{AuthorizationList, TxEnv};
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use std::sync::OnceLock;
@ -101,6 +104,17 @@ impl Transaction {
Self::Eip7702(_) => TxType::Eip7702,
}
}
/// This sets the transaction's nonce.
pub fn set_nonce(&mut self, nonce: u64) {
match self {
Self::Legacy(tx) => tx.nonce = nonce,
Self::Eip2930(tx) => tx.nonce = nonce,
Self::Eip1559(tx) => tx.nonce = nonce,
Self::Eip4844(tx) => tx.nonce = nonce,
Self::Eip7702(tx) => tx.nonce = nonce,
}
}
}
impl Typed2718 for Transaction {
@ -253,6 +267,18 @@ impl reth_codecs::Compact for Transaction {
}
}
impl From<TypedTransaction> for Transaction {
fn from(value: TypedTransaction) -> Self {
match value {
TypedTransaction::Legacy(tx) => Self::Legacy(tx),
TypedTransaction::Eip2930(tx) => Self::Eip2930(tx),
TypedTransaction::Eip1559(tx) => Self::Eip1559(tx),
TypedTransaction::Eip4844(tx) => Self::Eip4844(tx.into()),
TypedTransaction::Eip7702(tx) => Self::Eip7702(tx),
}
}
}
/// Signed Ethereum transaction.
#[derive(Debug, Clone, Eq, Serialize, Deserialize, derive_more::AsRef, derive_more::Deref)]
#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(rlp))]
@ -269,6 +295,12 @@ pub struct TransactionSigned {
pub transaction: Transaction,
}
impl Default for TransactionSigned {
fn default() -> Self {
Self::new_unhashed(Transaction::Legacy(Default::default()), Signature::test_signature())
}
}
impl TransactionSigned {
fn recalculate_hash(&self) -> B256 {
keccak256(self.encoded_2718())
@ -291,12 +323,50 @@ impl PartialEq for TransactionSigned {
}
impl TransactionSigned {
/// Creates a new signed transaction from the given transaction, signature and hash.
pub fn new(transaction: Transaction, signature: Signature, hash: B256) -> Self {
Self { hash: hash.into(), signature, transaction }
}
/// 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: Transaction, signature: Signature) -> Self {
Self { hash: Default::default(), signature, transaction }
}
/// Converts from an EIP-4844 transaction to a [`PooledTransaction`] with the given sidecar.
///
/// Returns an `Err` containing the original `TransactionSigned` if the transaction is not
/// EIP-4844.
pub fn try_into_pooled_eip4844(
self,
sidecar: BlobTransactionSidecar,
) -> Result<PooledTransaction, Self> {
let hash = *self.tx_hash();
Ok(match self {
// If the transaction is an EIP-4844 transaction...
Self { transaction: Transaction::Eip4844(tx), signature, .. } => {
// Construct a pooled eip488 tx with the provided sidecar.
PooledTransaction::Eip4844(Signed::new_unchecked(
TxEip4844WithSidecar { tx, sidecar },
signature,
hash,
))
}
// If the transaction is not EIP-4844, return an error with the original
// transaction.
_ => return Err(self),
})
}
/// Returns the [`TxEip4844`] if the transaction is an EIP-4844 transaction.
pub const fn as_eip4844(&self) -> Option<&TxEip4844> {
match &self.transaction {
Transaction::Eip4844(tx) => Some(tx),
_ => None,
}
}
}
impl Typed2718 for TransactionSigned {
@ -561,6 +631,85 @@ impl reth_codecs::Compact for TransactionSigned {
}
}
impl FillTxEnv for TransactionSigned {
fn fill_tx_env(&self, tx_env: &mut TxEnv, sender: Address) {
tx_env.caller = sender;
match self.as_ref() {
Transaction::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;
}
Transaction::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;
}
Transaction::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;
}
Transaction::Eip4844(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 = TxKind::Call(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.clone_from(&tx.blob_versioned_hashes);
tx_env.max_fee_per_blob_gas = Some(U256::from(tx.max_fee_per_blob_gas));
tx_env.authorization_list = None;
}
Transaction::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()));
}
}
}
}
impl SignedTransaction for TransactionSigned {
fn tx_hash(&self) -> &TxHash {
self.hash.get_or_init(|| self.recalculate_hash())
@ -582,6 +731,180 @@ impl SignedTransaction for TransactionSigned {
}
}
impl TryFrom<TransactionSigned> for PooledTransaction {
type Error = TransactionConversionError;
fn try_from(tx: TransactionSigned) -> Result<Self, Self::Error> {
let hash = *tx.tx_hash();
match tx {
TransactionSigned { transaction: Transaction::Legacy(tx), signature, .. } => {
Ok(Self::Legacy(Signed::new_unchecked(tx, signature, hash)))
}
TransactionSigned { transaction: Transaction::Eip2930(tx), signature, .. } => {
Ok(Self::Eip2930(Signed::new_unchecked(tx, signature, hash)))
}
TransactionSigned { transaction: Transaction::Eip1559(tx), signature, .. } => {
Ok(Self::Eip1559(Signed::new_unchecked(tx, signature, hash)))
}
TransactionSigned { transaction: Transaction::Eip7702(tx), signature, .. } => {
Ok(Self::Eip7702(Signed::new_unchecked(tx, signature, hash)))
}
// Not supported because missing blob sidecar
TransactionSigned { transaction: Transaction::Eip4844(_), .. } => {
Err(TransactionConversionError::UnsupportedForP2P)
}
}
}
}
impl<T> From<Signed<T>> for TransactionSigned
where
T: Into<Transaction>,
{
fn from(value: Signed<T>) -> Self {
let (tx, signature, hash) = value.into_parts();
Self { transaction: tx.into(), signature, hash: hash.into() }
}
}
impl From<PooledTransaction> for TransactionSigned {
fn from(value: PooledTransaction) -> Self {
match value {
PooledTransaction::Legacy(tx) => tx.into(),
PooledTransaction::Eip2930(tx) => tx.into(),
PooledTransaction::Eip1559(tx) => tx.into(),
PooledTransaction::Eip7702(tx) => tx.into(),
PooledTransaction::Eip4844(tx) => {
let (tx, signature, hash) = tx.into_parts();
Signed::new_unchecked(tx.tx, signature, hash).into()
}
}
}
}
/// Bincode-compatible transaction type serde implementations.
#[cfg(feature = "serde-bincode-compat")]
pub mod serde_bincode_compat {
use alloc::borrow::Cow;
use alloy_consensus::{
transaction::serde_bincode_compat::{TxEip1559, TxEip2930, TxEip7702, TxLegacy},
TxEip4844,
};
use alloy_primitives::{PrimitiveSignature as Signature, TxHash};
use reth_primitives_traits::{serde_bincode_compat::SerdeBincodeCompat, SignedTransaction};
use serde::{Deserialize, Serialize};
/// Bincode-compatible [`super::Transaction`] serde implementation.
#[derive(Debug, Serialize, Deserialize)]
#[allow(missing_docs)]
pub enum Transaction<'a> {
Legacy(TxLegacy<'a>),
Eip2930(TxEip2930<'a>),
Eip1559(TxEip1559<'a>),
Eip4844(Cow<'a, TxEip4844>),
Eip7702(TxEip7702<'a>),
}
impl<'a> From<&'a super::Transaction> for Transaction<'a> {
fn from(value: &'a super::Transaction) -> Self {
match value {
super::Transaction::Legacy(tx) => Self::Legacy(TxLegacy::from(tx)),
super::Transaction::Eip2930(tx) => Self::Eip2930(TxEip2930::from(tx)),
super::Transaction::Eip1559(tx) => Self::Eip1559(TxEip1559::from(tx)),
super::Transaction::Eip4844(tx) => Self::Eip4844(Cow::Borrowed(tx)),
super::Transaction::Eip7702(tx) => Self::Eip7702(TxEip7702::from(tx)),
}
}
}
impl<'a> From<Transaction<'a>> for super::Transaction {
fn from(value: Transaction<'a>) -> Self {
match value {
Transaction::Legacy(tx) => Self::Legacy(tx.into()),
Transaction::Eip2930(tx) => Self::Eip2930(tx.into()),
Transaction::Eip1559(tx) => Self::Eip1559(tx.into()),
Transaction::Eip4844(tx) => Self::Eip4844(tx.into_owned()),
Transaction::Eip7702(tx) => Self::Eip7702(tx.into()),
}
}
}
/// Bincode-compatible [`super::TransactionSigned`] serde implementation.
#[derive(Debug, Serialize, Deserialize)]
pub struct TransactionSigned<'a> {
hash: TxHash,
signature: Signature,
transaction: Transaction<'a>,
}
impl<'a> From<&'a super::TransactionSigned> for TransactionSigned<'a> {
fn from(value: &'a super::TransactionSigned) -> Self {
Self {
hash: *value.tx_hash(),
signature: value.signature,
transaction: Transaction::from(&value.transaction),
}
}
}
impl<'a> From<TransactionSigned<'a>> for super::TransactionSigned {
fn from(value: TransactionSigned<'a>) -> Self {
Self {
hash: value.hash.into(),
signature: value.signature,
transaction: value.transaction.into(),
}
}
}
impl SerdeBincodeCompat for super::TransactionSigned {
type BincodeRepr<'a> = TransactionSigned<'a>;
}
#[cfg(test)]
mod tests {
use super::super::{serde_bincode_compat, Transaction, TransactionSigned};
use arbitrary::Arbitrary;
use rand::Rng;
use reth_testing_utils::generators;
use serde::{Deserialize, Serialize};
#[test]
fn test_transaction_bincode_roundtrip() {
#[derive(Debug, Serialize, Deserialize)]
struct Data<'a> {
transaction: serde_bincode_compat::Transaction<'a>,
}
let mut bytes = [0u8; 1024];
generators::rng().fill(bytes.as_mut_slice());
let tx = Transaction::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap();
let data = Data { transaction: (&tx).into() };
let encoded = bincode::serialize(&data).unwrap();
let decoded: Data<'_> = bincode::deserialize(&encoded).unwrap();
assert_eq!(tx, decoded.transaction.into());
}
#[test]
fn test_transaction_signed_bincode_roundtrip() {
#[derive(Debug, Serialize, Deserialize)]
struct Data<'a> {
transaction: serde_bincode_compat::TransactionSigned<'a>,
}
let mut bytes = [0u8; 1024];
generators::rng().fill(bytes.as_mut_slice());
let tx =
TransactionSigned::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap();
let data = Data { transaction: (&tx).into() };
let encoded = bincode::serialize(&data).unwrap();
let decoded: Data<'_> = bincode::deserialize(&encoded).unwrap();
assert_eq!(tx, decoded.transaction.into());
}
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -36,7 +36,7 @@ reth-ethereum-primitives.workspace = true
[features]
default = ["std"]
optimism = ["reth-primitives/optimism", "revm/optimism"]
optimism = ["revm/optimism"]
serde = [
"dep:serde",
"rand/serde",
@ -55,7 +55,8 @@ serde-bincode-compat = [
"reth-primitives-traits/serde-bincode-compat",
"serde_with",
"alloy-eips/serde-bincode-compat",
"alloy-consensus/serde-bincode-compat",
"alloy-consensus/serde-bincode-compat",
"reth-ethereum-primitives/serde-bincode-compat"
]
std = [
"reth-primitives/std",

View File

@ -73,7 +73,6 @@ tempfile.workspace = true
[features]
optimism = [
"reth-primitives/optimism",
"reth-db?/optimism",
"reth-db-api?/optimism",
"reth-provider/optimism"

View File

@ -240,14 +240,15 @@ mod test {
struct MockReceiptContainer(Option<MockReceipt>);
impl TryFrom<MockReceipt> for ReceiptWithBlockNumber {
type Error = &'static str;
type Error = FileClientError;
fn try_from(exported_receipt: MockReceipt) -> Result<Self, Self::Error> {
let MockReceipt { tx_type, status, cumulative_gas_used, logs, block_number: number } =
exported_receipt;
#[allow(clippy::needless_update)]
let receipt = Receipt {
tx_type: TxType::try_from(tx_type.to_be_bytes()[0])?,
tx_type: TxType::try_from(tx_type.to_be_bytes()[0])
.map_err(|err| FileClientError::Rlp(err.into(), vec![tx_type]))?,
success: status != 0,
cumulative_gas_used,
logs,
@ -276,11 +277,7 @@ mod test {
.0;
src.advance(src.len() - buf_slice.len());
Ok(Some(
receipt
.map(|receipt| receipt.try_into().map_err(FileClientError::from))
.transpose()?,
))
Ok(Some(receipt.map(|receipt| receipt.try_into()).transpose()?))
}
}

View File

@ -2181,7 +2181,7 @@ mod tests {
});
assert!(transactions
.transactions_by_peers
.get(&signed_tx.hash())
.get(signed_tx.tx_hash())
.unwrap()
.contains(handle1.peer_id()));

View File

@ -356,7 +356,7 @@ mod test {
#[test]
fn eth68_announcement_unrecognized_tx_type() {
let types = vec![
TxType::MAX_RESERVED_EIP as u8 + 1, // the first type isn't valid
TxType::Eip7702 as u8 + 1, // the first type isn't valid
TxType::Legacy as u8,
];
let sizes = vec![MAX_MESSAGE_SIZE, MAX_MESSAGE_SIZE];
@ -391,8 +391,7 @@ mod test {
#[test]
fn eth68_announcement_too_small_tx() {
let types =
vec![TxType::MAX_RESERVED_EIP as u8, TxType::Legacy as u8, TxType::Eip2930 as u8];
let types = vec![TxType::Eip7702 as u8, TxType::Legacy as u8, TxType::Eip2930 as u8];
let sizes = vec![
0, // the first length isn't valid
0, // neither is the second

View File

@ -7,6 +7,7 @@ use reth_network::{
use reth_network_api::{NetworkInfo, Peers};
use reth_network_p2p::sync::{NetworkSyncUpdater, SyncState};
use reth_primitives::TransactionSigned;
use reth_primitives_traits::SignedTransaction;
use reth_provider::test_utils::MockEthProvider;
use reth_transaction_pool::{
test_utils::{testing_pool, MockTransaction},

View File

@ -9,6 +9,7 @@ use rand::thread_rng;
use reth_network::{test_utils::Testnet, NetworkEvent, NetworkEventListenerProvider};
use reth_network_api::{events::PeerEvent, PeersInfo};
use reth_primitives::TransactionSigned;
use reth_primitives_traits::SignedTransaction;
use reth_provider::test_utils::{ExtendedAccount, MockEthProvider};
use reth_transaction_pool::{test_utils::TransactionGenerator, PoolTransaction, TransactionPool};
@ -95,7 +96,7 @@ async fn test_4844_tx_gossip_penalization() {
let peer0_reputation_after =
peer1.peer_handle().peer_by_id(*peer0.peer_id()).await.unwrap().reputation();
assert_ne!(peer0_reputation_before, peer0_reputation_after);
assert_eq!(received, txs[1].transaction().hash());
assert_eq!(received, *txs[1].transaction().tx_hash());
// this will return an [`Empty`] error because blob txs are disallowed to be broadcasted
assert!(peer1_tx_listener.try_recv().is_err());

View File

@ -76,7 +76,7 @@ proptest.workspace = true
tokio.workspace = true
[features]
optimism = ["reth-primitives/optimism", "reth-db/optimism"]
optimism = ["reth-db/optimism"]
# Features for vergen to generate correct env vars
jemalloc = ["reth-cli-util/jemalloc"]
asm-keccak = ["reth-primitives/asm-keccak", "alloy-primitives/asm-keccak"]

View File

@ -83,7 +83,6 @@ optimism = [
"alloy-consensus",
"dep:derive_more",
"dep:serde",
"reth-primitives/optimism",
"reth-optimism-evm/optimism",
"reth-provider/optimism",
"reth-node-core/optimism",

View File

@ -1,6 +1,6 @@
use alloy_consensus::{
transaction::{from_eip155_value, RlpEcdsaTx},
Header, TxEip1559, TxEip2930, TxEip4844, TxEip7702, TxLegacy,
Header, TxEip1559, TxEip2930, TxEip7702, TxLegacy,
};
use alloy_eips::{
eip2718::{Decodable2718, Eip2718Error, Eip2718Result, Encodable2718},
@ -12,9 +12,8 @@ use alloy_primitives::{
};
use alloy_rlp::{Decodable, Error as RlpError, RlpDecodable};
use derive_more::{AsRef, Deref};
use op_alloy_consensus::TxDeposit;
use op_alloy_consensus::{OpTxType, OpTypedTransaction, TxDeposit};
use reth_downloaders::file_client::FileClientError;
use reth_primitives::transaction::{Transaction, TxType};
use serde::{Deserialize, Serialize};
use tokio_util::codec::Decoder;
@ -83,17 +82,7 @@ pub struct TransactionSigned {
/// Raw transaction info
#[deref]
#[as_ref]
pub transaction: Transaction,
}
impl Default for TransactionSigned {
fn default() -> Self {
Self {
hash: Default::default(),
signature: Signature::test_signature(),
transaction: Default::default(),
}
}
pub transaction: OpTypedTransaction,
}
impl AsRef<Self> for TransactionSigned {
@ -113,7 +102,10 @@ impl TransactionSigned {
/// Create a new signed transaction from a transaction and its signature.
///
/// This will also calculate the transaction hash using its encoding.
pub fn from_transaction_and_signature(transaction: Transaction, signature: Signature) -> Self {
pub fn from_transaction_and_signature(
transaction: OpTypedTransaction,
signature: Signature,
) -> Self {
let mut initial_tx = Self { transaction, hash: Default::default(), signature };
initial_tx.hash = initial_tx.recalculate_hash();
initial_tx
@ -190,7 +182,7 @@ impl TransactionSigned {
// so decoding methods do not need to manually advance the buffer
pub fn decode_rlp_legacy_transaction(data: &mut &[u8]) -> alloy_rlp::Result<Self> {
let (transaction, hash, signature) = Self::decode_rlp_legacy_transaction_tuple(data)?;
let signed = Self { transaction: Transaction::Legacy(transaction), hash, signature };
let signed = Self { transaction: OpTypedTransaction::Legacy(transaction), hash, signature };
Ok(signed)
}
}
@ -229,55 +221,58 @@ impl Decodable for TransactionSigned {
impl Encodable2718 for TransactionSigned {
fn type_flag(&self) -> Option<u8> {
match self.transaction.tx_type() {
TxType::Legacy => None,
OpTxType::Legacy => None,
tx_type => Some(tx_type as u8),
}
}
fn encode_2718_len(&self) -> usize {
match &self.transaction {
Transaction::Legacy(legacy_tx) => legacy_tx.eip2718_encoded_length(&self.signature),
Transaction::Eip2930(access_list_tx) => {
OpTypedTransaction::Legacy(legacy_tx) => {
legacy_tx.eip2718_encoded_length(&self.signature)
}
OpTypedTransaction::Eip2930(access_list_tx) => {
access_list_tx.eip2718_encoded_length(&self.signature)
}
Transaction::Eip1559(dynamic_fee_tx) => {
OpTypedTransaction::Eip1559(dynamic_fee_tx) => {
dynamic_fee_tx.eip2718_encoded_length(&self.signature)
}
Transaction::Eip4844(blob_tx) => blob_tx.eip2718_encoded_length(&self.signature),
Transaction::Eip7702(set_code_tx) => {
OpTypedTransaction::Eip7702(set_code_tx) => {
set_code_tx.eip2718_encoded_length(&self.signature)
}
Transaction::Deposit(deposit_tx) => deposit_tx.eip2718_encoded_length(),
OpTypedTransaction::Deposit(deposit_tx) => deposit_tx.eip2718_encoded_length(),
}
}
fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) {
self.transaction.eip2718_encode(&self.signature, out)
match &self.transaction {
OpTypedTransaction::Legacy(tx) => tx.eip2718_encode(&self.signature, out),
OpTypedTransaction::Eip2930(tx) => tx.eip2718_encode(&self.signature, out),
OpTypedTransaction::Eip1559(tx) => tx.eip2718_encode(&self.signature, out),
OpTypedTransaction::Eip7702(tx) => tx.eip2718_encode(&self.signature, out),
OpTypedTransaction::Deposit(tx) => tx.encode_2718(out),
}
}
}
impl Decodable2718 for TransactionSigned {
fn typed_decode(ty: u8, buf: &mut &[u8]) -> Eip2718Result<Self> {
match ty.try_into().map_err(|_| Eip2718Error::UnexpectedType(ty))? {
TxType::Legacy => Err(Eip2718Error::UnexpectedType(0)),
TxType::Eip2930 => {
OpTxType::Legacy => Err(Eip2718Error::UnexpectedType(0)),
OpTxType::Eip2930 => {
let (tx, signature, hash) = TxEip2930::rlp_decode_signed(buf)?.into_parts();
Ok(Self { transaction: Transaction::Eip2930(tx), signature, hash })
Ok(Self { transaction: OpTypedTransaction::Eip2930(tx), signature, hash })
}
TxType::Eip1559 => {
OpTxType::Eip1559 => {
let (tx, signature, hash) = TxEip1559::rlp_decode_signed(buf)?.into_parts();
Ok(Self { transaction: Transaction::Eip1559(tx), signature, hash })
Ok(Self { transaction: OpTypedTransaction::Eip1559(tx), signature, hash })
}
TxType::Eip7702 => {
OpTxType::Eip7702 => {
let (tx, signature, hash) = TxEip7702::rlp_decode_signed(buf)?.into_parts();
Ok(Self { transaction: Transaction::Eip7702(tx), signature, hash })
Ok(Self { transaction: OpTypedTransaction::Eip7702(tx), signature, hash })
}
TxType::Eip4844 => {
let (tx, signature, hash) = TxEip4844::rlp_decode_signed(buf)?.into_parts();
Ok(Self { transaction: Transaction::Eip4844(tx), signature, hash })
}
TxType::Deposit => Ok(Self::from_transaction_and_signature(
Transaction::Deposit(TxDeposit::rlp_decode(buf)?),
OpTxType::Deposit => Ok(Self::from_transaction_and_signature(
OpTypedTransaction::Deposit(TxDeposit::rlp_decode(buf)?),
TxDeposit::signature(),
)),
}
@ -291,8 +286,9 @@ impl Decodable2718 for TransactionSigned {
#[cfg(test)]
mod tests {
use crate::ovm_file_codec::TransactionSigned;
use alloy_consensus::Typed2718;
use alloy_primitives::{address, hex, TxKind, B256, U256};
use reth_primitives::transaction::Transaction;
use op_alloy_consensus::OpTypedTransaction;
const DEPOSIT_FUNCTION_SELECTOR: [u8; 4] = [0xb6, 0xb5, 0x5f, 0x25];
use alloy_rlp::Decodable;
@ -305,7 +301,7 @@ mod tests {
// Verify deposit transaction
let deposit_tx = match &deposit_decoded.transaction {
Transaction::Legacy(ref tx) => tx,
OpTypedTransaction::Legacy(ref tx) => tx,
_ => panic!("Expected legacy transaction for NFT deposit"),
};
@ -345,7 +341,7 @@ mod tests {
assert!(system_decoded.is_legacy());
let system_tx = match &system_decoded.transaction {
Transaction::Legacy(ref tx) => tx,
OpTypedTransaction::Legacy(ref tx) => tx,
_ => panic!("Expected Legacy transaction"),
};

View File

@ -5,9 +5,9 @@ use alloy_primitives::{
Address, Bloom, Bytes, B256,
};
use alloy_rlp::{Decodable, RlpDecodable};
use op_alloy_consensus::OpDepositReceipt;
use op_alloy_consensus::{OpDepositReceipt, OpTxType};
use reth_optimism_primitives::OpReceipt;
use reth_primitives::{Log, Receipt, TxType};
use reth_primitives::{Log, Receipt};
use tokio_util::codec::Decoder;
use reth_downloaders::{file_client::FileClientError, receipt_file_client::ReceiptWithBlockNumber};
@ -92,49 +92,27 @@ pub struct OpGethReceipt {
#[rlp(trailing)]
struct OpGethReceiptContainer(Option<OpGethReceipt>);
impl TryFrom<OpGethReceipt> for Receipt {
type Error = &'static str;
impl TryFrom<OpGethReceipt> for OpReceipt {
type Error = FileClientError;
fn try_from(exported_receipt: OpGethReceipt) -> Result<Self, Self::Error> {
let OpGethReceipt { tx_type, status, cumulative_gas_used, logs, .. } = exported_receipt;
#[allow(clippy::needless_update)]
Ok(Self {
tx_type: TxType::try_from(tx_type.to_be_bytes()[0])?,
success: status != 0,
cumulative_gas_used,
logs,
..Default::default()
})
}
}
impl TryFrom<OpGethReceipt> for OpReceipt {
type Error = &'static str;
fn try_from(exported_receipt: OpGethReceipt) -> Result<Self, Self::Error> {
let Receipt {
tx_type,
success,
cumulative_gas_used,
logs,
deposit_nonce,
deposit_receipt_version,
} = exported_receipt.try_into()?;
let tx_type = OpTxType::try_from(tx_type.to_be_bytes()[0])
.map_err(|e| FileClientError::Rlp(e.into(), vec![tx_type]))?;
let receipt =
alloy_consensus::Receipt { status: success.into(), cumulative_gas_used, logs };
alloy_consensus::Receipt { status: (status != 0).into(), cumulative_gas_used, logs };
match tx_type {
TxType::Legacy => Ok(Self::Legacy(receipt)),
TxType::Eip2930 => Ok(Self::Eip2930(receipt)),
TxType::Eip1559 => Ok(Self::Eip1559(receipt)),
TxType::Eip7702 => Ok(Self::Eip7702(receipt)),
TxType::Eip4844 => Err("EIP-4844 receipts are not supported for OP"),
TxType::Deposit => Ok(Self::Deposit(OpDepositReceipt {
OpTxType::Legacy => Ok(Self::Legacy(receipt)),
OpTxType::Eip2930 => Ok(Self::Eip2930(receipt)),
OpTxType::Eip1559 => Ok(Self::Eip1559(receipt)),
OpTxType::Eip7702 => Ok(Self::Eip7702(receipt)),
OpTxType::Deposit => Ok(Self::Deposit(OpDepositReceipt {
inner: receipt,
deposit_nonce,
deposit_receipt_version,
deposit_nonce: None,
deposit_receipt_version: None,
})),
}
}
@ -142,6 +120,7 @@ impl TryFrom<OpGethReceipt> for OpReceipt {
#[cfg(test)]
pub(crate) mod test {
use alloy_consensus::{Receipt, TxReceipt};
use alloy_primitives::{hex, LogData};
use super::*;
@ -156,12 +135,12 @@ pub(crate) mod test {
let receipt = receipt_block_1();
OpGethReceipt {
tx_type: receipt.receipt.tx_type as u8,
tx_type: receipt.receipt.tx_type() as u8,
post_state: Bytes::default(),
status: receipt.receipt.success as u64,
cumulative_gas_used: receipt.receipt.cumulative_gas_used,
status: receipt.receipt.status() as u64,
cumulative_gas_used: receipt.receipt.cumulative_gas_used(),
bloom: Bloom::from(hex!("00000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000400000000000100000000000000200000000002000000000000001000000000000000000004000000000000000000000000000040000400000100400000000000000100000000000000000000000000000020000000000000000000000000000000000000000000000001000000000000000000000100000000000000000000000000000000000000000000000000000000000000088000000080000000000010000000000000000000000000000800008000120000000000000000000000000000000002000")),
logs: receipt.receipt.logs,
logs: receipt.receipt.logs().to_vec(),
tx_hash: B256::from(hex!("5e77a04531c7c107af1882d76cbff9486d0a9aa53701c30888509d4f5f2b003a")), contract_address: Address::from(hex!("0000000000000000000000000000000000000000")), gas_used: 202813,
block_hash: B256::from(hex!("bee7192e575af30420cae0c7776304ac196077ee72b048970549e4f08e875453")),
block_number: receipt.number,
@ -173,7 +152,7 @@ pub(crate) mod test {
}
}
pub(crate) fn receipt_block_1() -> ReceiptWithBlockNumber {
pub(crate) fn receipt_block_1() -> ReceiptWithBlockNumber<OpReceipt> {
let log_1 = Log {
address: Address::from(hex!("8ce8c13d816fe6daf12d6fd9e4952e1fc88850af")),
data: LogData::new(
@ -233,20 +212,16 @@ pub(crate) mod test {
.unwrap(),
};
let mut receipt = Receipt {
tx_type: TxType::Legacy,
success: true,
let receipt = OpReceipt::Legacy(Receipt {
status: true.into(),
cumulative_gas_used: 202813,
..Default::default()
};
// #[allow(clippy::needless_update)] not recognised, ..Default::default() needed so optimism
// feature must not be brought into scope
receipt.logs = vec![log_1, log_2, log_3];
logs: vec![log_1, log_2, log_3],
});
ReceiptWithBlockNumber { receipt, number: 1 }
}
pub(crate) fn receipt_block_2() -> ReceiptWithBlockNumber {
pub(crate) fn receipt_block_2() -> ReceiptWithBlockNumber<OpReceipt> {
let log_1 = Log {
address: Address::from(hex!("8ce8c13d816fe6daf12d6fd9e4952e1fc88850af")),
data: LogData::new(
@ -285,20 +260,16 @@ pub(crate) mod test {
.unwrap(),
};
let mut receipt = Receipt {
tx_type: TxType::Legacy,
success: true,
let receipt = OpReceipt::Legacy(Receipt {
status: true.into(),
cumulative_gas_used: 116237,
..Default::default()
};
// #[allow(clippy::needless_update)] not recognised, ..Default::default() needed so optimism
// feature must not be brought into scope
receipt.logs = vec![log_1, log_2];
logs: vec![log_1, log_2],
});
ReceiptWithBlockNumber { receipt, number: 2 }
}
pub(crate) fn receipt_block_3() -> ReceiptWithBlockNumber {
pub(crate) fn receipt_block_3() -> ReceiptWithBlockNumber<OpReceipt> {
let log_1 = Log {
address: Address::from(hex!("8ce8c13d816fe6daf12d6fd9e4952e1fc88850af")),
data: LogData::new(
@ -337,15 +308,11 @@ pub(crate) mod test {
.unwrap(),
};
let mut receipt = Receipt {
tx_type: TxType::Legacy,
success: true,
let receipt = OpReceipt::Legacy(Receipt {
status: true.into(),
cumulative_gas_used: 116237,
..Default::default()
};
// #[allow(clippy::needless_update)] not recognised, ..Default::default() needed so optimism
// feature must not be brought into scope
receipt.logs = vec![log_1, log_2];
logs: vec![log_1, log_2],
});
ReceiptWithBlockNumber { receipt, number: 3 }
}

View File

@ -55,4 +55,4 @@ std = [
"alloy-trie/std",
"op-alloy-consensus/std",
]
optimism = ["reth-primitives/optimism", "reth-optimism-primitives/optimism"]
optimism = ["reth-optimism-primitives/optimism"]

View File

@ -78,7 +78,6 @@ std = [
"reth-consensus-common/std",
]
optimism = [
"reth-primitives/optimism",
"reth-execution-types/optimism",
"reth-optimism-consensus/optimism",
"revm/optimism",

View File

@ -312,7 +312,8 @@ mod tests {
use alloy_eips::eip2718::Decodable2718;
use reth_optimism_chainspec::OP_MAINNET;
use reth_optimism_forks::OpHardforks;
use reth_primitives::{Block, BlockBody, TransactionSigned};
use reth_optimism_primitives::OpTransactionSigned;
use reth_primitives::{Block, BlockBody};
use super::*;
@ -320,10 +321,9 @@ mod tests {
fn sanity_l1_block() {
use alloy_consensus::Header;
use alloy_primitives::{hex_literal::hex, Bytes};
use reth_primitives::TransactionSigned;
let bytes = Bytes::from_static(&hex!("7ef9015aa044bae9d41b8380d781187b426c6fe43df5fb2fb57bd4466ef6a701e1f01e015694deaddeaddeaddeaddeaddeaddeaddeaddead000194420000000000000000000000000000000000001580808408f0d18001b90104015d8eb900000000000000000000000000000000000000000000000000000000008057650000000000000000000000000000000000000000000000000000000063d96d10000000000000000000000000000000000000000000000000000000000009f35273d89754a1e0387b89520d989d3be9c37c1f32495a88faf1ea05c61121ab0d1900000000000000000000000000000000000000000000000000000000000000010000000000000000000000002d679b567db6187c0c8323fa982cfb88b74dbcc7000000000000000000000000000000000000000000000000000000000000083400000000000000000000000000000000000000000000000000000000000f4240"));
let l1_info_tx = TransactionSigned::decode_2718(&mut bytes.as_ref()).unwrap();
let l1_info_tx = OpTransactionSigned::decode_2718(&mut bytes.as_ref()).unwrap();
let mock_block = Block {
header: Header::default(),
body: BlockBody { transactions: vec![l1_info_tx], ..Default::default() },
@ -351,7 +351,7 @@ mod tests {
// https://optimistic.etherscan.io/getRawTx?tx=0x88501da5d5ca990347c2193be90a07037af1e3820bb40774c8154871c7669150
const TX: [u8; 251] = hex!("7ef8f8a0a539eb753df3b13b7e386e147d45822b67cb908c9ddc5618e3dbaa22ed00850b94deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b8a4440a5e2000000558000c5fc50000000000000000000000006605a89f00000000012a10d90000000000000000000000000000000000000000000000000000000af39ac3270000000000000000000000000000000000000000000000000000000d5ea528d24e582fa68786f080069bdbfe06a43f8e67bfd31b8e4d8a8837ba41da9a82a54a0000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f32985");
let tx = TransactionSigned::decode_2718(&mut TX.as_slice()).unwrap();
let tx = OpTransactionSigned::decode_2718(&mut TX.as_slice()).unwrap();
let block = Block {
body: BlockBody { transactions: vec![tx], ..Default::default() },
..Default::default()

View File

@ -89,7 +89,6 @@ futures.workspace = true
[features]
default = ["reth-codec"]
optimism = [
"reth-primitives/optimism",
"reth-provider/optimism",
"reth-optimism-evm/optimism",
"reth-optimism-payload-builder/optimism",

View File

@ -55,7 +55,6 @@ sha2.workspace = true
[features]
optimism = [
"reth-primitives/optimism",
"reth-provider/optimism",
"reth-optimism-evm/optimism",
"revm/optimism",

View File

@ -25,10 +25,9 @@ use reth_payload_builder_primitives::PayloadBuilderError;
use reth_payload_primitives::PayloadBuilderAttributes;
use reth_payload_util::{NoopPayloadTransactions, PayloadTransactions};
use reth_primitives::{
proofs, transaction::SignedTransactionIntoRecoveredExt, Block, BlockBody, RecoveredBlock,
SealedHeader, TxType,
proofs, transaction::SignedTransactionIntoRecoveredExt, Block, BlockBody, SealedHeader,
};
use reth_primitives_traits::block::Block as _;
use reth_primitives_traits::{block::Block as _, RecoveredBlock};
use reth_provider::{
HashedPostStateProvider, ProviderError, StateProofProvider, StateProviderFactory,
StateRootProvider,
@ -864,7 +863,7 @@ where
}
// A sequencer's block should never contain blob or deposit transactions from the pool.
if tx.is_eip4844() || tx.tx_type() == TxType::Deposit as u8 {
if tx.is_eip4844() || tx.tx_type() == OpTxType::Deposit {
best_txs.mark_invalid(tx.signer(), tx.nonce());
continue
}

View File

@ -49,6 +49,7 @@ rstest.workspace = true
arbitrary.workspace = true
secp256k1 = { workspace = true, features = ["rand"] }
proptest.workspace = true
rand.workspace = true
[features]
default = ["std"]

View File

@ -308,4 +308,197 @@ mod compact {
(receipt.into(), buf)
}
}
#[cfg(test)]
#[test]
fn test_ensure_backwards_compatibility() {
use reth_codecs::{test_utils::UnusedBits, validate_bitflag_backwards_compat};
assert_eq!(CompactOpReceipt::bitflag_encoded_bytes(), 2);
validate_bitflag_backwards_compat!(CompactOpReceipt<'_>, UnusedBits::NotZero);
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_eips::eip2718::Encodable2718;
use alloy_primitives::{address, b256, bytes, hex_literal::hex, Bytes};
use alloy_rlp::Encodable;
use reth_codecs::Compact;
#[test]
fn test_decode_receipt() {
reth_codecs::test_utils::test_decode::<OpReceipt>(&hex!(
"c30328b52ffd23fc426961a00105007eb0042307705a97e503562eacf2b95060cce9de6de68386b6c155b73a9650021a49e2f8baad17f30faff5899d785c4c0873e45bc268bcf07560106424570d11f9a59e8f3db1efa4ceec680123712275f10d92c3411e1caaa11c7c5d591bc11487168e09934a9986848136da1b583babf3a7188e3aed007a1520f1cf4c1ca7d3482c6c28d37c298613c70a76940008816c4c95644579fd08471dc34732fd0f24"
));
}
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
#[test]
fn encode_legacy_receipt() {
let expected = hex!("f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff");
let mut data = Vec::with_capacity(expected.length());
let receipt = ReceiptWithBloom {
receipt: OpReceipt::Legacy(Receipt {
status: Eip658Value::Eip658(false),
cumulative_gas_used: 0x1,
logs: vec![Log::new_unchecked(
address!("0000000000000000000000000000000000000011"),
vec![
b256!("000000000000000000000000000000000000000000000000000000000000dead"),
b256!("000000000000000000000000000000000000000000000000000000000000beef"),
],
bytes!("0100ff"),
)],
}),
logs_bloom: [0; 256].into(),
};
receipt.encode(&mut data);
// check that the rlp length equals the length of the expected rlp
assert_eq!(receipt.length(), expected.len());
assert_eq!(data, expected);
}
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
#[test]
fn decode_legacy_receipt() {
let data = hex!("f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff");
// EIP658Receipt
let expected = ReceiptWithBloom {
receipt: OpReceipt::Legacy(Receipt {
status: Eip658Value::Eip658(false),
cumulative_gas_used: 0x1,
logs: vec![Log::new_unchecked(
address!("0000000000000000000000000000000000000011"),
vec![
b256!("000000000000000000000000000000000000000000000000000000000000dead"),
b256!("000000000000000000000000000000000000000000000000000000000000beef"),
],
bytes!("0100ff"),
)],
}),
logs_bloom: [0; 256].into(),
};
let receipt = ReceiptWithBloom::decode(&mut &data[..]).unwrap();
assert_eq!(receipt, expected);
}
#[test]
fn decode_deposit_receipt_regolith_roundtrip() {
let data = hex!("b901107ef9010c0182b741b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0833d3bbf");
// Deposit Receipt (post-regolith)
let expected = ReceiptWithBloom {
receipt: OpReceipt::Deposit(OpDepositReceipt {
inner: Receipt {
status: Eip658Value::Eip658(true),
cumulative_gas_used: 46913,
logs: vec![],
},
deposit_nonce: Some(4012991),
deposit_receipt_version: None,
}),
logs_bloom: [0; 256].into(),
};
let receipt = ReceiptWithBloom::decode(&mut &data[..]).unwrap();
assert_eq!(receipt, expected);
let mut buf = Vec::with_capacity(data.len());
receipt.encode(&mut buf);
assert_eq!(buf, &data[..]);
}
#[test]
fn decode_deposit_receipt_canyon_roundtrip() {
let data = hex!("b901117ef9010d0182b741b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0833d3bbf01");
// Deposit Receipt (post-regolith)
let expected = ReceiptWithBloom {
receipt: OpReceipt::Deposit(OpDepositReceipt {
inner: Receipt {
status: Eip658Value::Eip658(true),
cumulative_gas_used: 46913,
logs: vec![],
},
deposit_nonce: Some(4012991),
deposit_receipt_version: Some(1),
}),
logs_bloom: [0; 256].into(),
};
let receipt = ReceiptWithBloom::decode(&mut &data[..]).unwrap();
assert_eq!(receipt, expected);
let mut buf = Vec::with_capacity(data.len());
expected.encode(&mut buf);
assert_eq!(buf, &data[..]);
}
#[test]
fn gigantic_receipt() {
let receipt = OpReceipt::Legacy(Receipt {
status: Eip658Value::Eip658(true),
cumulative_gas_used: 16747627,
logs: vec![
Log::new_unchecked(
address!("4bf56695415f725e43c3e04354b604bcfb6dfb6e"),
vec![b256!("c69dc3d7ebff79e41f525be431d5cd3cc08f80eaf0f7819054a726eeb7086eb9")],
Bytes::from(vec![1; 0xffffff]),
),
Log::new_unchecked(
address!("faca325c86bf9c2d5b413cd7b90b209be92229c2"),
vec![b256!("8cca58667b1e9ffa004720ac99a3d61a138181963b294d270d91c53d36402ae2")],
Bytes::from(vec![1; 0xffffff]),
),
],
});
let mut data = vec![];
receipt.to_compact(&mut data);
let (decoded, _) = OpReceipt::from_compact(&data[..], data.len());
assert_eq!(decoded, receipt);
}
#[test]
fn test_encode_2718_length() {
let receipt = ReceiptWithBloom {
receipt: OpReceipt::Eip1559(Receipt {
status: Eip658Value::Eip658(true),
cumulative_gas_used: 21000,
logs: vec![],
}),
logs_bloom: Bloom::default(),
};
let encoded = receipt.encoded_2718();
assert_eq!(
encoded.len(),
receipt.encode_2718_len(),
"Encoded length should match the actual encoded data length"
);
// Test for legacy receipt as well
let legacy_receipt = ReceiptWithBloom {
receipt: OpReceipt::Legacy(Receipt {
status: Eip658Value::Eip658(true),
cumulative_gas_used: 21000,
logs: vec![],
}),
logs_bloom: Bloom::default(),
};
let legacy_encoded = legacy_receipt.encoded_2718();
assert_eq!(
legacy_encoded.len(),
legacy_receipt.encode_2718_len(),
"Encoded length for legacy receipt should match the actual encoded data length"
);
}
}

View File

@ -70,7 +70,6 @@ reth-optimism-chainspec.workspace = true
[features]
optimism = [
"reth-optimism-evm/optimism",
"reth-primitives/optimism",
"reth-provider/optimism",
"revm/optimism",
"reth-optimism-consensus/optimism",

View File

@ -21,7 +21,6 @@ reth-stages-types.workspace = true
[features]
optimism = [
"reth-primitives/optimism",
"reth-codecs/op",
"reth-db-api/optimism"
]

View File

@ -16,7 +16,7 @@ mod tests {
CompactClientVersion, CompactU256, CompactU64, StoredBlockBodyIndices,
StoredBlockWithdrawals,
};
use reth_primitives::{Account, Receipt};
use reth_primitives::Account;
use reth_prune_types::{PruneCheckpoint, PruneMode, PruneSegment};
use reth_stages_types::{
AccountHashingCheckpoint, CheckpointBlockRange, EntitiesCheckpoint, ExecutionCheckpoint,
@ -39,7 +39,6 @@ mod tests {
assert_eq!(PruneCheckpoint::bitflag_encoded_bytes(), 1);
assert_eq!(PruneMode::bitflag_encoded_bytes(), 1);
assert_eq!(PruneSegment::bitflag_encoded_bytes(), 1);
assert_eq!(Receipt::bitflag_encoded_bytes(), 2);
assert_eq!(StageCheckpoint::bitflag_encoded_bytes(), 1);
assert_eq!(StageUnitCheckpoint::bitflag_encoded_bytes(), 1);
assert_eq!(StoredBlockBodyIndices::bitflag_encoded_bytes(), 1);
@ -62,7 +61,6 @@ mod tests {
validate_bitflag_backwards_compat!(PruneCheckpoint, UnusedBits::NotZero);
validate_bitflag_backwards_compat!(PruneMode, UnusedBits::Zero);
validate_bitflag_backwards_compat!(PruneSegment, UnusedBits::Zero);
validate_bitflag_backwards_compat!(Receipt, UnusedBits::NotZero);
validate_bitflag_backwards_compat!(StageCheckpoint, UnusedBits::NotZero);
validate_bitflag_backwards_compat!(StageUnitCheckpoint, UnusedBits::Zero);
validate_bitflag_backwards_compat!(StoredBlockBodyIndices, UnusedBits::Zero);

View File

@ -13,48 +13,24 @@ workspace = true
[dependencies]
# reth
reth-ethereum-primitives.workspace = true
reth-primitives-traits = { workspace = true, features = ["serde"] }
reth-ethereum-forks.workspace = true
reth-static-file-types.workspace = true
revm-primitives = { workspace = true, features = ["serde"] }
reth-codecs = { workspace = true, optional = true }
reth-zstd-compressors = { workspace = true, optional = true }
# ethereum
alloy-consensus.workspace = true
alloy-network = { workspace = true, optional = true }
alloy-primitives = { workspace = true, features = ["rand", "rlp"] }
alloy-rlp = { workspace = true, features = ["arrayvec"] }
alloy-rpc-types = { workspace = true, optional = true }
alloy-serde = { workspace = true, optional = true }
alloy-eips = { workspace = true, features = ["serde"] }
alloy-trie = { workspace = true, features = ["serde"] }
# optimism
op-alloy-rpc-types = { workspace = true, optional = true }
op-alloy-consensus = { workspace = true, features = [
"arbitrary",
"serde",
], optional = true }
# for eip-4844
c-kzg = { workspace = true, features = ["serde"], optional = true }
# crypto
secp256k1 = { workspace = true, features = [
"global-context",
"recovery",
"rand",
], optional = true }
# misc
bytes.workspace = true
derive_more.workspace = true
modular-bitfield = { workspace = true, optional = true }
once_cell.workspace = true
rand = { workspace = true, optional = true }
serde.workspace = true
serde_with = { workspace = true, optional = true }
# arbitrary utils
arbitrary = { workspace = true, features = ["derive"], optional = true }
@ -62,30 +38,20 @@ arbitrary = { workspace = true, features = ["derive"], optional = true }
[dev-dependencies]
# eth
reth-chainspec = { workspace = true, features = ["arbitrary"] }
reth-codecs = { workspace = true, features = ["test-utils"] }
reth-primitives-traits = { workspace = true, features = ["arbitrary", "test-utils"] }
reth-testing-utils.workspace = true
reth-trie-common = { workspace = true, features = ["arbitrary"] }
revm-primitives = { workspace = true, features = ["arbitrary"] }
alloy-rlp.workspace = true
alloy-eips = { workspace = true, features = ["arbitrary"] }
alloy-genesis.workspace = true
arbitrary = { workspace = true, features = ["derive"] }
secp256k1 = { workspace = true, features = [
"global-context",
"recovery",
"rand",
] }
assert_matches.workspace = true
bincode.workspace = true
proptest-arbitrary-interop.workspace = true
proptest.workspace = true
rand.workspace = true
serde_json.workspace = true
test-fuzz.workspace = true
rstest.workspace = true
reth-codecs.workspace = true
criterion.workspace = true
pprof = { workspace = true, features = [
@ -102,50 +68,36 @@ std = [
"alloy-eips/std",
"alloy-genesis/std",
"alloy-primitives/std",
"alloy-serde?/std",
"once_cell/std",
"revm-primitives/std",
"serde/std",
"alloy-trie/std",
"serde_with?/std",
"alloy-rlp/std",
"reth-ethereum-forks/std",
"bytes/std",
"derive_more/std",
"reth-zstd-compressors?/std",
"secp256k1?/std",
"reth-trie-common/std",
"op-alloy-consensus?/std",
"op-alloy-rpc-types?/std",
"serde_json/std",
"reth-chainspec/std"
"reth-chainspec/std",
"reth-ethereum-primitives/std",
"alloy-rlp/std"
]
reth-codec = [
"dep:reth-codecs",
"dep:reth-zstd-compressors",
"dep:modular-bitfield", "std",
"std",
"reth-primitives-traits/reth-codec",
"reth-ethereum-primitives/reth-codec"
]
asm-keccak = ["alloy-primitives/asm-keccak", "revm-primitives/asm-keccak"]
asm-keccak = ["alloy-primitives/asm-keccak"]
arbitrary = [
"dep:arbitrary",
"alloy-eips/arbitrary",
"rand",
"reth-codec",
"reth-ethereum-forks/arbitrary",
"reth-primitives-traits/arbitrary",
"revm-primitives/arbitrary",
"reth-chainspec/arbitrary",
"alloy-consensus/arbitrary",
"alloy-primitives/arbitrary",
"alloy-rpc-types?/arbitrary",
"alloy-serde?/arbitrary",
"op-alloy-consensus?/arbitrary",
"op-alloy-rpc-types?/arbitrary",
"reth-codecs?/arbitrary",
"alloy-trie/arbitrary",
"reth-trie-common/arbitrary",
"dep:secp256k1"
"reth-ethereum-primitives/arbitrary",
"reth-codecs/arbitrary"
]
secp256k1 = [
"reth-primitives-traits/secp256k1",
@ -154,33 +106,23 @@ c-kzg = [
"dep:c-kzg",
"alloy-consensus/kzg",
"alloy-eips/kzg",
"revm-primitives/c-kzg",
]
optimism = [
"dep:op-alloy-consensus",
"reth-codecs?/op",
"revm-primitives/optimism",
]
alloy-compat = [
"dep:alloy-rpc-types",
"dep:alloy-serde",
"dep:op-alloy-rpc-types",
"dep:alloy-network",
"reth-ethereum-primitives/alloy-compat"
]
test-utils = [
"reth-primitives-traits/test-utils",
"reth-chainspec/test-utils",
"reth-codecs?/test-utils",
"reth-trie-common/test-utils",
"arbitrary",
"reth-codecs/test-utils"
]
serde-bincode-compat = [
"serde_with",
"alloy-eips/serde-bincode-compat",
"alloy-consensus/serde-bincode-compat",
"op-alloy-consensus?/serde-bincode-compat",
"reth-primitives-traits/serde-bincode-compat",
"reth-trie-common/serde-bincode-compat",
"reth-ethereum-primitives/serde-bincode-compat"
]
[[bench]]

View File

@ -1,189 +0,0 @@
//! Common conversions from alloy types.
use crate::{Transaction, TransactionSigned};
use alloc::string::ToString;
use alloy_consensus::TxEnvelope;
use alloy_network::{AnyRpcTransaction, AnyTxEnvelope};
use alloy_serde::WithOtherFields;
use op_alloy_rpc_types as _;
impl TryFrom<AnyRpcTransaction> for TransactionSigned {
type Error = alloy_rpc_types::ConversionError;
fn try_from(tx: AnyRpcTransaction) -> Result<Self, Self::Error> {
use alloy_rpc_types::ConversionError;
let WithOtherFields { inner: tx, other: _ } = tx;
#[allow(unreachable_patterns)]
let (transaction, signature, hash) = match tx.inner {
AnyTxEnvelope::Ethereum(TxEnvelope::Legacy(tx)) => {
let (tx, signature, hash) = tx.into_parts();
(Transaction::Legacy(tx), signature, hash)
}
AnyTxEnvelope::Ethereum(TxEnvelope::Eip2930(tx)) => {
let (tx, signature, hash) = tx.into_parts();
(Transaction::Eip2930(tx), signature, hash)
}
AnyTxEnvelope::Ethereum(TxEnvelope::Eip1559(tx)) => {
let (tx, signature, hash) = tx.into_parts();
(Transaction::Eip1559(tx), signature, hash)
}
AnyTxEnvelope::Ethereum(TxEnvelope::Eip4844(tx)) => {
let (tx, signature, hash) = tx.into_parts();
(Transaction::Eip4844(tx.into()), signature, hash)
}
AnyTxEnvelope::Ethereum(TxEnvelope::Eip7702(tx)) => {
let (tx, signature, hash) = tx.into_parts();
(Transaction::Eip7702(tx), signature, hash)
}
#[cfg(feature = "optimism")]
AnyTxEnvelope::Unknown(alloy_network::UnknownTxEnvelope { hash, inner }) => {
use alloy_consensus::{Transaction as _, Typed2718};
if inner.ty() == crate::TxType::Deposit {
let fields: op_alloy_rpc_types::OpTransactionFields = inner
.fields
.clone()
.deserialize_into::<op_alloy_rpc_types::OpTransactionFields>()
.map_err(|e| ConversionError::Custom(e.to_string()))?;
(
Transaction::Deposit(op_alloy_consensus::TxDeposit {
source_hash: fields.source_hash.ok_or_else(|| {
ConversionError::Custom("MissingSourceHash".to_string())
})?,
from: tx.from,
to: revm_primitives::TxKind::from(inner.to()),
mint: fields.mint.filter(|n| *n != 0),
value: inner.value(),
gas_limit: inner.gas_limit(),
is_system_transaction: fields.is_system_tx.unwrap_or(false),
input: inner.input().clone(),
}),
op_alloy_consensus::TxDeposit::signature(),
hash,
)
} else {
return Err(ConversionError::Custom("unknown transaction type".to_string()))
}
}
_ => return Err(ConversionError::Custom("unknown transaction type".to_string())),
};
Ok(Self { transaction, signature, hash: hash.into() })
}
}
#[cfg(test)]
#[cfg(feature = "optimism")]
mod tests {
use super::*;
use alloy_primitives::{address, Address, B256, U256};
use revm_primitives::TxKind;
#[test]
fn optimism_deposit_tx_conversion_no_mint() {
let input = r#"{
"blockHash": "0xef664d656f841b5ad6a2b527b963f1eb48b97d7889d742f6cbff6950388e24cd",
"blockNumber": "0x73a78fd",
"depositReceiptVersion": "0x1",
"from": "0x36bde71c97b33cc4729cf772ae268934f7ab70b2",
"gas": "0xc27a8",
"gasPrice": "0x0",
"hash": "0x0bf1845c5d7a82ec92365d5027f7310793d53004f3c86aa80965c67bf7e7dc80",
"input":
"0xd764ad0b000100000000000000000000000000000000000000000000000000000001cf5400000000000000000000000099c9fc46f92e8a1c0dec1b1747d010903e884be100000000000000000000000042000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e40166a07a0000000000000000000000000994206dfe8de6ec6920ff4d779b0d950605fb53000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd52000000000000000000000000ca74f404e0c7bfa35b13b511097df966d5a65597000000000000000000000000ca74f404e0c7bfa35b13b511097df966d5a65597000000000000000000000000000000000000000000000216614199391dbba2ba00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
, "mint": "0x0",
"nonce": "0x74060",
"r": "0x0",
"s": "0x0",
"sourceHash": "0x074adb22f2e6ed9bdd31c52eefc1f050e5db56eb85056450bccd79a6649520b3",
"to": "0x4200000000000000000000000000000000000007",
"transactionIndex": "0x1",
"type": "0x7e",
"v": "0x0",
"value": "0x0"
}"#;
let alloy_tx: WithOtherFields<alloy_rpc_types::Transaction<AnyTxEnvelope>> =
serde_json::from_str(input).expect("failed to deserialize");
let TransactionSigned { transaction: reth_tx, .. } =
alloy_tx.try_into().expect("failed to convert");
if let Transaction::Deposit(deposit_tx) = reth_tx {
assert_eq!(
deposit_tx.source_hash,
"0x074adb22f2e6ed9bdd31c52eefc1f050e5db56eb85056450bccd79a6649520b3"
.parse::<B256>()
.unwrap()
);
assert_eq!(
deposit_tx.from,
"0x36bde71c97b33cc4729cf772ae268934f7ab70b2".parse::<Address>().unwrap()
);
assert_eq!(
deposit_tx.to,
TxKind::from(address!("4200000000000000000000000000000000000007"))
);
assert_eq!(deposit_tx.mint, None);
assert_eq!(deposit_tx.value, U256::ZERO);
assert_eq!(deposit_tx.gas_limit, 796584);
assert!(!deposit_tx.is_system_transaction);
} else {
panic!("Expected Deposit transaction");
}
}
#[test]
fn optimism_deposit_tx_conversion_mint() {
let input = r#"{
"blockHash": "0x7194f63b105e93fb1a27c50d23d62e422d4185a68536c55c96284911415699b2",
"blockNumber": "0x73a82cc",
"depositReceiptVersion": "0x1",
"from": "0x36bde71c97b33cc4729cf772ae268934f7ab70b2",
"gas": "0x7812e",
"gasPrice": "0x0",
"hash": "0xf7e83886d3c6864f78e01c453ebcd57020c5795d96089e8f0e0b90a467246ddb",
"input":
"0xd764ad0b000100000000000000000000000000000000000000000000000000000001cf5f00000000000000000000000099c9fc46f92e8a1c0dec1b1747d010903e884be100000000000000000000000042000000000000000000000000000000000000100000000000000000000000000000000000000000000000239c2e16a5ca5900000000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e41635f5fd0000000000000000000000002ce910fbba65b454bbaf6a18c952a70f3bcd82990000000000000000000000002ce910fbba65b454bbaf6a18c952a70f3bcd82990000000000000000000000000000000000000000000000239c2e16a5ca590000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
, "mint": "0x239c2e16a5ca590000",
"nonce": "0x7406b",
"r": "0x0",
"s": "0x0",
"sourceHash": "0xe0358cd2b2686d297c5c859646a613124a874fb9d9c4a2c88636a46a65c06e48",
"to": "0x4200000000000000000000000000000000000007",
"transactionIndex": "0x1",
"type": "0x7e",
"v": "0x0",
"value": "0x239c2e16a5ca590000"
}"#;
let alloy_tx: WithOtherFields<alloy_rpc_types::Transaction<AnyTxEnvelope>> =
serde_json::from_str(input).expect("failed to deserialize");
let TransactionSigned { transaction: reth_tx, .. } =
alloy_tx.try_into().expect("failed to convert");
if let Transaction::Deposit(deposit_tx) = reth_tx {
assert_eq!(
deposit_tx.source_hash,
"0xe0358cd2b2686d297c5c859646a613124a874fb9d9c4a2c88636a46a65c06e48"
.parse::<B256>()
.unwrap()
);
assert_eq!(
deposit_tx.from,
"0x36bde71c97b33cc4729cf772ae268934f7ab70b2".parse::<Address>().unwrap()
);
assert_eq!(
deposit_tx.to,
TxKind::from(address!("4200000000000000000000000000000000000007"))
);
assert_eq!(deposit_tx.mint, Some(656890000000000000000));
assert_eq!(deposit_tx.value, U256::from(0x239c2e16a5ca590000_u128));
assert_eq!(deposit_tx.gas_limit, 491822);
assert!(!deposit_tx.is_system_transaction);
} else {
panic!("Expected Deposit transaction");
}
}
}

View File

@ -1,4 +1,4 @@
use crate::TransactionSigned;
use reth_ethereum_primitives::TransactionSigned;
#[cfg(any(test, feature = "arbitrary"))]
pub use reth_primitives_traits::test_utils::{generate_valid_header, valid_header_strategy};

View File

@ -21,8 +21,6 @@
extern crate alloc;
#[cfg(feature = "alloy-compat")]
mod alloy_compat;
mod block;
pub mod proofs;
mod receipt;
@ -69,7 +67,6 @@ pub use c_kzg as kzg;
/// Read more: <https://github.com/bincode-org/bincode/issues/326>
#[cfg(feature = "serde-bincode-compat")]
pub mod serde_bincode_compat {
pub use super::transaction::{serde_bincode_compat as transaction, serde_bincode_compat::*};
pub use reth_primitives_traits::serde_bincode_compat::*;
}

View File

@ -1,6 +1,7 @@
//! Helper function for calculating Merkle proofs and hashes.
use crate::Receipt;
use alloy_consensus::TxReceipt;
use alloy_eips::eip2718::Encodable2718;
use alloy_primitives::B256;
pub use alloy_trie::root::ordered_trie_root_with_encoder;
@ -31,20 +32,15 @@ pub fn calculate_receipt_root_no_memo(receipts: &[&Receipt]) -> B256 {
#[cfg(test)]
mod tests {
use super::*;
use crate::Block;
use crate::{Block, TxType};
use alloy_consensus::EMPTY_ROOT_HASH;
use alloy_genesis::GenesisAccount;
use alloy_primitives::{b256, hex_literal::hex, Address, U256};
use alloy_primitives::{b256, bloom, hex_literal::hex, Address, Log, LogData, U256};
use alloy_rlp::Decodable;
use reth_chainspec::{HOLESKY, MAINNET, SEPOLIA};
use reth_trie_common::root::{state_root_ref_unhashed, state_root_unhashed};
use std::collections::HashMap;
#[cfg(not(feature = "optimism"))]
use crate::TxType;
#[cfg(not(feature = "optimism"))]
use alloy_primitives::{bloom, Log, LogData};
#[test]
fn check_transaction_root() {
let data = &hex!("f90262f901f9a092230ce5476ae868e98c7979cfc165a93f8b6ad1922acf2df62e340916efd49da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa02307107a867056ca33b5087e77c4174f47625e48fb49f1c70ced34890ddd88f3a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba0c598f69a5674cae9337261b669970e24abc0b46e6d284372a239ec8ccbf20b0ab901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018502540be40082a8618203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0");
@ -55,7 +51,6 @@ mod tests {
assert_eq!(block.transactions_root, tx_root, "Must be the same");
}
#[cfg(not(feature = "optimism"))]
#[test]
fn check_receipt_root_optimism() {
use alloy_consensus::ReceiptWithBloom;

View File

@ -1,287 +1,13 @@
use alloc::{vec, vec::Vec};
use reth_primitives_traits::InMemorySize;
use alloy_consensus::{
Eip2718EncodableReceipt, Eip658Value, ReceiptWithBloom, RlpDecodableReceipt,
RlpEncodableReceipt, TxReceipt, Typed2718,
};
use alloy_primitives::{Bloom, Log, B256};
use alloy_rlp::{Decodable, Encodable, Header, RlpDecodable, RlpEncodable};
use bytes::BufMut;
use alloy_primitives::B256;
use derive_more::{DerefMut, From, IntoIterator};
use serde::{Deserialize, Serialize};
use crate::TxType;
/// Retrieves gas spent by transactions as a vector of tuples (transaction index, gas used).
pub use reth_primitives_traits::receipt::gas_spent_by_transactions;
/// Receipt containing result of transaction execution.
#[derive(
Clone, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable, Serialize, Deserialize,
)]
#[cfg_attr(any(test, feature = "reth-codec"), derive(reth_codecs::CompactZstd))]
#[cfg_attr(any(test, feature = "reth-codec"), reth_zstd(
compressor = reth_zstd_compressors::RECEIPT_COMPRESSOR,
decompressor = reth_zstd_compressors::RECEIPT_DECOMPRESSOR
))]
#[rlp(trailing)]
pub struct Receipt {
/// Receipt type.
pub tx_type: TxType,
/// If transaction is executed successfully.
///
/// This is the `statusCode`
pub success: bool,
/// Gas used
pub cumulative_gas_used: u64,
/// Log send from contracts.
pub logs: Vec<Log>,
/// Deposit nonce for Optimism deposit transactions
#[cfg(feature = "optimism")]
pub deposit_nonce: Option<u64>,
/// Deposit receipt version for Optimism deposit transactions
///
///
/// The deposit receipt version was introduced in Canyon to indicate an update to how
/// receipt hashes should be computed when set. The state transition process
/// ensures this is only set for post-Canyon deposit transactions.
#[cfg(feature = "optimism")]
pub deposit_receipt_version: Option<u64>,
}
impl Receipt {
/// Calculates [`Log`]'s bloom filter. this is slow operation and [`ReceiptWithBloom`] can
/// be used to cache this value.
pub fn bloom_slow(&self) -> Bloom {
alloy_primitives::logs_bloom(self.logs.iter())
}
/// Calculates the bloom filter for the receipt and returns the [`ReceiptWithBloom`] container
/// type.
pub fn with_bloom(self) -> ReceiptWithBloom<Self> {
self.into()
}
/// Calculates the bloom filter for the receipt and returns the [`ReceiptWithBloom`]
/// container type.
pub fn with_bloom_ref(&self) -> ReceiptWithBloom<&Self> {
self.into()
}
/// Returns length of RLP-encoded receipt fields with the given [`Bloom`] without an RLP header.
pub fn rlp_encoded_fields_length(&self, bloom: &Bloom) -> usize {
let len = self.success.length() +
self.cumulative_gas_used.length() +
bloom.length() +
self.logs.length();
#[cfg(feature = "optimism")]
if self.tx_type == TxType::Deposit {
let mut len = len;
if let Some(deposit_nonce) = self.deposit_nonce {
len += deposit_nonce.length();
}
if let Some(deposit_receipt_version) = self.deposit_receipt_version {
len += deposit_receipt_version.length();
}
return len
}
len
}
/// RLP-encodes receipt fields with the given [`Bloom`] without an RLP header.
pub fn rlp_encode_fields(&self, bloom: &Bloom, out: &mut dyn BufMut) {
self.success.encode(out);
self.cumulative_gas_used.encode(out);
bloom.encode(out);
self.logs.encode(out);
#[cfg(feature = "optimism")]
if self.tx_type == TxType::Deposit {
if let Some(nonce) = self.deposit_nonce {
nonce.encode(out);
}
if let Some(version) = self.deposit_receipt_version {
version.encode(out);
}
}
}
/// Returns RLP header for inner encoding.
pub fn rlp_header_inner(&self, bloom: &Bloom) -> Header {
Header { list: true, payload_length: self.rlp_encoded_fields_length(bloom) }
}
fn decode_receipt_with_bloom(
buf: &mut &[u8],
tx_type: TxType,
) -> alloy_rlp::Result<ReceiptWithBloom<Self>> {
let b = &mut &**buf;
let rlp_head = alloy_rlp::Header::decode(b)?;
if !rlp_head.list {
return Err(alloy_rlp::Error::UnexpectedString)
}
let started_len = b.len();
let success = Decodable::decode(b)?;
let cumulative_gas_used = Decodable::decode(b)?;
let bloom = Decodable::decode(b)?;
let logs = Decodable::decode(b)?;
let receipt = match tx_type {
#[cfg(feature = "optimism")]
TxType::Deposit => {
let remaining = |b: &[u8]| rlp_head.payload_length - (started_len - b.len()) > 0;
let deposit_nonce = remaining(b).then(|| Decodable::decode(b)).transpose()?;
let deposit_receipt_version =
remaining(b).then(|| Decodable::decode(b)).transpose()?;
Self {
tx_type,
success,
cumulative_gas_used,
logs,
deposit_nonce,
deposit_receipt_version,
}
}
_ => Self {
tx_type,
success,
cumulative_gas_used,
logs,
#[cfg(feature = "optimism")]
deposit_nonce: None,
#[cfg(feature = "optimism")]
deposit_receipt_version: None,
},
};
let this = ReceiptWithBloom { receipt, logs_bloom: bloom };
let consumed = started_len - b.len();
if consumed != rlp_head.payload_length {
return Err(alloy_rlp::Error::ListLengthMismatch {
expected: rlp_head.payload_length,
got: consumed,
})
}
*buf = *b;
Ok(this)
}
}
impl Eip2718EncodableReceipt for Receipt {
fn eip2718_encoded_length_with_bloom(&self, bloom: &Bloom) -> usize {
self.rlp_header_inner(bloom).length_with_payload() +
!matches!(self.tx_type, TxType::Legacy) as usize // account for type prefix
}
fn eip2718_encode_with_bloom(&self, bloom: &Bloom, out: &mut dyn BufMut) {
if !matches!(self.tx_type, TxType::Legacy) {
out.put_u8(self.tx_type as u8);
}
self.rlp_header_inner(bloom).encode(out);
self.rlp_encode_fields(bloom, out);
}
}
impl RlpEncodableReceipt for Receipt {
fn rlp_encoded_length_with_bloom(&self, bloom: &Bloom) -> usize {
let mut len = self.eip2718_encoded_length_with_bloom(bloom);
if !matches!(self.tx_type, TxType::Legacy) {
len += Header {
list: false,
payload_length: self.eip2718_encoded_length_with_bloom(bloom),
}
.length();
}
len
}
fn rlp_encode_with_bloom(&self, bloom: &Bloom, out: &mut dyn BufMut) {
if !matches!(self.tx_type, TxType::Legacy) {
Header { list: false, payload_length: self.eip2718_encoded_length_with_bloom(bloom) }
.encode(out);
}
self.eip2718_encode_with_bloom(bloom, out);
}
}
impl RlpDecodableReceipt for Receipt {
fn rlp_decode_with_bloom(buf: &mut &[u8]) -> alloy_rlp::Result<ReceiptWithBloom<Self>> {
let header_buf = &mut &**buf;
let header = Header::decode(header_buf)?;
if header.list {
return Self::decode_receipt_with_bloom(buf, TxType::Legacy);
}
*buf = *header_buf;
let remaining = buf.len();
let tx_type = TxType::decode(buf)?;
let this = Self::decode_receipt_with_bloom(buf, tx_type)?;
if buf.len() + header.payload_length != remaining {
return Err(alloy_rlp::Error::UnexpectedLength);
}
Ok(this)
}
}
impl TxReceipt for Receipt {
type Log = Log;
fn status_or_post_state(&self) -> Eip658Value {
self.success.into()
}
fn status(&self) -> bool {
self.success
}
fn bloom(&self) -> Bloom {
alloy_primitives::logs_bloom(self.logs.iter())
}
fn cumulative_gas_used(&self) -> u64 {
self.cumulative_gas_used
}
fn logs(&self) -> &[Log] {
&self.logs
}
}
impl Typed2718 for Receipt {
fn ty(&self) -> u8 {
self.tx_type as u8
}
}
impl reth_primitives_traits::Receipt for Receipt {}
impl InMemorySize for Receipt {
/// Calculates a heuristic for the in-memory size of the [Receipt].
#[inline]
fn size(&self) -> usize {
let total_size = self.tx_type.size() +
core::mem::size_of::<bool>() +
core::mem::size_of::<u64>() +
self.logs.capacity() * core::mem::size_of::<Log>();
#[cfg(feature = "optimism")]
return total_size + 2 * core::mem::size_of::<Option<u64>>();
#[cfg(not(feature = "optimism"))]
total_size
}
}
pub use reth_ethereum_primitives::Receipt;
/// A collection of receipts organized as a two-dimensional vector.
#[derive(
@ -342,248 +68,3 @@ impl<T> Default for Receipts<T> {
Self { receipt_vec: Vec::new() }
}
}
#[cfg(any(test, feature = "arbitrary"))]
impl<'a> arbitrary::Arbitrary<'a> for Receipt {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
let tx_type = TxType::arbitrary(u)?;
let success = bool::arbitrary(u)?;
let cumulative_gas_used = u64::arbitrary(u)?;
let logs = Vec::<Log>::arbitrary(u)?;
// Only receipts for deposit transactions may contain a deposit nonce
#[cfg(feature = "optimism")]
let (deposit_nonce, deposit_receipt_version) = if tx_type == TxType::Deposit {
let deposit_nonce = Option::<u64>::arbitrary(u)?;
let deposit_nonce_version =
deposit_nonce.map(|_| Option::<u64>::arbitrary(u)).transpose()?.flatten();
(deposit_nonce, deposit_nonce_version)
} else {
(None, None)
};
Ok(Self {
tx_type,
success,
cumulative_gas_used,
logs,
#[cfg(feature = "optimism")]
deposit_nonce,
#[cfg(feature = "optimism")]
deposit_receipt_version,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_eips::eip2718::Encodable2718;
use alloy_primitives::{address, b256, bytes, hex_literal::hex, Bytes};
use reth_codecs::Compact;
#[test]
fn test_decode_receipt() {
#[cfg(not(feature = "optimism"))]
reth_codecs::test_utils::test_decode::<Receipt>(&hex!(
"c428b52ffd23fc42696156b10200f034792b6a94c3850215c2fef7aea361a0c31b79d9a32652eefc0d4e2e730036061cff7344b6fc6132b50cda0ed810a991ae58ef013150c12b2522533cb3b3a8b19b7786a8b5ff1d3cdc84225e22b02def168c8858df"
));
#[cfg(feature = "optimism")]
reth_codecs::test_utils::test_decode::<Receipt>(&hex!(
"c30328b52ffd23fc426961a00105007eb0042307705a97e503562eacf2b95060cce9de6de68386b6c155b73a9650021a49e2f8baad17f30faff5899d785c4c0873e45bc268bcf07560106424570d11f9a59e8f3db1efa4ceec680123712275f10d92c3411e1caaa11c7c5d591bc11487168e09934a9986848136da1b583babf3a7188e3aed007a1520f1cf4c1ca7d3482c6c28d37c298613c70a76940008816c4c95644579fd08471dc34732fd0f24"
));
}
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
#[test]
fn encode_legacy_receipt() {
let expected = hex!("f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff");
let mut data = Vec::with_capacity(expected.length());
let receipt = ReceiptWithBloom {
receipt: Receipt {
tx_type: TxType::Legacy,
cumulative_gas_used: 0x1u64,
logs: vec![Log::new_unchecked(
address!("0000000000000000000000000000000000000011"),
vec![
b256!("000000000000000000000000000000000000000000000000000000000000dead"),
b256!("000000000000000000000000000000000000000000000000000000000000beef"),
],
bytes!("0100ff"),
)],
success: false,
#[cfg(feature = "optimism")]
deposit_nonce: None,
#[cfg(feature = "optimism")]
deposit_receipt_version: None,
},
logs_bloom: [0; 256].into(),
};
receipt.encode(&mut data);
// check that the rlp length equals the length of the expected rlp
assert_eq!(receipt.length(), expected.len());
assert_eq!(data, expected);
}
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
#[test]
fn decode_legacy_receipt() {
let data = hex!("f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff");
// EIP658Receipt
let expected = ReceiptWithBloom {
receipt: Receipt {
tx_type: TxType::Legacy,
cumulative_gas_used: 0x1u64,
logs: vec![Log::new_unchecked(
address!("0000000000000000000000000000000000000011"),
vec![
b256!("000000000000000000000000000000000000000000000000000000000000dead"),
b256!("000000000000000000000000000000000000000000000000000000000000beef"),
],
bytes!("0100ff"),
)],
success: false,
#[cfg(feature = "optimism")]
deposit_nonce: None,
#[cfg(feature = "optimism")]
deposit_receipt_version: None,
},
logs_bloom: [0; 256].into(),
};
let receipt = ReceiptWithBloom::decode(&mut &data[..]).unwrap();
assert_eq!(receipt, expected);
}
#[cfg(feature = "optimism")]
#[test]
fn decode_deposit_receipt_regolith_roundtrip() {
let data = hex!("b901107ef9010c0182b741b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0833d3bbf");
// Deposit Receipt (post-regolith)
let expected = ReceiptWithBloom {
receipt: Receipt {
tx_type: TxType::Deposit,
cumulative_gas_used: 46913,
logs: vec![],
success: true,
deposit_nonce: Some(4012991),
deposit_receipt_version: None,
},
logs_bloom: [0; 256].into(),
};
let receipt = ReceiptWithBloom::decode(&mut &data[..]).unwrap();
assert_eq!(receipt, expected);
let mut buf = Vec::with_capacity(data.len());
receipt.encode(&mut buf);
assert_eq!(buf, &data[..]);
}
#[cfg(feature = "optimism")]
#[test]
fn decode_deposit_receipt_canyon_roundtrip() {
let data = hex!("b901117ef9010d0182b741b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0833d3bbf01");
// Deposit Receipt (post-regolith)
let expected = ReceiptWithBloom {
receipt: Receipt {
tx_type: TxType::Deposit,
cumulative_gas_used: 46913,
logs: vec![],
success: true,
deposit_nonce: Some(4012991),
deposit_receipt_version: Some(1),
},
logs_bloom: [0; 256].into(),
};
let receipt = ReceiptWithBloom::decode(&mut &data[..]).unwrap();
assert_eq!(receipt, expected);
let mut buf = Vec::with_capacity(data.len());
expected.encode(&mut buf);
assert_eq!(buf, &data[..]);
}
#[test]
fn gigantic_receipt() {
let receipt = Receipt {
cumulative_gas_used: 16747627,
success: true,
tx_type: TxType::Legacy,
logs: vec![
Log::new_unchecked(
address!("4bf56695415f725e43c3e04354b604bcfb6dfb6e"),
vec![b256!("c69dc3d7ebff79e41f525be431d5cd3cc08f80eaf0f7819054a726eeb7086eb9")],
Bytes::from(vec![1; 0xffffff]),
),
Log::new_unchecked(
address!("faca325c86bf9c2d5b413cd7b90b209be92229c2"),
vec![b256!("8cca58667b1e9ffa004720ac99a3d61a138181963b294d270d91c53d36402ae2")],
Bytes::from(vec![1; 0xffffff]),
),
],
#[cfg(feature = "optimism")]
deposit_nonce: None,
#[cfg(feature = "optimism")]
deposit_receipt_version: None,
};
let mut data = vec![];
receipt.to_compact(&mut data);
let (decoded, _) = Receipt::from_compact(&data[..], data.len());
assert_eq!(decoded, receipt);
}
#[test]
fn test_encode_2718_length() {
let receipt = ReceiptWithBloom {
receipt: Receipt {
tx_type: TxType::Eip1559,
success: true,
cumulative_gas_used: 21000,
logs: vec![],
#[cfg(feature = "optimism")]
deposit_nonce: None,
#[cfg(feature = "optimism")]
deposit_receipt_version: None,
},
logs_bloom: Bloom::default(),
};
let encoded = receipt.encoded_2718();
assert_eq!(
encoded.len(),
receipt.encode_2718_len(),
"Encoded length should match the actual encoded data length"
);
// Test for legacy receipt as well
let legacy_receipt = ReceiptWithBloom {
receipt: Receipt {
tx_type: TxType::Legacy,
success: true,
cumulative_gas_used: 21000,
logs: vec![],
#[cfg(feature = "optimism")]
deposit_nonce: None,
#[cfg(feature = "optimism")]
deposit_receipt_version: None,
},
logs_bloom: Bloom::default(),
};
let legacy_encoded = legacy_receipt.encoded_2718();
assert_eq!(
legacy_encoded.len(),
legacy_receipt.encode_2718_len(),
"Encoded length for legacy receipt should match the actual encoded data length"
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -12,10 +12,9 @@ mod tests {
use super::*;
use alloy_consensus::{transaction::RlpEcdsaTx, Transaction as _, TxLegacy};
use alloy_eips::eip2718::Decodable2718;
use alloy_primitives::{address, hex};
use alloy_primitives::{address, hex, Bytes};
use alloy_rlp::Decodable;
use assert_matches::assert_matches;
use bytes::Bytes;
#[test]
fn invalid_legacy_pooled_decoding_input_too_short() {

View File

@ -1,16 +1,3 @@
use alloy_consensus::{
constants::{
EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID,
LEGACY_TX_TYPE_ID,
},
Typed2718,
};
use alloy_primitives::{U64, U8};
use alloy_rlp::{Decodable, Encodable};
use derive_more::Display;
use reth_primitives_traits::InMemorySize;
use serde::{Deserialize, Serialize};
/// Transaction Type
///
/// Currently being used as 2-bit type when encoding it to `reth_codecs::Compact` on
@ -18,292 +5,4 @@ use serde::{Deserialize, Serialize};
/// database format.
///
/// 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,
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,
}
impl TxType {
/// The max type reserved by an EIP.
pub const MAX_RESERVED_EIP: Self = Self::Eip7702;
/// Check if the transaction type has an access list.
pub const fn has_access_list(&self) -> bool {
match self {
Self::Legacy => false,
Self::Eip2930 | Self::Eip1559 | Self::Eip4844 | Self::Eip7702 => true,
#[cfg(feature = "optimism")]
Self::Deposit => false,
}
}
}
impl Typed2718 for TxType {
fn ty(&self) -> u8 {
(*self).into()
}
}
impl InMemorySize for TxType {
/// Calculates a heuristic for the in-memory size of the [`TxType`].
#[inline]
fn size(&self) -> usize {
core::mem::size_of::<Self>()
}
}
impl From<TxType> for u8 {
fn from(value: TxType) -> Self {
match value {
TxType::Legacy => LEGACY_TX_TYPE_ID,
TxType::Eip2930 => EIP2930_TX_TYPE_ID,
TxType::Eip1559 => EIP1559_TX_TYPE_ID,
TxType::Eip4844 => EIP4844_TX_TYPE_ID,
TxType::Eip7702 => EIP7702_TX_TYPE_ID,
#[cfg(feature = "optimism")]
TxType::Deposit => op_alloy_consensus::DEPOSIT_TX_TYPE_ID,
}
}
}
impl From<TxType> for U8 {
fn from(value: TxType) -> Self {
Self::from(u8::from(value))
}
}
impl TryFrom<u8> for TxType {
type Error = &'static str;
fn try_from(value: u8) -> Result<Self, Self::Error> {
#[cfg(feature = "optimism")]
if value == Self::Deposit {
return Ok(Self::Deposit)
}
if value == Self::Legacy {
return Ok(Self::Legacy)
} else if value == Self::Eip2930 {
return Ok(Self::Eip2930)
} else if value == Self::Eip1559 {
return Ok(Self::Eip1559)
} else if value == Self::Eip4844 {
return Ok(Self::Eip4844)
} else if value == Self::Eip7702 {
return Ok(Self::Eip7702)
}
Err("invalid tx type")
}
}
impl TryFrom<u64> for TxType {
type Error = &'static str;
fn try_from(value: u64) -> Result<Self, Self::Error> {
let value: u8 = value.try_into().map_err(|_| "invalid tx type")?;
Self::try_from(value)
}
}
impl TryFrom<U64> for TxType {
type Error = &'static str;
fn try_from(value: U64) -> Result<Self, Self::Error> {
value.to::<u64>().try_into()
}
}
#[cfg(any(test, feature = "reth-codec"))]
impl reth_codecs::Compact for TxType {
fn to_compact<B>(&self, buf: &mut B) -> usize
where
B: bytes::BufMut + AsMut<[u8]>,
{
use reth_codecs::txtype::*;
match self {
Self::Legacy => COMPACT_IDENTIFIER_LEGACY,
Self::Eip2930 => COMPACT_IDENTIFIER_EIP2930,
Self::Eip1559 => COMPACT_IDENTIFIER_EIP1559,
Self::Eip4844 => {
buf.put_u8(EIP4844_TX_TYPE_ID);
COMPACT_EXTENDED_IDENTIFIER_FLAG
}
Self::Eip7702 => {
buf.put_u8(EIP7702_TX_TYPE_ID);
COMPACT_EXTENDED_IDENTIFIER_FLAG
}
#[cfg(feature = "optimism")]
Self::Deposit => {
buf.put_u8(op_alloy_consensus::DEPOSIT_TX_TYPE_ID);
COMPACT_EXTENDED_IDENTIFIER_FLAG
}
}
}
// For backwards compatibility purposes only 2 bits of the type are encoded in the identifier
// parameter. In the case of a [`COMPACT_EXTENDED_IDENTIFIER_FLAG`], the full transaction type
// is read from the buffer as a single byte.
fn from_compact(mut buf: &[u8], identifier: usize) -> (Self, &[u8]) {
use bytes::Buf;
(
match identifier {
reth_codecs::txtype::COMPACT_IDENTIFIER_LEGACY => Self::Legacy,
reth_codecs::txtype::COMPACT_IDENTIFIER_EIP2930 => Self::Eip2930,
reth_codecs::txtype::COMPACT_IDENTIFIER_EIP1559 => Self::Eip1559,
reth_codecs::txtype::COMPACT_EXTENDED_IDENTIFIER_FLAG => {
let extended_identifier = buf.get_u8();
match extended_identifier {
EIP4844_TX_TYPE_ID => Self::Eip4844,
EIP7702_TX_TYPE_ID => Self::Eip7702,
#[cfg(feature = "optimism")]
op_alloy_consensus::DEPOSIT_TX_TYPE_ID => Self::Deposit,
_ => panic!("Unsupported TxType identifier: {extended_identifier}"),
}
}
_ => panic!("Unknown identifier for TxType: {identifier}"),
},
buf,
)
}
}
impl PartialEq<u8> for TxType {
fn eq(&self, other: &u8) -> bool {
*self as u8 == *other
}
}
impl PartialEq<TxType> for u8 {
fn eq(&self, other: &TxType) -> bool {
*self == *other as Self
}
}
impl Encodable for TxType {
fn encode(&self, out: &mut dyn bytes::BufMut) {
(*self as u8).encode(out);
}
fn length(&self) -> usize {
1
}
}
impl Decodable for TxType {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
let ty = u8::decode(buf)?;
Self::try_from(ty).map_err(alloy_rlp::Error::Custom)
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_primitives::hex;
use reth_codecs::{txtype::*, Compact};
use rstest::rstest;
#[rstest]
#[case(U64::from(LEGACY_TX_TYPE_ID), Ok(TxType::Legacy))]
#[case(U64::from(EIP2930_TX_TYPE_ID), Ok(TxType::Eip2930))]
#[case(U64::from(EIP1559_TX_TYPE_ID), Ok(TxType::Eip1559))]
#[case(U64::from(EIP4844_TX_TYPE_ID), Ok(TxType::Eip4844))]
#[case(U64::from(EIP7702_TX_TYPE_ID), Ok(TxType::Eip7702))]
#[cfg_attr(
feature = "optimism",
case(U64::from(op_alloy_consensus::DEPOSIT_TX_TYPE_ID), Ok(TxType::Deposit))
)]
#[case(U64::MAX, Err("invalid tx type"))]
fn test_u64_to_tx_type(#[case] input: U64, #[case] expected: Result<TxType, &'static str>) {
let tx_type_result = TxType::try_from(input);
assert_eq!(tx_type_result, expected);
}
#[rstest]
#[case(TxType::Legacy, COMPACT_IDENTIFIER_LEGACY, vec![])]
#[case(TxType::Eip2930, COMPACT_IDENTIFIER_EIP2930, vec![])]
#[case(TxType::Eip1559, COMPACT_IDENTIFIER_EIP1559, vec![])]
#[case(TxType::Eip4844, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![EIP4844_TX_TYPE_ID])]
#[case(TxType::Eip7702, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![EIP7702_TX_TYPE_ID])]
#[cfg_attr(feature = "optimism", case(TxType::Deposit, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![op_alloy_consensus::DEPOSIT_TX_TYPE_ID]))]
fn test_txtype_to_compact(
#[case] tx_type: TxType,
#[case] expected_identifier: usize,
#[case] expected_buf: Vec<u8>,
) {
let mut buf = vec![];
let identifier = tx_type.to_compact(&mut buf);
assert_eq!(identifier, expected_identifier, "Unexpected identifier for TxType {tx_type:?}",);
assert_eq!(buf, expected_buf, "Unexpected buffer for TxType {tx_type:?}",);
}
#[rstest]
#[case(TxType::Legacy, COMPACT_IDENTIFIER_LEGACY, vec![])]
#[case(TxType::Eip2930, COMPACT_IDENTIFIER_EIP2930, vec![])]
#[case(TxType::Eip1559, COMPACT_IDENTIFIER_EIP1559, vec![])]
#[case(TxType::Eip4844, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![EIP4844_TX_TYPE_ID])]
#[case(TxType::Eip7702, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![EIP7702_TX_TYPE_ID])]
#[cfg_attr(feature = "optimism", case(TxType::Deposit, COMPACT_EXTENDED_IDENTIFIER_FLAG, vec![op_alloy_consensus::DEPOSIT_TX_TYPE_ID]))]
fn test_txtype_from_compact(
#[case] expected_type: TxType,
#[case] identifier: usize,
#[case] buf: Vec<u8>,
) {
let (actual_type, remaining_buf) = TxType::from_compact(&buf, identifier);
assert_eq!(actual_type, expected_type, "Unexpected TxType for identifier {identifier}");
assert!(remaining_buf.is_empty(), "Buffer not fully consumed for identifier {identifier}");
}
#[rstest]
#[case(&hex!("80"), Ok(TxType::Legacy))]
#[case(&[EIP2930_TX_TYPE_ID], Ok(TxType::Eip2930))]
#[case(&[EIP1559_TX_TYPE_ID], Ok(TxType::Eip1559))]
#[case(&[EIP4844_TX_TYPE_ID], Ok(TxType::Eip4844))]
#[case(&[EIP7702_TX_TYPE_ID], Ok(TxType::Eip7702))]
#[case(&[u8::MAX], Err(alloy_rlp::Error::InputTooShort))]
#[cfg_attr(feature = "optimism", case(&[op_alloy_consensus::DEPOSIT_TX_TYPE_ID], Ok(TxType::Deposit)))]
fn decode_tx_type(#[case] input: &[u8], #[case] expected: Result<TxType, alloy_rlp::Error>) {
let tx_type_result = TxType::decode(&mut &input[..]);
assert_eq!(tx_type_result, expected)
}
}
pub use alloy_consensus::TxType;

View File

@ -117,6 +117,7 @@ mod tests {
Itertools,
};
use reth_db::tables;
use reth_primitives_traits::SignedTransaction;
use reth_provider::{DatabaseProviderFactory, PruneCheckpointReader};
use reth_prune_types::{
PruneCheckpoint, PruneInterruptReason, PruneMode, PruneProgress, PruneSegment,
@ -141,7 +142,7 @@ mod tests {
for block in &blocks {
tx_hash_numbers.reserve_exact(block.transaction_count());
for transaction in &block.body().transactions {
tx_hash_numbers.push((transaction.hash(), tx_hash_numbers.len() as u64));
tx_hash_numbers.push((*transaction.tx_hash(), tx_hash_numbers.len() as u64));
}
}
let tx_hash_numbers_len = tx_hash_numbers.len();

View File

@ -37,7 +37,7 @@ use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
use reth_tasks::pool::BlockingTaskGuard;
use revm::{
db::{CacheDB, State},
primitives::{db::DatabaseCommit, Env},
primitives::db::DatabaseCommit,
};
use revm_inspectors::tracing::{
FourByteInspector, MuxInspector, TracingInspector, TracingInspectorConfig, TransactionContext,
@ -450,7 +450,7 @@ where
tx_env.clone(),
&mut inspector,
)?;
let env = Env::boxed(
let env = revm_primitives::Env::boxed(
evm_env.cfg_env_with_handler_cfg.cfg_env,
evm_env.block_env,
tx_env,
@ -785,7 +785,7 @@ where
self.eth_api().inspect(&mut *db, evm_env, tx_env, &mut inspector)?;
let state = res.state.clone();
let env = Env::boxed(
let env = revm_primitives::Env::boxed(
evm_env.cfg_env_with_handler_cfg.cfg_env,
evm_env.block_env,
tx_env,

View File

@ -1,6 +1,6 @@
//! `Eth` bundle implementation and helpers.
use alloy_consensus::{BlockHeader, Transaction as _};
use alloy_consensus::{BlockHeader, EnvKzgSettings, Transaction as _};
use alloy_eips::eip4844::MAX_DATA_GAS_PER_BLOCK;
use alloy_primitives::{Keccak256, U256};
use alloy_rpc_types_mev::{EthCallBundle, EthCallBundleResponse, EthCallBundleTransactionResult};
@ -23,7 +23,7 @@ use revm::{
db::{CacheDB, DatabaseCommit, DatabaseRef},
primitives::ResultAndState,
};
use revm_primitives::{EnvKzgSettings, SpecId};
use revm_primitives::SpecId;
use std::sync::Arc;
/// `Eth` bundle implementation.

View File

@ -1,6 +1,6 @@
//! Support for building a pending block with transactions from local view of mempool.
use alloy_consensus::{constants::EMPTY_WITHDRAWALS, Header, EMPTY_OMMER_ROOT_HASH};
use alloy_consensus::{constants::EMPTY_WITHDRAWALS, Header, Transaction, EMPTY_OMMER_ROOT_HASH};
use alloy_eips::{eip7685::EMPTY_REQUESTS_HASH, merge::BEACON_NONCE};
use alloy_primitives::U256;
use reth_chainspec::{EthChainSpec, EthereumHardforks};

View File

@ -6,6 +6,7 @@ use alloy_primitives::PrimitiveSignature as Signature;
use alloy_rpc_types::TransactionRequest;
use alloy_rpc_types_eth::{Transaction, TransactionInfo};
use reth_primitives::{RecoveredTx, TransactionSigned};
use reth_primitives_traits::SignedTransaction;
use reth_rpc_eth_api::EthApiTypes;
use reth_rpc_eth_types::EthApiError;
use reth_rpc_types_compat::TransactionCompat;
@ -43,7 +44,7 @@ where
tx_info: TransactionInfo,
) -> Result<Self::Transaction, Self::Error> {
let from = tx.signer();
let hash = tx.hash();
let hash = *tx.tx_hash();
let TransactionSigned { transaction, signature, .. } = tx.into_tx();
let inner: TxEnvelope = match transaction {

View File

@ -220,6 +220,7 @@ mod tests {
models::StoredBlockBodyIndices,
};
use reth_primitives::SealedBlock;
use reth_primitives_traits::SignedTransaction;
use reth_provider::providers::StaticFileWriter;
use reth_testing_utils::generators::{
self, random_block_range, random_contract_account_range, BlockRangeParams,
@ -356,7 +357,7 @@ mod tests {
progress.body().transactions.iter().try_for_each(
|transaction| -> Result<(), reth_db::DatabaseError> {
tx.put::<tables::TransactionHashNumbers>(
transaction.hash(),
*transaction.tx_hash(),
next_tx_num,
)?;
tx.put::<tables::Transactions>(next_tx_num, transaction.clone())?;

View File

@ -387,7 +387,7 @@ mod tests {
for block in &blocks[..=max_processed_block] {
for transaction in &block.body().transactions {
if block.number > max_pruned_block {
tx_hash_numbers.push((transaction.hash(), tx_hash_number));
tx_hash_numbers.push((*transaction.tx_hash(), tx_hash_number));
}
tx_hash_number += 1;
}
@ -552,7 +552,10 @@ mod tests {
for tx_id in body.tx_num_range() {
let transaction =
provider.transaction_by_id(tx_id)?.expect("no transaction entry");
assert_eq!(Some(tx_id), provider.transaction_id(transaction.hash())?);
assert_eq!(
Some(tx_id),
provider.transaction_id(*transaction.tx_hash())?
);
}
}
}

View File

@ -107,7 +107,7 @@ impl crate::Compact for OpTxType {
match extended_identifier {
EIP7702_TX_TYPE_ID => Self::Eip7702,
op_alloy_consensus::DEPOSIT_TX_TYPE_ID => Self::Deposit,
_ => panic!("Unsupported TxType identifier: {extended_identifier}"),
_ => panic!("Unsupported OpTxType identifier: {extended_identifier}"),
}
}
_ => panic!("Unknown identifier for TxType: {identifier}"),

View File

@ -87,7 +87,6 @@ arbitrary = [
"reth-optimism-primitives?/arbitrary"
]
optimism = [
"reth-primitives/optimism",
"reth-codecs/op",
"reth-optimism-primitives?/optimism",
"op",

View File

@ -112,7 +112,7 @@ arbitrary = [
"reth-stages-types/arbitrary",
"alloy-consensus/arbitrary",
]
optimism = ["reth-primitives/optimism", "reth-db-api/optimism"]
optimism = ["reth-db-api/optimism"]
op = ["reth-db-api/op"]
disable-lock = []

View File

@ -88,7 +88,6 @@ alloy-consensus.workspace = true
[features]
optimism = [
"reth-primitives/optimism",
"reth-execution-types/optimism",
"reth-optimism-primitives",
"reth-codecs/op",

View File

@ -2402,7 +2402,7 @@ mod tests {
let mut in_memory_blocks: std::collections::VecDeque<_> = in_memory_blocks.into();
$(
let tx_hash = |block: &SealedBlock| block.body().transactions[0].hash();
let tx_hash = |block: &SealedBlock| *block.body().transactions[0].tx_hash();
let tx_num = |block: &SealedBlock| {
database_blocks
.iter()
@ -2726,7 +2726,7 @@ mod tests {
// above, we do not see it.
assert!(matches!(
old_transaction_hash_fn(
to_be_persisted_tx.hash(),
*to_be_persisted_tx.tx_hash(),
provider.canonical_in_memory_state(),
provider.database.clone()
),
@ -2743,7 +2743,7 @@ mod tests {
assert!(matches!(
correct_transaction_hash_fn(
to_be_persisted_tx.hash(),
*to_be_persisted_tx.tx_hash(),
provider.canonical_in_memory_state(),
provider.database
),

View File

@ -708,7 +708,7 @@ mod tests {
if sender == block.body().transactions[0].recover_signer().unwrap()
);
assert_matches!(
provider.transaction_id(block.body().transactions[0].hash()),
provider.transaction_id(*block.body().transactions[0].tx_hash()),
Ok(Some(0))
);
}
@ -726,7 +726,10 @@ mod tests {
Ok(_)
);
assert_matches!(provider.transaction_sender(0), Ok(None));
assert_matches!(provider.transaction_id(block.body().transactions[0].hash()), Ok(None));
assert_matches!(
provider.transaction_id(*block.body().transactions[0].tx_hash()),
Ok(None)
);
}
}

View File

@ -253,7 +253,7 @@ impl TransactionsProvider for MockEthProvider {
let tx_number = lock
.values()
.flat_map(|block| &block.body.transactions)
.position(|tx| tx.hash() == tx_hash)
.position(|tx| *tx.tx_hash() == tx_hash)
.map(|pos| pos as TxNumber);
Ok(tx_number)
@ -280,7 +280,7 @@ impl TransactionsProvider for MockEthProvider {
fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<TransactionSigned>> {
Ok(self.blocks.lock().iter().find_map(|(_, block)| {
block.body.transactions.iter().find(|tx| tx.hash() == hash).cloned()
block.body.transactions.iter().find(|tx| *tx.tx_hash() == hash).cloned()
}))
}
@ -291,7 +291,7 @@ impl TransactionsProvider for MockEthProvider {
let lock = self.blocks.lock();
for (block_hash, block) in lock.iter() {
for (index, tx) in block.body.transactions.iter().enumerate() {
if tx.hash() == hash {
if *tx.tx_hash() == hash {
let meta = TransactionMeta {
tx_hash: hash,
index: index as u64,

View File

@ -1,10 +1,12 @@
use crate::EthPooledTransaction;
use alloy_consensus::{TxEip1559, TxEip4844, TxLegacy};
use alloy_consensus::{SignableTransaction, TxEip1559, TxEip4844, TxLegacy};
use alloy_eips::{eip1559::MIN_PROTOCOL_BASE_FEE, eip2718::Encodable2718, eip2930::AccessList};
use alloy_primitives::{Address, Bytes, TxKind, B256, U256};
use rand::Rng;
use reth_chainspec::MAINNET;
use reth_primitives::{Transaction, TransactionSigned};
use reth_primitives::{
transaction::SignedTransactionIntoRecoveredExt, Transaction, TransactionSigned,
};
use reth_primitives_traits::crypto::secp256k1::sign_message;
/// A generator for transactions for testing purposes.
@ -99,12 +101,12 @@ impl<R: Rng> TransactionGenerator<R> {
/// Generates and returns a pooled EIP-1559 transaction with a random signer.
pub fn gen_eip1559_pooled(&mut self) -> EthPooledTransaction {
self.gen_eip1559().into_ecrecovered().unwrap().try_into().unwrap()
self.gen_eip1559().try_into_ecrecovered().unwrap().try_into().unwrap()
}
/// Generates and returns a pooled EIP-4844 transaction with a random signer.
pub fn gen_eip4844_pooled(&mut self) -> EthPooledTransaction {
let tx = self.gen_eip4844().into_ecrecovered().unwrap();
let tx = self.gen_eip4844().try_into_ecrecovered().unwrap();
let encoded_length = tx.encode_2718_len();
EthPooledTransaction::new(tx, encoded_length)
}

View File

@ -32,7 +32,7 @@ use reth_primitives::{
transaction::{SignedTransactionIntoRecoveredExt, TryFromRecoveredTransactionError},
PooledTransaction, RecoveredTx, Transaction, TransactionSigned, TxType,
};
use reth_primitives_traits::InMemorySize;
use reth_primitives_traits::{InMemorySize, SignedTransaction};
use std::{ops::Range, sync::Arc, time::Instant, vec::IntoIter};
/// A transaction pool implementation using [`MockOrdering`] for transaction ordering.
@ -909,7 +909,7 @@ impl TryFrom<RecoveredTx<TransactionSigned>> for MockTransaction {
fn try_from(tx: RecoveredTx<TransactionSigned>) -> Result<Self, Self::Error> {
let sender = tx.signer();
let transaction = tx.into_tx();
let hash = transaction.hash();
let hash = *transaction.tx_hash();
let size = transaction.size();
#[allow(unreachable_patterns)]

View File

@ -7,7 +7,7 @@ use crate::{
};
use alloy_consensus::{
constants::{EIP1559_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID},
BlockHeader, Transaction as _, Typed2718,
BlockHeader, Signed, Transaction as _, Typed2718,
};
use alloy_eips::{
eip2718::Encodable2718,
@ -1249,7 +1249,8 @@ impl From<RecoveredTx<PooledTransaction>> for EthPooledTransaction {
// include the blob sidecar
let (tx, sig, hash) = tx.into_parts();
let (tx, blob) = tx.into_parts();
let tx = TransactionSigned::new(tx.into(), sig, hash);
let tx = Signed::new_unchecked(tx, sig, hash);
let tx = TransactionSigned::from(tx);
let tx = RecoveredTx::new_unchecked(tx, signer);
let mut pooled = Self::new(tx, encoded_length);
pooled.blob_sidecar = EthBlobTransactionSidecar::Present(blob);
@ -1279,9 +1280,8 @@ impl PoolTransaction for EthPooledTransaction {
tx: RecoveredTx<Self::Consensus>,
) -> Result<RecoveredTx<Self::Pooled>, Self::TryFromConsensusError> {
let (tx, signer) = tx.into_parts();
let pooled = tx
.try_into_pooled()
.map_err(|_| TryFromRecoveredTransactionError::BlobSidecarMissing)?;
let pooled =
tx.try_into().map_err(|_| TryFromRecoveredTransactionError::BlobSidecarMissing)?;
Ok(RecoveredTx::new_unchecked(pooled, signer))
}

View File

@ -1,6 +1,7 @@
use crate::BeaconSidecarConfig;
use alloy_consensus::{
transaction::PooledTransaction, BlockHeader, Signed, Transaction as _, TxEip4844WithSidecar,
Typed2718,
};
use alloy_primitives::B256;
use alloy_rpc_types_beacon::sidecar::{BeaconBlobBundle, SidecarIterator};
@ -8,6 +9,7 @@ use eyre::Result;
use futures_util::{stream::FuturesUnordered, Future, Stream, StreamExt};
use reqwest::{Error, StatusCode};
use reth::{
core::primitives::SignedTransaction,
primitives::RecoveredBlock,
providers::CanonStateNotification,
transaction_pool::{BlobStoreError, TransactionPoolExt},
@ -112,7 +114,7 @@ where
return
}
match self.pool.get_all_blobs_exact(txs.iter().map(|(tx, _)| tx.hash()).collect()) {
match self.pool.get_all_blobs_exact(txs.iter().map(|(tx, _)| *tx.tx_hash()).collect()) {
Ok(blobs) => {
actions_to_queue.reserve_exact(txs.len());
for ((tx, _), sidecar) in txs.iter().zip(blobs.into_iter()) {
@ -199,7 +201,7 @@ where
.transactions()
.filter(|tx| tx.is_eip4844())
.map(|tx| {
let transaction_hash = tx.hash();
let transaction_hash = *tx.tx_hash();
let block_metadata = BlockMetadata {
block_hash: new.tip().hash(),
block_number: new.tip().number(),

View File

@ -21,6 +21,4 @@ alloy-consensus.workspace = true
eyre.workspace = true
[features]
optimism = [
"reth-primitives/optimism"
]
optimism = []

View File

@ -15,7 +15,7 @@ use reth::{
tasks::TaskManager,
};
use reth_chainspec::ChainSpec;
use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig};
use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig, primitives::SignedTransaction};
use reth_node_ethereum::EthereumNode;
#[tokio::main]
@ -51,7 +51,7 @@ async fn main() -> eyre::Result<()> {
let head = notifications.next().await.unwrap();
let tx = &head.tip().body().transactions().next().unwrap();
assert_eq!(tx.hash(), hash);
assert_eq!(*tx.tx_hash(), hash);
println!("mined transaction: {hash}");
Ok(())
}

View File

@ -10,6 +10,7 @@ license.workspace = true
reth-chainspec.workspace = true
reth-db.workspace = true
reth-primitives.workspace = true
reth-primitives-traits.workspace = true
reth-provider.workspace = true
reth-node-ethereum.workspace = true
reth-node-types.workspace = true

View File

@ -6,6 +6,7 @@ use reth_db::{open_db_read_only, DatabaseEnv};
use reth_node_ethereum::EthereumNode;
use reth_node_types::NodeTypesWithDBAdapter;
use reth_primitives::{SealedBlock, SealedHeader, TransactionSigned};
use reth_primitives_traits::transaction::signed::SignedTransaction;
use reth_provider::{
providers::StaticFileProvider, AccountReader, BlockReader, BlockSource, HeaderProvider,
ProviderFactory, ReceiptProvider, StateProvider, TransactionsProvider,
@ -95,17 +96,17 @@ fn txs_provider_example<T: TransactionsProvider<Transaction = TransactionSigned>
// Can query the tx by hash
let tx_by_hash =
provider.transaction_by_hash(tx.hash())?.ok_or(eyre::eyre!("txhash not found"))?;
provider.transaction_by_hash(*tx.tx_hash())?.ok_or(eyre::eyre!("txhash not found"))?;
assert_eq!(tx, tx_by_hash);
// Can query the tx by hash with info about the block it was included in
let (tx, meta) = provider
.transaction_by_hash_with_meta(tx.hash())?
.transaction_by_hash_with_meta(*tx.tx_hash())?
.ok_or(eyre::eyre!("txhash not found"))?;
assert_eq!(tx.hash(), meta.tx_hash);
assert_eq!(*tx.tx_hash(), meta.tx_hash);
// Can reverse lookup the key too
let id = provider.transaction_id(tx.hash())?.ok_or(eyre::eyre!("txhash not found"))?;
let id = provider.transaction_id(*tx.tx_hash())?.ok_or(eyre::eyre!("txhash not found"))?;
assert_eq!(id, txid);
// Can find the block of a transaction given its key
@ -181,8 +182,9 @@ fn receipts_provider_example<
// Can query receipt by txhash too
let tx = provider.transaction_by_id(txid)?.unwrap();
let receipt_by_hash =
provider.receipt_by_hash(tx.hash())?.ok_or(eyre::eyre!("tx receipt by hash not found"))?;
let receipt_by_hash = provider
.receipt_by_hash(*tx.tx_hash())?
.ok_or(eyre::eyre!("tx receipt by hash not found"))?;
assert_eq!(receipt, receipt_by_hash);
// Can query all the receipts in a block

View File

@ -1,6 +1,6 @@
//! Generators for different data structures like block headers, block bodies and ranges of those.
use alloy_consensus::{Block, Header, Transaction as _, TxLegacy};
use alloy_consensus::{Block, Header, SignableTransaction, Transaction as _, TxLegacy};
use alloy_eips::{
eip1898::BlockWithParent,
eip4895::{Withdrawal, Withdrawals},