Skip to content

Commit 71e9c9b

Browse files
authored
internal/ethapi: support for beacon root and withdrawals in simulate api (#31304)
Adds block override fields for beacon block root and withdrawals to the eth_simulateV1. Addresses #31264
1 parent 8e3b94d commit 71e9c9b

File tree

6 files changed

+106
-17
lines changed

6 files changed

+106
-17
lines changed

eth/gasestimator/gasestimator.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,9 @@ func run(ctx context.Context, call *core.Message, opts *Options) (*core.Executio
223223
dirtyState = opts.State.Copy()
224224
)
225225
if opts.BlockOverrides != nil {
226-
opts.BlockOverrides.Apply(&evmContext)
226+
if err := opts.BlockOverrides.Apply(&evmContext); err != nil {
227+
return nil, err
228+
}
227229
}
228230
// Lower the basefee to 0 to avoid breaking EVM
229231
// invariants (basefee < feecap).

eth/tracers/api.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,9 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
950950
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
951951
// Apply the customization rules if required.
952952
if config != nil {
953-
config.BlockOverrides.Apply(&vmctx)
953+
if overrideErr := config.BlockOverrides.Apply(&vmctx); overrideErr != nil {
954+
return nil, overrideErr
955+
}
954956
rules := api.backend.ChainConfig().Rules(vmctx.BlockNumber, vmctx.Random != nil, vmctx.Time)
955957

956958
precompiles = vm.ActivePrecompiledContracts(rules)

internal/ethapi/api.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,9 @@ func (context *ChainContext) Config() *params.ChainConfig {
660660
func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
661661
blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil)
662662
if blockOverrides != nil {
663-
blockOverrides.Apply(&blockCtx)
663+
if err := blockOverrides.Apply(&blockCtx); err != nil {
664+
return nil, err
665+
}
664666
}
665667
rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time)
666668
precompiles := vm.ActivePrecompiledContracts(rules)

internal/ethapi/api_test.go

+18
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,24 @@ func TestCall(t *testing.T) {
11341134
},
11351135
want: "0x0000000000000000000000000000000000000000000000000000000000000000",
11361136
},
1137+
{
1138+
name: "unsupported block override beaconRoot",
1139+
blockNumber: rpc.LatestBlockNumber,
1140+
call: TransactionArgs{},
1141+
blockOverrides: override.BlockOverrides{
1142+
BeaconRoot: &common.Hash{0, 1, 2},
1143+
},
1144+
expectErr: errors.New(`block override "beaconRoot" is not supported for this RPC method`),
1145+
},
1146+
{
1147+
name: "unsupported block override withdrawals",
1148+
blockNumber: rpc.LatestBlockNumber,
1149+
call: TransactionArgs{},
1150+
blockOverrides: override.BlockOverrides{
1151+
Withdrawals: &types.Withdrawals{},
1152+
},
1153+
expectErr: errors.New(`block override "withdrawals" is not supported for this RPC method`),
1154+
},
11371155
}
11381156
for _, tc := range testSuite {
11391157
result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides)

internal/ethapi/override/override.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package override
1818

