mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 02:49:55 +00:00
feat: use reth-ethereum-primitives (#13830)
This commit is contained in:
25
Cargo.lock
generated
25
Cargo.lock
generated
@ -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]]
|
||||
|
||||
@ -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 = []
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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<_>>();
|
||||
|
||||
|
||||
@ -52,7 +52,6 @@ tracing.workspace = true
|
||||
|
||||
[features]
|
||||
optimism = [
|
||||
"reth-primitives/optimism",
|
||||
"reth-provider/optimism",
|
||||
"revm-primitives/optimism",
|
||||
]
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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},
|
||||
|
||||
@ -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)?;
|
||||
|
||||
|
||||
@ -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"
|
||||
]
|
||||
|
||||
44
crates/ethereum/primitives/src/alloy_compat.rs
Normal file
44
crates/ethereum/primitives/src/alloy_compat.rs
Normal 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() })
|
||||
}
|
||||
}
|
||||
@ -16,3 +16,6 @@ pub use receipt::*;
|
||||
|
||||
mod transaction;
|
||||
pub use transaction::*;
|
||||
|
||||
#[cfg(feature = "alloy-compat")]
|
||||
mod alloy_compat;
|
||||
|
||||
@ -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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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::*;
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -73,7 +73,6 @@ tempfile.workspace = true
|
||||
|
||||
[features]
|
||||
optimism = [
|
||||
"reth-primitives/optimism",
|
||||
"reth-db?/optimism",
|
||||
"reth-db-api?/optimism",
|
||||
"reth-provider/optimism"
|
||||
|
||||
@ -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()?))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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()));
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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},
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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"]
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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"),
|
||||
};
|
||||
|
||||
|
||||
@ -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 }
|
||||
}
|
||||
|
||||
@ -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"]
|
||||
|
||||
@ -78,7 +78,6 @@ std = [
|
||||
"reth-consensus-common/std",
|
||||
]
|
||||
optimism = [
|
||||
"reth-primitives/optimism",
|
||||
"reth-execution-types/optimism",
|
||||
"reth-optimism-consensus/optimism",
|
||||
"revm/optimism",
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -55,7 +55,6 @@ sha2.workspace = true
|
||||
|
||||
[features]
|
||||
optimism = [
|
||||
"reth-primitives/optimism",
|
||||
"reth-provider/optimism",
|
||||
"reth-optimism-evm/optimism",
|
||||
"revm/optimism",
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ rstest.workspace = true
|
||||
arbitrary.workspace = true
|
||||
secp256k1 = { workspace = true, features = ["rand"] }
|
||||
proptest.workspace = true
|
||||
rand.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
|
||||
@ -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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -21,7 +21,6 @@ reth-stages-types.workspace = true
|
||||
|
||||
[features]
|
||||
optimism = [
|
||||
"reth-primitives/optimism",
|
||||
"reth-codecs/op",
|
||||
"reth-db-api/optimism"
|
||||
]
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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]]
|
||||
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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};
|
||||
|
||||
|
||||
@ -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::*;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
@ -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() {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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};
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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())?;
|
||||
|
||||
@ -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())?
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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}"),
|
||||
|
||||
@ -87,7 +87,6 @@ arbitrary = [
|
||||
"reth-optimism-primitives?/arbitrary"
|
||||
]
|
||||
optimism = [
|
||||
"reth-primitives/optimism",
|
||||
"reth-codecs/op",
|
||||
"reth-optimism-primitives?/optimism",
|
||||
"op",
|
||||
|
||||
@ -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 = []
|
||||
|
||||
|
||||
@ -88,7 +88,6 @@ alloy-consensus.workspace = true
|
||||
|
||||
[features]
|
||||
optimism = [
|
||||
"reth-primitives/optimism",
|
||||
"reth-execution-types/optimism",
|
||||
"reth-optimism-primitives",
|
||||
"reth-codecs/op",
|
||||
|
||||
@ -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
|
||||
),
|
||||
|
||||
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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))
|
||||
}
|
||||
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -21,6 +21,4 @@ alloy-consensus.workspace = true
|
||||
eyre.workspace = true
|
||||
|
||||
[features]
|
||||
optimism = [
|
||||
"reth-primitives/optimism"
|
||||
]
|
||||
optimism = []
|
||||
@ -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(())
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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},
|
||||
|
||||
Reference in New Issue
Block a user