Skip to content

Commit b50a2c8

Browse files
committed
WIP build receipts
1 parent 54abd9f commit b50a2c8

File tree

10 files changed

+163
-323
lines changed

10 files changed

+163
-323
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ alloy-rpc-types-eth = "1.0.41"
116116
alloy-rpc-types-engine = "1.0.41"
117117

118118
# op-alloy
119+
alloy-op-evm = { version = "0.23.3", default-features = false }
119120
op-alloy-network = "0.22.0"
120121
op-alloy-rpc-types = "0.22.0"
121122
op-alloy-consensus = "0.22.0"

crates/flashblocks/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ alloy-provider.workspace = true
3232
alloy-rpc-types.workspace = true
3333
alloy-consensus.workspace = true
3434
alloy-primitives.workspace = true
35+
alloy-op-evm.workspace = true
3536
alloy-rpc-types-eth.workspace = true
3637
alloy-rpc-types-engine.workspace = true
3738

crates/flashblocks/benches/pending_state.rs

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,21 @@ use std::{
55
time::{Duration, Instant},
66
};
77

8-
use alloy_consensus::Receipt;
98
use alloy_eips::{BlockHashOrNumber, Encodable2718};
10-
use alloy_primitives::{Address, B256, BlockNumber, Bytes, U256, b256, bytes, hex::FromHex};
9+
use alloy_primitives::{Address, B256, BlockNumber, Bytes, U256, bytes, hex::FromHex};
1110
use alloy_rpc_types_engine::PayloadId;
1211
use base_flashtypes::{
1312
ExecutionPayloadBaseV1, ExecutionPayloadFlashblockDeltaV1, Flashblock, Metadata,
1413
};
1514
use base_reth_flashblocks::{FlashblocksAPI, FlashblocksReceiver, FlashblocksState};
1615
use base_reth_test_utils::{LocalNodeProvider, TestAccounts, TestHarness};
1716
use criterion::{BatchSize, Criterion, Throughput, criterion_group, criterion_main};
18-
use op_alloy_consensus::OpDepositReceipt;
1917
use reth::{
2018
chainspec::{ChainSpecProvider, EthChainSpec},
2119
providers::BlockReader,
2220
transaction_pool::test_utils::TransactionBuilder,
2321
};
24-
use reth_optimism_primitives::{OpBlock, OpReceipt, OpTransactionSigned};
22+
use reth_optimism_primitives::{OpBlock, OpTransactionSigned};
2523
use reth_primitives_traits::{Block as BlockT, RecoveredBlock};
2624
use tokio::{runtime::Runtime, time::sleep};
2725
use tracing_subscriber::{EnvFilter, filter::LevelFilter};
@@ -33,8 +31,6 @@ const CHUNK_SIZE: usize = 10;
3331
const BLOCK_INFO_TXN: Bytes = bytes!(
3432
"0x7ef90104a06c0c775b6b492bab9d7e81abdf27f77cafb698551226455a82f559e0f93fea3794deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b8b0098999be000008dd00101c1200000000000000020000000068869d6300000000015f277f000000000000000000000000000000000000000000000000000000000d42ac290000000000000000000000000000000000000000000000000000000000000001abf52777e63959936b1bf633a2a643f0da38d63deffe49452fed1bf8a44975d50000000000000000000000005050f69a9786f081509234f1a7f4684b5e5b76c9000000000000000000000000"
3533
);
36-
const BLOCK_INFO_TXN_HASH: B256 =
37-
b256!("0xba56c8b0deb460ff070f8fca8e2ee01e51a3db27841cc862fdd94cc1a47662b6");
3834

