Skip to content

Commit 1de93fc

Browse files
authored
fix(anvil): preserve OP receipt fields in convert_to_anvil_receipt (#12396)
* fix(anvil): preserve OP receipt fields in convert_to_anvil_receipt * test(anvil): add test for OP receipt fields preservation * fix(anvil): adapt receipt handling for WithOtherFields wrapper * chore(anvil): removed unrelated snapshot state save * test(anvil): use Bloom::default() instead manual zero hex * chore(anvil): updated to fit linter format
1 parent ad9fcef commit 1de93fc

File tree

5 files changed

+101
-48
lines changed

5 files changed

+101
-48
lines changed

crates/anvil/core/src/eth/transaction/mod.rs

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,7 +1462,7 @@ impl Decodable2718 for TypedReceipt {
14621462
}
14631463
}
14641464

1465-
pub type ReceiptResponse = TransactionReceipt<TypedReceiptRpc>;
1465+
pub type ReceiptResponse = WithOtherFields<TransactionReceipt<TypedReceiptRpc>>;
14661466

14671467
pub fn convert_to_anvil_receipt(receipt: AnyTransactionReceipt) -> Option<ReceiptResponse> {
14681468
let WithOtherFields {
@@ -1484,51 +1484,56 @@ pub fn convert_to_anvil_receipt(receipt: AnyTransactionReceipt) -> Option<Receip
14841484
other,
14851485
} = receipt;
14861486

1487-
Some(TransactionReceipt {
1488-
transaction_hash,
1489-
transaction_index,
1490-
block_hash,
1491-
block_number,
1492-
gas_used,
1493-
contract_address,
1494-
effective_gas_price,
1495-
from,
1496-
to,
1497-
blob_gas_price,
1498-
blob_gas_used,
1499-
inner: match r#type {
1500-
0x00 => TypedReceiptRpc::Legacy(receipt_with_bloom),
1501-
0x01 => TypedReceiptRpc::EIP2930(receipt_with_bloom),
1502-
0x02 => TypedReceiptRpc::EIP1559(receipt_with_bloom),
1503-
0x03 => TypedReceiptRpc::EIP4844(receipt_with_bloom),
1504-
0x04 => TypedReceiptRpc::EIP7702(receipt_with_bloom),
1505-
0x7E => TypedReceiptRpc::Deposit(OpDepositReceiptWithBloom {
1506-
receipt: OpDepositReceipt {
1507-
inner: Receipt {
1508-
status: alloy_consensus::Eip658Value::Eip658(receipt_with_bloom.status()),
1509-
cumulative_gas_used: receipt_with_bloom.cumulative_gas_used(),
1510-
logs: receipt_with_bloom
1511-
.receipt
1512-
.logs
1513-
.into_iter()
1514-
.map(|l| l.inner)
1515-
.collect(),
1487+
Some(WithOtherFields {
1488+
inner: TransactionReceipt {
1489+
transaction_hash,
1490+
transaction_index,
1491+
block_hash,
1492+
block_number,
1493+
gas_used,
1494+
contract_address,
1495+
effective_gas_price,
1496+
from,
1497+
to,
1498+
blob_gas_price,
1499+
blob_gas_used,
1500+
inner: match r#type {
1501+
0x00 => TypedReceiptRpc::Legacy(receipt_with_bloom),
1502+
0x01 => TypedReceiptRpc::EIP2930(receipt_with_bloom),
1503+
0x02 => TypedReceiptRpc::EIP1559(receipt_with_bloom),
1504+
0x03 => TypedReceiptRpc::EIP4844(receipt_with_bloom),
1505+
0x04 => TypedReceiptRpc::EIP7702(receipt_with_bloom),
1506+
0x7E => TypedReceiptRpc::Deposit(OpDepositReceiptWithBloom {
1507+
receipt: OpDepositReceipt {
1508+
inner: Receipt {
1509+
status: alloy_consensus::Eip658Value::Eip658(
1510+
receipt_with_bloom.status(),
1511+
),
1512+
cumulative_gas_used: receipt_with_bloom.cumulative_gas_used(),
1513+
logs: receipt_with_bloom
1514+
.receipt
1515+
.logs
1516+
.into_iter()
1517+
.map(|l| l.inner)
1518+
.collect(),
1519+
},
1520+
deposit_nonce: other
1521+
.get_deserialized::<U64>("depositNonce")
1522+
.transpose()
1523+
.ok()?
1524+
.map(|v| v.to()),
1525+
deposit_receipt_version: other
1526+
.get_deserialized::<U64>("depositReceiptVersion")
1527+
.transpose()
1528+
.ok()?
1529+
.map(|v| v.to()),
15161530
},
1517-
deposit_nonce: other
1518-
.get_deserialized::<U64>("depositNonce")
1519-
.transpose()
1520-
.ok()?
1521-
.map(|v| v.to()),
1522-
deposit_receipt_version: other
1523-
.get_deserialized::<U64>("depositReceiptVersion")
1524-
.transpose()
1525-
.ok()?
1526-
.map(|v| v.to()),
1527-
},
1528-
logs_bloom: receipt_with_bloom.logs_bloom,
1529-
}),
1530-
_ => return None,
1531+
logs_bloom: receipt_with_bloom.logs_bloom,
1532+
}),
1533+
_ => return None,
1534+
},
15311535
},
1536+
other,
15321537
})
15331538
}
15341539

crates/anvil/src/eth/api.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2655,6 +2655,7 @@ impl EthApi {
26552655
{
26562656
// insert revert reason if failure
26572657
if !receipt
2658+
.inner
26582659
.inner
26592660
.inner
26602661
.as_receipt_with_bloom()

crates/anvil/src/eth/backend/mem/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3207,6 +3207,7 @@ impl Backend {
32073207
blob_gas_used,
32083208
};
32093209

3210+
let inner = WithOtherFields { inner, other: Default::default() };
32103211
Some(MinedTransactionReceipt { inner, out: info.out })
32113212
}
32123213

crates/anvil/src/eth/otterscan/api.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ impl EthApi {
8585
node_info!("ots_getTransactionError");
8686

8787
if let Some(receipt) = self.backend.mined_transaction_receipt(hash)
88-
&& !receipt.inner.inner.as_receipt_with_bloom().receipt.status.coerce_status()
88+
&& !receipt.inner.inner.inner.as_receipt_with_bloom().receipt.status.coerce_status()
8989
{
9090
return Ok(receipt.out.unwrap_or_default());
9191
}
@@ -379,7 +379,7 @@ impl EthApi {
379379
if let Ok(Some(r)) = r.await {
380380
let block = self.block_by_number(r.block_number.unwrap().into()).await?;
381381
let timestamp = block.ok_or(BlockchainError::BlockNotFound)?.header.timestamp;
382-
let receipt = r.map_inner(OtsReceipt::from);
382+
let receipt = r.inner.clone().map_inner(OtsReceipt::from);
383383
Ok(OtsTransactionReceipt { receipt, timestamp: Some(timestamp) })
384384
} else {
385385
Err(BlockchainError::BlockNotFound)
@@ -420,7 +420,7 @@ impl EthApi {
420420
if let Ok(Some(r)) = r.await {
421421
let block = self.block_by_number(r.block_number.unwrap().into()).await?;
422422
let timestamp = block.ok_or(BlockchainError::BlockNotFound)?.header.timestamp;
423-
let receipt = r.map_inner(OtsReceipt::from);
423+
let receipt = r.inner.clone().map_inner(OtsReceipt::from);
424424
Ok(OtsTransactionReceipt { receipt, timestamp: Some(timestamp) })
425425
} else {
426426
Err(BlockchainError::BlockNotFound)

crates/anvil/tests/it/optimism.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
use crate::utils::{http_provider, http_provider_with_signer};
44
use alloy_eips::eip2718::Encodable2718;
55
use alloy_network::{EthereumWallet, TransactionBuilder};
6-
use alloy_primitives::{Address, TxHash, TxKind, U256, b256};
6+
use alloy_primitives::{Address, Bloom, TxHash, TxKind, U256, b256};
77
use alloy_provider::Provider;
88
use alloy_rpc_types::TransactionRequest;
99
use alloy_serde::WithOtherFields;
1010
use anvil::{NodeConfig, spawn};
1111
use foundry_evm_networks::NetworkConfigs;
1212
use op_alloy_consensus::TxDeposit;
1313
use op_alloy_rpc_types::OpTransactionFields;
14+
use serde_json::{Value, json};
1415

1516
#[tokio::test(flavor = "multi_thread")]
1617
async fn test_deposits_not_supported_if_optimism_disabled() {
@@ -224,3 +225,48 @@ async fn test_deposit_tx_checks_sufficient_funds_after_applying_deposited_value(
224225
// recipient should've received the entire deposited value
225226
assert_eq!(recipient_new_balance, U256::from(send_value));
226227
}
228+
229+
#[test]
230+
fn preserves_op_fields_in_convert_to_anvil_receipt() {
231+
let receipt_json = json!({
232+
"status": "0x1",
233+
"cumulativeGasUsed": "0x74e483",
234+
"logs": [],
235+
"logsBloom": Bloom::default(),
236+
"type": "0x2",
237+
"transactionHash": "0x91181b0dca3b29aa136eeb2f536be5ce7b0aebc949be1c44b5509093c516097d",
238+
"transactionIndex": "0x10",
239+
"blockHash": "0x54bafb12e8cea9bb355fbf03a4ac49e42a2a1a80fa6cf4364b342e2de6432b5d",
240+
"blockNumber": "0x7b1ab93",
241+
"gasUsed": "0xc222",
242+
"effectiveGasPrice": "0x18961",
243+
"from": "0x2d815240a61731c75fa01b2793e1d3ed09f289d0",
244+
"to": "0x4200000000000000000000000000000000000000",
245+
"contractAddress": Value::Null,
246+
"l1BaseFeeScalar": "0x146b",
247+
"l1BlobBaseFee": "0x6a83078",
248+
"l1BlobBaseFeeScalar": "0xf79c5",
249+
"l1Fee": "0x51a9af7fd3",
250+
"l1GasPrice": "0x972fe4acc",
251+
"l1GasUsed": "0x640",
252+
});
253+
254+
let receipt: alloy_network::AnyTransactionReceipt =
255+
serde_json::from_value(receipt_json).expect("valid receipt json");
256+
257+
let converted = anvil_core::eth::transaction::convert_to_anvil_receipt(receipt)
258+
.expect("conversion should succeed");
259+
let converted_json = serde_json::to_value(&converted).expect("serialize to json");
260+
261+
for (key, expected) in [
262+
("l1Fee", "0x51a9af7fd3"),
263+
("l1GasPrice", "0x972fe4acc"),
264+
("l1GasUsed", "0x640"),
265+
("l1BaseFeeScalar", "0x146b"),
266+
("l1BlobBaseFee", "0x6a83078"),
267+
("l1BlobBaseFeeScalar", "0xf79c5"),
268+
] {
269+
let got = converted_json.get(key).and_then(Value::as_str);
270+
assert_eq!(got, Some(expected), "field `{key}` mismatch");
271+
}
272+
}

0 commit comments

Comments
 (0)