Skip to content

Commit 74c050a

Browse files
committed
Support block overrides for eth_call & debug_traceCall endpoints
1 parent a9c1289 commit 74c050a

File tree

7 files changed

+348
-28
lines changed

7 files changed

+348
-28
lines changed

api/api.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ func (b *BlockChainAPI) Call(
539539
args ethTypes.TransactionArgs,
540540
blockNumberOrHash *rpc.BlockNumberOrHash,
541541
stateOverrides *ethTypes.StateOverride,
542-
_ *ethTypes.BlockOverrides,
542+
blockOverrides *ethTypes.BlockOverrides,
543543
) (hexutil.Bytes, error) {
544544
l := b.logger.With().
545545
Str("endpoint", "call").
@@ -576,7 +576,7 @@ func (b *BlockChainAPI) Call(
576576
from = *args.From
577577
}
578578

579-
res, err := b.evm.Call(tx, from, height, stateOverrides)
579+
res, err := b.evm.Call(tx, from, height, stateOverrides, blockOverrides)
580580
if err != nil {
581581
return handleError[hexutil.Bytes](err, l, b.collector)
582582
}

api/debug.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,11 +175,19 @@ func (d *DebugAPI) TraceCall(
175175
return nil, err
176176
}
177177

178-
blocksProvider := replayer.NewBlocksProvider(
178+
blocksProvider := requester.NewBlocksProvider(
179179
d.blocks,
180180
d.config.FlowNetworkID,
181-
tracer,
182181
)
182+
blocksProvider.SetTracer(tracer)
183+
if config.BlockOverrides != nil {
184+
blocksProvider.SetBlockOverrides(&ethTypes.BlockOverrides{
185+
Number: config.BlockOverrides.Number,
186+
Time: config.BlockOverrides.Time,
187+
Coinbase: config.BlockOverrides.Coinbase,
188+
Random: config.BlockOverrides.Random,
189+
})
190+
}
183191
viewProvider := query.NewViewProvider(
184192
d.config.FlowNetworkID,
185193
flowEVM.StorageAccountAddress(d.config.FlowNetworkID),

bootstrap/bootstrap.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,9 @@ func (b *Bootstrap) StartAPIServer(ctx context.Context) error {
208208
b.config,
209209
)
210210

211-
blocksProvider := replayer.NewBlocksProvider(
211+
blocksProvider := requester.NewBlocksProvider(
212212
b.storages.Blocks,
213213
b.config.FlowNetworkID,
214-
nil,
215214
)
216215

217216
accountKeys := make([]*requester.AccountKey, 0)
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package requester
2+
3+
import (
4+
ethTypes "github.com/onflow/flow-evm-gateway/eth/types"
5+
"github.com/onflow/flow-evm-gateway/models"
6+
"github.com/onflow/flow-evm-gateway/storage"
7+
"github.com/onflow/flow-go/fvm/evm/offchain/blocks"
8+
evmTypes "github.com/onflow/flow-go/fvm/evm/types"
9+
flowGo "github.com/onflow/flow-go/model/flow"
10+
gethCommon "github.com/onflow/go-ethereum/common"
11+
"github.com/onflow/go-ethereum/eth/tracers"
12+
)
13+
14+
type blockSnapshot struct {
15+
*BlocksProvider
16+
block models.Block
17+
}
18+
19+
var _ evmTypes.BlockSnapshot = (*blockSnapshot)(nil)
20+
21+
func (bs *blockSnapshot) BlockContext() (evmTypes.BlockContext, error) {
22+
blockContext, err := blocks.NewBlockContext(
23+
bs.chainID,
24+
bs.block.Height,
25+
bs.block.Timestamp,
26+
func(n uint64) gethCommon.Hash {
27+
block, err := bs.blocks.GetByHeight(n)
28+
if err != nil {
29+
return gethCommon.Hash{}
30+
}
31+
blockHash, err := block.Hash()
32+
if err != nil {
33+
return gethCommon.Hash{}
34+
}
35+
36+
return blockHash
37+
},
38+
bs.block.PrevRandao,
39+
bs.tracer,
40+
)
41+
if err != nil {
42+
return evmTypes.BlockContext{}, err
43+
}
44+
45+
if bs.blockOverrides == nil {
46+
return blockContext, nil
47+
}
48+
49+
if bs.blockOverrides.Number != nil {
50+
blockContext.BlockNumber = bs.blockOverrides.Number.ToInt().Uint64()
51+
}
52+
53+
if bs.blockOverrides.Time != nil {
54+
blockContext.BlockTimestamp = uint64(*bs.blockOverrides.Time)
55+
}
56+
57+
if bs.blockOverrides.Random != nil {
58+
blockContext.Random = *bs.blockOverrides.Random
59+
}
60+
61+
if bs.blockOverrides.Coinbase != nil {
62+
blockContext.GasFeeCollector = evmTypes.NewAddress(*bs.blockOverrides.Coinbase)
63+
}
64+
65+
return blockContext, nil
66+
}
67+
68+
type BlocksProvider struct {
69+
blocks storage.BlockIndexer
70+
chainID flowGo.ChainID
71+
tracer *tracers.Tracer
72+
blockOverrides *ethTypes.BlockOverrides
73+
}
74+
75+
var _ evmTypes.BlockSnapshotProvider = (*BlocksProvider)(nil)
76+
77+
func NewBlocksProvider(
78+
blocks storage.BlockIndexer,
79+
chainID flowGo.ChainID,
80+
) *BlocksProvider {
81+
return &BlocksProvider{
82+
blocks: blocks,
83+
chainID: chainID,
84+
}
85+
}
86+
87+
func (bp *BlocksProvider) SetTracer(tracer *tracers.Tracer) {
88+
bp.tracer = tracer
89+
}
90+
91+
func (bp *BlocksProvider) SetBlockOverrides(blockOverrides *ethTypes.BlockOverrides) {
92+
bp.blockOverrides = blockOverrides
93+
}
94+
95+
func (bp *BlocksProvider) GetSnapshotAt(height uint64) (
96+
evmTypes.BlockSnapshot,
97+
error,
98+
) {
99+
block, err := bp.blocks.GetByHeight(height)
100+
if err != nil {
101+
return nil, err
102+
}
103+
104+
return &blockSnapshot{
105+
BlocksProvider: bp,
106+
block: *block,
107+
}, nil
108+
}

services/requester/requester.go

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
"github.com/onflow/flow-evm-gateway/metrics"
2828
"github.com/onflow/flow-evm-gateway/models"
2929
errs "github.com/onflow/flow-evm-gateway/models/errors"
30-
"github.com/onflow/flow-evm-gateway/services/replayer"
3130
"github.com/onflow/flow-evm-gateway/storage"
3231
"github.com/onflow/flow-evm-gateway/storage/pebble"
3332

@@ -66,6 +65,7 @@ type Requester interface {
6665
from common.Address,
6766
height uint64,
6867
stateOverrides *ethTypes.StateOverride,
68+
blockOverrides *ethTypes.BlockOverrides,
6969
) ([]byte, error)
7070

7171
// EstimateGas executes the given signed transaction data on the state for the given EVM block height.
@@ -95,15 +95,16 @@ type Requester interface {
9595
var _ Requester = &EVM{}
9696

9797
type EVM struct {
98-
registerStore *pebble.RegisterStorage
99-
blocksProvider *replayer.BlocksProvider
100-
client *CrossSporkClient
101-
config config.Config
102-
txPool *TxPool
103-
logger zerolog.Logger
104-
blocks storage.BlockIndexer
105-
mux sync.Mutex
106-
keystore *KeyStore
98+
registerStore *pebble.RegisterStorage
99+
blocksProvider *BlocksProvider
100+
client *CrossSporkClient
101+
config config.Config
102+
txPool *TxPool
103+
logger zerolog.Logger
104+
blocks storage.BlockIndexer
105+
mux sync.Mutex
106+
keystore *KeyStore
107+
107108
head *types.Header
108109
evmSigner types.Signer
109110
validationOptions *txpool.ValidationOptions
@@ -112,7 +113,7 @@ type EVM struct {
112113

113114
func NewEVM(
114115
registerStore *pebble.RegisterStorage,
115-
blocksProvider *replayer.BlocksProvider,
116+
blocksProvider *BlocksProvider,
116117
client *CrossSporkClient,
117118
config config.Config,
118119
logger zerolog.Logger,
@@ -250,7 +251,7 @@ func (e *EVM) GetBalance(
250251
address common.Address,
251252
height uint64,
252253
) (*big.Int, error) {
253-
view, err := e.getBlockView(height)
254+
view, err := e.getBlockView(height, nil)
254255
if err != nil {
255256
return nil, err
256257
}
@@ -262,7 +263,7 @@ func (e *EVM) GetNonce(
262263
address common.Address,
263264
height uint64,
264265
) (uint64, error) {
265-
view, err := e.getBlockView(height)
266+
view, err := e.getBlockView(height, nil)
266267
if err != nil {
267268
return 0, err
268269
}
@@ -275,7 +276,7 @@ func (e *EVM) GetStorageAt(
275276
hash common.Hash,
276277
height uint64,
277278
) (common.Hash, error) {
278-
view, err := e.getBlockView(height)
279+
view, err := e.getBlockView(height, nil)
279280
if err != nil {
280281
return common.Hash{}, err
281282
}
@@ -288,8 +289,9 @@ func (e *EVM) Call(
288289
from common.Address,
289290
height uint64,
290291
stateOverrides *ethTypes.StateOverride,
292+
blockOverrides *ethTypes.BlockOverrides,
291293
) ([]byte, error) {
292-
result, err := e.dryRunTx(tx, from, height, stateOverrides)
294+
result, err := e.dryRunTx(tx, from, height, stateOverrides, blockOverrides)
293295
if err != nil {
294296
return nil, err
295297
}
@@ -327,7 +329,7 @@ func (e *EVM) EstimateGas(
327329
tx.Gas = passingGasLimit
328330
// We first execute the transaction at the highest allowable gas limit,
329331
// since if this fails we can return the error immediately.
330-
result, err := e.dryRunTx(tx, from, height, stateOverrides)
332+
result, err := e.dryRunTx(tx, from, height, stateOverrides, nil)
331333
if err != nil {
332334
return 0, err
333335
}
@@ -352,7 +354,7 @@ func (e *EVM) EstimateGas(
352354
optimisticGasLimit := (result.GasConsumed + result.GasRefund + gethParams.CallStipend) * 64 / 63
353355
if optimisticGasLimit < passingGasLimit {
354356
tx.Gas = optimisticGasLimit
355-
result, err = e.dryRunTx(tx, from, height, stateOverrides)
357+
result, err = e.dryRunTx(tx, from, height, stateOverrides, nil)
356358
if err != nil {
357359
// This should not happen under normal conditions since if we make it this far the
358360
// transaction had run without error at least once before.
@@ -382,7 +384,7 @@ func (e *EVM) EstimateGas(
382384
mid = failingGasLimit * 2
383385
}
384386
tx.Gas = mid
385-
result, err = e.dryRunTx(tx, from, height, stateOverrides)
387+
result, err = e.dryRunTx(tx, from, height, stateOverrides, nil)
386388
if err != nil {
387389
return 0, err
388390
}
@@ -405,7 +407,7 @@ func (e *EVM) GetCode(
405407
address common.Address,
406408
height uint64,
407409
) ([]byte, error) {
408-
view, err := e.getBlockView(height)
410+
view, err := e.getBlockView(height, nil)
409411
if err != nil {
410412
return nil, err
411413
}
@@ -437,7 +439,14 @@ func (e *EVM) GetLatestEVMHeight(ctx context.Context) (uint64, error) {
437439
return height, nil
438440
}
439441

440-
func (e *EVM) getBlockView(height uint64) (*query.View, error) {
442+
func (e *EVM) getBlockView(
443+
height uint64,
444+
blockOverrides *ethTypes.BlockOverrides,
445+
) (*query.View, error) {
446+
if blockOverrides != nil {
447+
e.blocksProvider.SetBlockOverrides(blockOverrides)
448+
}
449+
441450
viewProvider := query.NewViewProvider(
442451
e.config.FlowNetworkID,
443452
evm.StorageAccountAddress(e.config.FlowNetworkID),
@@ -467,8 +476,9 @@ func (e *EVM) dryRunTx(
467476
from common.Address,
468477
height uint64,
469478
stateOverrides *ethTypes.StateOverride,
479+
blockOverrides *ethTypes.BlockOverrides,
470480
) (*evmTypes.Result, error) {
471-
view, err := e.getBlockView(height)
481+
view, err := e.getBlockView(height, blockOverrides)
472482
if err != nil {
473483
return nil, err
474484
}
@@ -592,7 +602,7 @@ func (e *EVM) validateTransactionWithState(
592602
if err != nil {
593603
return err
594604
}
595-
view, err := e.getBlockView(height)
605+
view, err := e.getBlockView(height, nil)
596606
if err != nil {
597607
return err
598608
}

tests/e2e_web3js_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ func TestWeb3_E2E(t *testing.T) {
4040
runWeb3Test(t, "debug_util_test")
4141
})
4242

43+
t.Run("test contract call overrides", func(t *testing.T) {
44+
runWeb3Test(t, "contract_call_overrides_test")
45+
})
46+
4347
t.Run("test setup sanity check", func(t *testing.T) {
4448
runWeb3Test(t, "setup_test")
4549
})

0 commit comments

Comments
 (0)