3935
struct BenchSetup {
4036
provider: LocalNodeProvider,
@@ -203,20 +199,6 @@ fn base_flashblock(
203199
canonical_block: &RecoveredBlock<OpBlock>,
204200
block_number: BlockNumber,
205201
) -> Flashblock {
206-
let mut receipts = alloy_primitives::map::HashMap::default();
207-
receipts.insert(
208-
BLOCK_INFO_TXN_HASH,
209-
OpReceipt::Deposit(OpDepositReceipt {
210-
inner: Receipt {
211-
status: true.into(),
212-
cumulative_gas_used: DEPOSIT_GAS_USED,
213-
logs: vec![],
214-
},
215-
deposit_nonce: Some(0),
216-
deposit_receipt_version: None,
217-
}),
218-
);
219-
220202
Flashblock {
221203
payload_id: PayloadId::default(),
222204
index: 0,
@@ -242,7 +224,11 @@ fn base_flashblock(
242224
transactions: vec![BLOCK_INFO_TXN.clone()],
243225
blob_gas_used: Default::default(),
244226
},
245-
metadata: Metadata { block_number, receipts, new_account_balances: Default::default() },
227+
metadata: Metadata {
228+
block_number,
229+
receipts: None,
230+
new_account_balances: Default::default(),
231+
},
246232
}
247233
}
248234

@@ -252,20 +238,11 @@ fn transaction_flashblock(
252238
transactions: &[OpTransactionSigned],
253239
gas_used: &mut u64,
254240
) -> Flashblock {
255-
let mut tx_receipts = alloy_primitives::map::HashMap::default();
256241
let mut tx_bytes = Vec::with_capacity(transactions.len());
257242

258243
for tx in transactions {
259244
*gas_used += TX_GAS_USED;
260245
tx_bytes.push(tx.encoded_2718().into());
261-
tx_receipts.insert(
262-
tx.hash().clone(),
263-
OpReceipt::Eip1559(Receipt {
264-
status: true.into(),
265-
cumulative_gas_used: *gas_used,
266-
logs: vec![],
267-
}),
268-
);
269246
}
270247

271248
Flashblock {
@@ -285,7 +262,7 @@ fn transaction_flashblock(
285262
},
286263
metadata: Metadata {
287264
block_number,
288-
receipts: tx_receipts,
265+
receipts: None,
289266
new_account_balances: Default::default(),
290267
},
291268
}

crates/flashblocks/src/processor.rs

Lines changed: 101 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,19 @@ use std::{
77
};
88

99
use alloy_consensus::{
10-
Header, TxReceipt,
10+
Eip658Value, Header, TxReceipt,
1111
transaction::{Recovered, SignerRecoverable, TransactionMeta},
1212
};
1313
use alloy_eips::BlockNumberOrTag;
14+
use alloy_op_evm::block::receipt_builder::OpReceiptBuilder;
1415
use alloy_primitives::{B256, BlockNumber, Bytes, Sealable, map::foldhash::HashMap};
1516
use alloy_rpc_types::{TransactionTrait, Withdrawal};
1617
use alloy_rpc_types_engine::{ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3};
1718
use alloy_rpc_types_eth::state::StateOverride;
1819
use arc_swap::ArcSwapOption;
1920
use base_flashtypes::Flashblock;
2021
use eyre::eyre;
21-
use op_alloy_consensus::OpTxEnvelope;
22+
use op_alloy_consensus::{OpDepositReceipt, OpTxEnvelope};
2223
use op_alloy_network::TransactionResponse;
2324
use op_alloy_rpc_types::Transaction;
2425
use reth::{
@@ -29,11 +30,11 @@ use reth::{
2930
db::CacheDB,
3031
},
3132
};
32-
use reth_evm::{ConfigureEvm, Evm};
33+
use reth_evm::{ConfigureEvm, Evm, eth::receipt_builder::ReceiptBuilderCtx};
3334
use reth_optimism_chainspec::OpHardforks;
3435
use reth_optimism_evm::{OpEvmConfig, OpNextBlockEnvAttributes};
3536
use reth_optimism_primitives::{DepositReceipt, OpBlock, OpPrimitives};
36-
use reth_optimism_rpc::OpReceiptBuilder;
37+
use reth_optimism_rpc::OpReceiptBuilder as OpRpcReceiptBuilder;
3738
use reth_primitives::RecoveredBlock;
3839
use reth_rpc_convert::transaction::ConvertReceiptInput;
3940
use tokio::sync::{Mutex, broadcast::Sender, mpsc::UnboundedReceiver};
@@ -333,7 +334,9 @@ where
333334
.iter()
334335
.map(|flashblock| flashblock.metadata.receipts.clone())
335336
.fold(HashMap::default(), |mut acc, receipts| {
336-
acc.extend(receipts);
337+
if let Some(receipts) = receipts {
338+
acc.extend(receipts);
339+
}
337340
acc
338341
});
339342

@@ -390,7 +393,7 @@ where
390393
let evm_env = evm_config.next_evm_env(&last_block_header, &block_env_attributes)?;
391394
let mut evm = evm_config.evm_with_env(db, evm_env);
392395

393-
let mut gas_used = 0;
396+
let mut cumulative_gas_used: u64 = 0;
394397
let mut next_log_index = 0;
395398

396399
for (idx, transaction) in block.body.transactions.iter().enumerate() {
@@ -407,16 +410,15 @@ where
407410
pending_blocks_builder.with_transaction_sender(tx_hash, sender);
408411
pending_blocks_builder.increment_nonce(sender);
409412

410-
let receipt = receipt_by_hash
411-
.get(&tx_hash)
412-
.cloned()
413-
.ok_or(eyre!("missing receipt for {:?}", tx_hash))?;
413+
let receipt = receipt_by_hash.get(&tx_hash).cloned();
414414

415415
let recovered_transaction = Recovered::new_unchecked(transaction.clone(), sender);
416416
let envelope = recovered_transaction.clone().convert::<OpTxEnvelope>();
417417

418418
// Build Transaction
419-
let (deposit_receipt_version, deposit_nonce) = if transaction.is_deposit() {
419+
let (deposit_receipt_version, deposit_nonce) = if transaction.is_deposit()
420+
&& let Some(receipt) = &receipt
421+
{
420422
let deposit_receipt = receipt
421423
.as_deposit_receipt()
422424
.ok_or(eyre!("deposit transaction, non deposit receipt"))?;
@@ -451,54 +453,32 @@ where
451453
};
452454

453455
pending_blocks_builder.with_transaction(rpc_txn);
456+
let mut should_execute_transaction = true;
454457

455458
// Receipt Generation
456-
let op_receipt = prev_pending_blocks
457-
.as_ref()
458-
.and_then(|pending_blocks| pending_blocks.get_receipt(tx_hash))
459-
.unwrap_or_else(|| {
460-
let meta = TransactionMeta {
461-
tx_hash,
462-
index: idx as u64,
463-
block_hash: header.hash(),
464-
block_number: block.number,
465-
base_fee: block.base_fee_per_gas,
466-
excess_blob_gas: block.excess_blob_gas,
467-
timestamp: block.timestamp,
468-
};
469-
470-
let input: ConvertReceiptInput<'_, OpPrimitives> = ConvertReceiptInput {
471-
receipt: receipt.clone(),
472-
tx: Recovered::new_unchecked(transaction, sender),
473-
gas_used: receipt.cumulative_gas_used() - gas_used,
474-
next_log_index,
475-
meta,
476-
};
477-
478-
OpReceiptBuilder::new(
479-
self.client.chain_spec().as_ref(),
480-
input,
481-
&mut l1_block_info,
482-
)
483-
.unwrap()
484-
.build()
485-
});
486-
487-
pending_blocks_builder.with_receipt(tx_hash, op_receipt);
488-
gas_used = receipt.cumulative_gas_used();
489-
next_log_index += receipt.logs().len();
459+
let saved_receipt = {
460+
let receipt = prev_pending_blocks.as_ref().and_then(|p| p.get_receipt(tx_hash));
461+
462+
if let Some(receipt) = receipt {
463+
pending_blocks_builder.with_receipt(tx_hash, receipt);
464+
true
465+
} else {
466+
false
467+
}
468+
};
490469

491-
let mut should_execute_transaction = true;
492-
if let Some(state) =
493-
prev_pending_blocks.as_ref().and_then(|p| p.get_transaction_state(&tx_hash))
470+
if saved_receipt
471+
&& let Some(state) =
472+
prev_pending_blocks.as_ref().and_then(|p| p.get_transaction_state(&tx_hash))
494473
{
495474
pending_blocks_builder.with_transaction_state(tx_hash, state);
496475
should_execute_transaction = false;
497476
}
498477

499478
if should_execute_transaction {
500-
match evm.transact(recovered_transaction) {
501-
Ok(ResultAndState { state, .. }) => {
479+
match evm.transact(recovered_transaction.clone()) {
480+
Ok(ResultAndState { state, result }) => {
481+
let gas_used = result.gas_used();
502482
for (addr, acc) in &state {
503483
let existing_override = state_overrides.entry(*addr).or_default();
504484
existing_override.balance = Some(acc.info.balance);
@@ -514,6 +494,77 @@ where
514494

515495
existing.extend(changed_slots);
516496
}
497+
498+
cumulative_gas_used = cumulative_gas_used
499+
.checked_add(gas_used)
500+
.ok_or(eyre!("cumulative gas used overflow"))?;
501+
502+
let receipt_builder =
503+
evm_config.block_executor_factory().receipt_builder();
504+
505+
let is_canyon_active = self
506+
.client
507+
.chain_spec()
508+
.is_canyon_active_at_timestamp(block.timestamp);
509+
let receipt = match receipt_builder.build_receipt(ReceiptBuilderCtx {
510+
tx: &recovered_transaction,
511+
evm: &evm,
512+
result,
513+
state: &state,
514+
cumulative_gas_used,
515+
}) {
516+
Ok(receipt) => receipt,
517+
Err(ctx) => {
518+
let receipt = alloy_consensus::Receipt {
519+
// Success flag was added in `EIP-658: Embedding transaction status code
520+
// in receipts`.
521+
status: Eip658Value::Eip658(ctx.result.is_success()),
522+
cumulative_gas_used: ctx.cumulative_gas_used,
523+
logs: ctx.result.into_logs(),
524+
};
525+
526+
receipt_builder.build_deposit_receipt(OpDepositReceipt {
527+
inner: receipt,
528+
deposit_nonce,
529+
// The deposit receipt version was introduced in Canyon to indicate an
530+
// update to how receipt hashes should be computed
531+
// when set. The state transition process ensures
532+
// this is only set for post-Canyon deposit
533+
// transactions.
534+
deposit_receipt_version: is_canyon_active.then_some(1),
535+
})
536+
}
537+
};
538+
539+
let meta = TransactionMeta {
540+
tx_hash,
541+
index: idx as u64,
542+
block_hash: header.hash(),
543+
block_number: block.number,
544+
base_fee: block.base_fee_per_gas,
545+
excess_blob_gas: block.excess_blob_gas,
546+
timestamp: block.timestamp,
547+
};
548+
549+
let input: ConvertReceiptInput<'_, OpPrimitives> =
550+
ConvertReceiptInput {
551+
receipt: receipt.clone(),
552+
tx: Recovered::new_unchecked(transaction, sender),
553+
gas_used,
554+
next_log_index,
555+
meta,
556+
};
557+
558+
let op_receipt = OpRpcReceiptBuilder::new(
559+
self.client.chain_spec().as_ref(),
560+
input,
561+
&mut l1_block_info,
562+
)
563+
.unwrap()
564+
.build();
565+
next_log_index = next_log_index + receipt.logs().len();
566+
567+
pending_blocks_builder.with_receipt(tx_hash, op_receipt);
517568
pending_blocks_builder.with_transaction_state(tx_hash, state.clone());
518569
evm.db_mut().commit(state);
519570
}

0 commit comments

Comments
 (0)