From da79cd348f51382621557902c7176bd10fe494b6 Mon Sep 17 00:00:00 2001 From: Ardit Marku Date: Wed, 8 Jan 2025 16:59:33 +0200 Subject: [PATCH] Update API of requester.BlocksProvider type to avoid concurrency issues --- api/debug.go | 5 ++--- bootstrap/bootstrap.go | 6 ------ services/replayer/blocks_provider.go | 7 +++++++ services/requester/blocks_provider.go | 24 ++++++++++++++++++++---- services/requester/requester.go | 25 ++++++++++++------------- 5 files changed, 41 insertions(+), 26 deletions(-) diff --git a/api/debug.go b/api/debug.go index c19f76870..113f99e99 100644 --- a/api/debug.go +++ b/api/debug.go @@ -178,10 +178,9 @@ func (d *DebugAPI) TraceCall( blocksProvider := requester.NewBlocksProvider( d.blocks, d.config.FlowNetworkID, - ) - blocksProvider.SetTracer(tracer) + ).WithTracer(tracer) if config.BlockOverrides != nil { - blocksProvider.SetBlockOverrides(ðTypes.BlockOverrides{ + blocksProvider = blocksProvider.WithBlockOverrides(ðTypes.BlockOverrides{ Number: config.BlockOverrides.Number, Time: config.BlockOverrides.Time, Coinbase: config.BlockOverrides.Coinbase, diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go index de844548a..3eea9bf83 100644 --- a/bootstrap/bootstrap.go +++ b/bootstrap/bootstrap.go @@ -193,11 +193,6 @@ func (b *Bootstrap) StartAPIServer(ctx context.Context) error { b.config, ) - blocksProvider := requester.NewBlocksProvider( - b.storages.Blocks, - b.config.FlowNetworkID, - ) - accountKeys := make([]*requester.AccountKey, 0) if !b.config.IndexOnly { account, err := b.client.GetAccount(ctx, b.config.COAAddress) @@ -230,7 +225,6 @@ func (b *Bootstrap) StartAPIServer(ctx context.Context) error { evm, err := requester.NewEVM( b.storages.Registers, - blocksProvider, b.client, b.config, b.logger, diff --git a/services/replayer/blocks_provider.go b/services/replayer/blocks_provider.go index 9cb2dfbe1..ab1ed0b59 100644 --- a/services/replayer/blocks_provider.go +++ b/services/replayer/blocks_provider.go @@ -41,6 +41,13 @@ func (bs *blockSnapshot) BlockContext() (evmTypes.BlockContext, error) { ) } +// This BlocksProvider implementation is used in the EVM events ingestion pipeline. +// The ingestion module notifies the BlocksProvider of incoming EVM blocks, by +// calling the `OnBlockReceived` method. This method guarantees that blocks are +// processed sequentially, and keeps track of the latest block, which is used +// for generating the proper `BlockContext`. This is necessary for replaying +// EVM blocks/transactions locally, and verifying that there are no state +// mismatches. type BlocksProvider struct { blocks storage.BlockIndexer chainID flowGo.ChainID diff --git a/services/requester/blocks_provider.go b/services/requester/blocks_provider.go index 48d3948b6..e465e0349 100644 --- a/services/requester/blocks_provider.go +++ b/services/requester/blocks_provider.go @@ -65,6 +65,10 @@ func (bs *blockSnapshot) BlockContext() (evmTypes.BlockContext, error) { return blockContext, nil } +// This BlocksProvider implementation is only used for the `eth_call` & +// `debug_traceCall` JSON-RPC endpoints. It accepts optional `Tracer` & +// `BlockOverrides` objects, which are used when constructing the +// `BlockContext` object. type BlocksProvider struct { blocks storage.BlockIndexer chainID flowGo.ChainID @@ -84,12 +88,24 @@ func NewBlocksProvider( } } -func (bp *BlocksProvider) SetTracer(tracer *tracers.Tracer) { - bp.tracer = tracer +func (bp *BlocksProvider) WithTracer(tracer *tracers.Tracer) *BlocksProvider { + return &BlocksProvider{ + blocks: bp.blocks, + chainID: bp.chainID, + tracer: tracer, + blockOverrides: bp.blockOverrides, + } } -func (bp *BlocksProvider) SetBlockOverrides(blockOverrides *ethTypes.BlockOverrides) { - bp.blockOverrides = blockOverrides +func (bp *BlocksProvider) WithBlockOverrides( + blockOverrides *ethTypes.BlockOverrides, +) *BlocksProvider { + return &BlocksProvider{ + blocks: bp.blocks, + chainID: bp.chainID, + tracer: bp.tracer, + blockOverrides: blockOverrides, + } } func (bp *BlocksProvider) GetSnapshotAt(height uint64) ( diff --git a/services/requester/requester.go b/services/requester/requester.go index d1ae7a232..78ddacc7e 100644 --- a/services/requester/requester.go +++ b/services/requester/requester.go @@ -95,15 +95,14 @@ type Requester interface { var _ Requester = &EVM{} type EVM struct { - registerStore *pebble.RegisterStorage - blocksProvider *BlocksProvider - client *CrossSporkClient - config config.Config - txPool *TxPool - logger zerolog.Logger - blocks storage.BlockIndexer - mux sync.Mutex - keystore *KeyStore + registerStore *pebble.RegisterStorage + client *CrossSporkClient + config config.Config + txPool *TxPool + logger zerolog.Logger + blocks storage.BlockIndexer + mux sync.Mutex + keystore *KeyStore head *types.Header evmSigner types.Signer @@ -113,7 +112,6 @@ type EVM struct { func NewEVM( registerStore *pebble.RegisterStorage, - blocksProvider *BlocksProvider, client *CrossSporkClient, config config.Config, logger zerolog.Logger, @@ -168,7 +166,6 @@ func NewEVM( evm := &EVM{ registerStore: registerStore, - blocksProvider: blocksProvider, client: client, config: config, logger: logger, @@ -443,15 +440,17 @@ func (e *EVM) getBlockView( height uint64, blockOverrides *ethTypes.BlockOverrides, ) (*query.View, error) { + blocksProvider := NewBlocksProvider(e.blocks, e.config.FlowNetworkID) + if blockOverrides != nil { - e.blocksProvider.SetBlockOverrides(blockOverrides) + blocksProvider = blocksProvider.WithBlockOverrides(blockOverrides) } viewProvider := query.NewViewProvider( e.config.FlowNetworkID, evm.StorageAccountAddress(e.config.FlowNetworkID), e.registerStore, - e.blocksProvider, + blocksProvider, blockGasLimit, )