1919
import (
20+
"errors"
2021
"fmt"
2122
"math/big"
2223

@@ -128,12 +129,20 @@ type BlockOverrides struct {
128129
PrevRandao *common.Hash
129130
BaseFeePerGas *hexutil.Big
130131
BlobBaseFee *hexutil.Big
132+
BeaconRoot *common.Hash
133+
Withdrawals *types.Withdrawals
131134
}
132135

133136
// Apply overrides the given header fields into the given block context.
134-
func (o *BlockOverrides) Apply(blockCtx *vm.BlockContext) {
137+
func (o *BlockOverrides) Apply(blockCtx *vm.BlockContext) error {
135138
if o == nil {
136-
return
139+
return nil
140+
}
141+
if o.BeaconRoot != nil {
142+
return errors.New(`block override "beaconRoot" is not supported for this RPC method`)
143+
}
144+
if o.Withdrawals != nil {
145+
return errors.New(`block override "withdrawals" is not supported for this RPC method`)
137146
}
138147
if o.Number != nil {
139148
blockCtx.BlockNumber = o.Number.ToInt()
@@ -159,6 +168,7 @@ func (o *BlockOverrides) Apply(blockCtx *vm.BlockContext) {
159168
if o.BlobBaseFee != nil {
160169
blockCtx.BlobBaseFee = o.BlobBaseFee.ToInt()
161170
}
171+
return nil
162172
}
163173

164174
// MakeHeader returns a new header object with the overridden

internal/ethapi/simulate.go

+67-12
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ 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"
4039
)
4140

4241
const (
@@ -95,6 +94,47 @@ type simOpts struct {
9594
ReturnFullTransactions bool
9695
}
9796

97+
// simChainHeadReader implements ChainHeaderReader which is needed as input for FinalizeAndAssemble.
98+
type simChainHeadReader struct {
99+
context.Context
100+
Backend
101+
}
102+
103+
func (m *simChainHeadReader) Config() *params.ChainConfig {
104+
return m.Backend.ChainConfig()
105+
}
106+
107+
func (m *simChainHeadReader) CurrentHeader() *types.Header {
108+
return m.Backend.CurrentHeader()
109+
}
110+
111+
func (m *simChainHeadReader) GetHeader(hash common.Hash, number uint64) *types.Header {
112+
header, err := m.Backend.HeaderByNumber(m.Context, rpc.BlockNumber(number))
113+
if err != nil || header == nil {
114+
return nil
115+
}
116+
if header.Hash() != hash {
117+
return nil
118+
}
119+
return header
120+
}
121+
122+
func (m *simChainHeadReader) GetHeaderByNumber(number uint64) *types.Header {
123+
header, err := m.Backend.HeaderByNumber(m.Context, rpc.BlockNumber(number))
124+
if err != nil {
125+
return nil
126+
}
127+
return header
128+
}
129+
130+
func (m *simChainHeadReader) GetHeaderByHash(hash common.Hash) *types.Header {
131+
header, err := m.Backend.HeaderByHash(m.Context, hash)
132+
if err != nil {
133+
return nil
134+
}
135+
return header
136+
}
137+
98138
// simulator is a stateful object that simulates a series of blocks.
99139
// it is not safe for concurrent use.
100140
type simulator struct {
@@ -209,6 +249,9 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
209249
if sim.chainConfig.IsPrague(header.Number, header.Time) || sim.chainConfig.IsVerkle(header.Number, header.Time) {
210250
core.ProcessParentBlockHash(header.ParentHash, evm)
211251
}
252+
if header.ParentBeaconRoot != nil {
253+
core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, evm)
254+
}
212255
var allLogs []*types.Log
213256
for i, call := range block.Calls {
214257
if err := ctx.Err(); err != nil {
@@ -258,6 +301,10 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
258301
}
259302
callResults[i] = callRes
260303
}
304+
header.GasUsed = gasUsed
305+
if sim.chainConfig.IsCancun(header.Number, header.Time) {
306+
header.BlobGasUsed = &blobGasUsed
307+
}
261308
var requests [][]byte
262309
// Process EIP-7685 requests
263310
if sim.chainConfig.IsPrague(header.Number, header.Time) {
@@ -271,20 +318,16 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
271318
// EIP-7251
272319
core.ProcessConsolidationQueue(&requests, evm)
273320
}
274-
header.Root = sim.state.IntermediateRoot(true)
275-
header.GasUsed = gasUsed
276-
if sim.chainConfig.IsCancun(header.Number, header.Time) {
277-
header.BlobGasUsed = &blobGasUsed
278-
}
279-
var withdrawals types.Withdrawals
280-
if sim.chainConfig.IsShanghai(header.Number, header.Time) {
281-
withdrawals = make([]*types.Withdrawal, 0)
282-
}
283321
if requests != nil {
284322
reqHash := types.CalcRequestsHash(requests)
285323
header.RequestsHash = &reqHash
286324
}
287-
b := types.NewBlock(header, &types.Body{Transactions: txes, Withdrawals: withdrawals}, receipts, trie.NewStackTrie(nil))
325+
blockBody := &types.Body{Transactions: txes, Withdrawals: *block.BlockOverrides.Withdrawals}
326+
chainHeadReader := &simChainHeadReader{ctx, sim.b}
327+
b, err := sim.b.Engine().FinalizeAndAssemble(chainHeadReader, header, sim.state, blockBody, receipts)
328+
if err != nil {
329+
return nil, nil, err
330+
}
288331
repairLogs(callResults, b.Hash())
289332
return b, callResults, nil
290333
}
@@ -346,6 +389,9 @@ func (sim *simulator) sanitizeChain(blocks []simBlock) ([]simBlock, error) {
346389
n := new(big.Int).Add(prevNumber, big.NewInt(1))
347390
block.BlockOverrides.Number = (*hexutil.Big)(n)
348391
}
392+
if block.BlockOverrides.Withdrawals == nil {
393+
block.BlockOverrides.Withdrawals = &types.Withdrawals{}
394+
}
349395
diff := new(big.Int).Sub(block.BlockOverrides.Number.ToInt(), prevNumber)
350396
if diff.Cmp(common.Big0) <= 0 {
351397
return nil, &invalidBlockNumberError{fmt.Sprintf("block numbers must be in order: %d <= %d", block.BlockOverrides.Number.ToInt().Uint64(), prevNumber)}
@@ -360,7 +406,13 @@ func (sim *simulator) sanitizeChain(blocks []simBlock) ([]simBlock, error) {
360406
for i := uint64(0); i < gap.Uint64(); i++ {
361407
n := new(big.Int).Add(prevNumber, big.NewInt(int64(i+1)))
362408
t := prevTimestamp + timestampIncrement
363-
b := simBlock{BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(n), Time: (*hexutil.Uint64)(&t)}}
409+
b := simBlock{
410+
BlockOverrides: &override.BlockOverrides{
411+
Number: (*hexutil.Big)(n),
412+
Time: (*hexutil.Uint64)(&t),
413+
Withdrawals: &types.Withdrawals{},
414+
},
415+
}
364416
prevTimestamp = t
365417
res = append(res, b)
366418
}
@@ -405,6 +457,9 @@ func (sim *simulator) makeHeaders(blocks []simBlock) ([]*types.Header, error) {
405457
var parentBeaconRoot *common.Hash
406458
if sim.chainConfig.IsCancun(overrides.Number.ToInt(), (uint64)(*overrides.Time)) {
407459
parentBeaconRoot = &common.Hash{}
460+
if overrides.BeaconRoot != nil {
461+
parentBeaconRoot = overrides.BeaconRoot
462+
}
408463
}
409464
header = overrides.MakeHeader(&types.Header{
410465
UncleHash: types.EmptyUncleHash,

0 commit comments

Comments
 (0)