diff --git a/api/api.go b/api/api.go index 78db1c6a..89d680d7 100644 --- a/api/api.go +++ b/api/api.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/filters" @@ -89,6 +90,8 @@ type BlockChainAPI struct { indexingResumedHeight uint64 rateLimiter RateLimiter collector metrics.Collector + + blockByNumberCache *lru.Cache[uint64, *ethTypes.Block] } func NewBlockChainAPI( @@ -101,6 +104,7 @@ func NewBlockChainAPI( rateLimiter RateLimiter, collector metrics.Collector, indexingResumedHeight uint64, + blockByNumberCacheSize int, ) *BlockChainAPI { return &BlockChainAPI{ logger: logger, @@ -112,6 +116,7 @@ func NewBlockChainAPI( indexingResumedHeight: indexingResumedHeight, rateLimiter: rateLimiter, collector: collector, + blockByNumberCache: lru.NewCache[uint64, *ethTypes.Block](blockByNumberCacheSize), } } @@ -407,6 +412,10 @@ func (b *BlockChainAPI) GetBlockByNumber( return handleError[*ethTypes.Block](err, l, b.collector) } + if block, ok := b.blockByNumberCache.Get(height); ok { + return block, nil + } + block, err := b.blocks.GetByHeight(height) if err != nil { @@ -418,6 +427,8 @@ func (b *BlockChainAPI) GetBlockByNumber( return handleError[*ethTypes.Block](err, l, b.collector) } + _ = b.blockByNumberCache.Add(height, apiBlock) + return apiBlock, nil } diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go index 3aa4a0ef..c220c41c 100644 --- a/bootstrap/bootstrap.go +++ b/bootstrap/bootstrap.go @@ -352,6 +352,7 @@ func (b *Bootstrap) StartAPIServer(ctx context.Context) error { rateLimiter, b.collector, indexingResumedHeight, + b.config.BlockByNumberCacheSize, ) streamAPI := api.NewStreamAPI( diff --git a/cmd/run/cmd.go b/cmd/run/cmd.go index e3b22cf1..4bedd242 100644 --- a/cmd/run/cmd.go +++ b/cmd/run/cmd.go @@ -300,6 +300,7 @@ func init() { Cmd.Flags().BoolVar(&experimentalSealingVerificationEnabled, "experimental-sealing-verification-enabled", true, "Sets whether the gateway should use the experimental soft finality sealing verification feature. WARNING: This may result in indexing halts if events do not match. Use only if you know what you are doing.") Cmd.Flags().DurationVar(&cfg.EOAActivityCacheTTL, "eoa-activity-cache-ttl", time.Second*10, "Time interval used to track EOA activity. Tx send more frequently than this interval will be batched. Useful only when batch transaction submission is enabled.") Cmd.Flags().DurationVar(&cfg.RpcRequestTimeout, "rpc-request-timeout", time.Second*120, "Sets the maximum duration at which JSON-RPC requests should generate a response, before they timeout. The default is 120 seconds.") + Cmd.Flags().IntVar(&cfg.BlockByNumberCacheSize, "block-by-number-cache-size", 1000, "Number of block cache for getBlockByNumber API.") err := Cmd.Flags().MarkDeprecated("init-cadence-height", "This flag is no longer necessary and will be removed in future version. The initial Cadence height is known for testnet/mainnet and this was only required for fresh deployments of EVM Gateway. Once the DB has been initialized, the latest index Cadence height will be used upon start-up.") if err != nil { diff --git a/config/config.go b/config/config.go index 10694f0b..5ae03fa0 100644 --- a/config/config.go +++ b/config/config.go @@ -136,4 +136,6 @@ type Config struct { // RpcRequestTimeout is the maximum duration at which JSON-RPC requests should generate // a response, before they timeout. RpcRequestTimeout time.Duration + // BlockByNumberCacheSize is the size of the block by number cache. + BlockByNumberCacheSize int }