Skip to content

Commit e482612

Browse files
kustrungeoknee
andauthored
Fix eth_simulateV1 after Jovian fork (#732)
* fix(eth_simulatev1): Create synthetic Jovian Deposit TX, to not fail in the CalcDAFootprint() function. * fix(eth_simulatev1): Return block without synthetic Jovian deposit tx. * fix(eth_simulatev1): Extract JovianDepositTx() from tests, activate Jovian fork based on parent.Time. * Inject L1 attributes tx in Optimism simulation * Unexport JovianDepositTx and move to tests Remove exported JovianDepositTx from core/types and add a local jovianDepositTx helper in miner tests. Also remove the unused encoding/binary import from the core/types file and add it to the test files where needed. * Pass nil options to sim.execute in test * Pass nil as second argument in simulation test * Embed L1 attributes tx in simulator * Handle Optimism genesis without L1 tx * Rename finalTxes to prependedTxes * Remove nil argument from sim.execute calls * Update internal/ethapi/api.go Co-authored-by: kustrun <[email protected]> --------- Co-authored-by: geoknee <[email protected]>
1 parent b574afa commit e482612

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

internal/ethapi/api.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,18 @@ func (api *BlockChainAPI) SimulateV1(ctx context.Context, opts simOpts, blockNrO
921921
validate: opts.Validation,
922922
fullTx: opts.ReturnFullTransactions,
923923
}
924+
if api.b.ChainConfig().IsOptimism() {
925+
block, err := api.b.BlockByNumberOrHash(ctx, *blockNrOrHash)
926+
if err != nil {
927+
return nil, err
928+
}
929+
if len(block.Transactions()) > 0 {
930+
// For the special case of the genesis block, there are no transactions
931+
// so we won't set the l1AttributesTx and the simulation will
932+
// likely fail.
933+
sim.l1AttributesTx = block.Transactions()[0]
934+
}
935+
}
924936
return sim.execute(ctx, opts.BlockStateCalls)
925937
}
926938

internal/ethapi/simulate.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"github.com/ethereum/go-ethereum/internal/ethapi/override"
3737
"github.com/ethereum/go-ethereum/params"
3838
"github.com/ethereum/go-ethereum/rpc"
39+
"github.com/ethereum/go-ethereum/trie"
3940
)
4041

4142
const (
@@ -174,9 +175,14 @@ type simulator struct {
174175
traceTransfers bool
175176
validate bool
176177
fullTx bool
178+
179+
// OP-Stack diff
180+
l1AttributesTx *types.Transaction
177181
}
178182

179183
// execute runs the simulation of a series of blocks.
184+
// OPStack-diff: execute accepts an l1 attributes transaction which (if non-nil) will be injected into each block
185+
// at position 0.
180186
func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]*simBlockResult, error) {
181187
if err := ctx.Err(); err != nil {
182188
return nil, err
@@ -220,6 +226,8 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]*simBlo
220226
return results, nil
221227
}
222228

229+
// OP-Stack diff: proceesBlock accepts an l1 attributes transaction which (if non-nil) will be injected into the block
230+
// at position 0.
223231
func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, parent *types.Header, headers []*types.Header, timeout time.Duration) (*types.Block, []simCallResult, map[common.Hash]common.Address, types.Receipts, error) {
224232
// Set header fields that depend only on parent block.
225233
// Parent hash is needed for evm.GetHashFn to work.
@@ -359,12 +367,36 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
359367
reqHash := types.CalcRequestsHash(requests)
360368
header.RequestsHash = &reqHash
361369
}
362-
blockBody := &types.Body{Transactions: txes, Withdrawals: *block.BlockOverrides.Withdrawals}
370+
371+
// For Optimism blocks, inject the provided l1 attributes transaction at the beginning of the block.
372+
// This is required because CalcDAFootprint (called by FinalizeAndAssemble for Jovian blocks)
373+
// expects the first transaction to be a deposit transaction containing L1 attributes data.
374+
isOptimism := sim.chainConfig.IsOptimism()
375+
prependedTxes := txes
376+
if isOptimism && sim.l1AttributesTx != nil {
377+
prependedTxes = append([]*types.Transaction{sim.l1AttributesTx}, txes...)
378+
}
379+
380+
blockBody := &types.Body{Transactions: prependedTxes, Withdrawals: *block.BlockOverrides.Withdrawals}
363381
chainHeadReader := &simChainHeadReader{ctx, sim.b}
364382
b, err := sim.b.Engine().FinalizeAndAssemble(chainHeadReader, header, sim.state, blockBody, receipts)
365383
if err != nil {
366384
return nil, nil, nil, nil, err
367385
}
386+
387+
// For Optimism blocks, reconstruct the block without the l1 attributes transaction
388+
// to maintain consistent indexing between transactions and receipts.
389+
// We must use types.NewBlock to recompute TxHash correctly for the user transactions only.
390+
if isOptimism && sim.l1AttributesTx != nil {
391+
b = types.NewBlock(
392+
b.Header(),
393+
&types.Body{Transactions: txes, Withdrawals: *block.BlockOverrides.Withdrawals},
394+
receipts,
395+
trie.NewStackTrie(nil),
396+
sim.chainConfig,
397+
)
398+
}
399+
368400
repairLogs(callResults, b.Hash())
369401
return b, callResults, senders, receipts, nil
370402
}

0 commit comments

Comments
 (0)