Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RPC: Receipts LRU cache #10112

Merged
merged 6 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions turbo/jsonrpc/erigon_receipts.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,14 @@ func (api *ErigonImpl) GetLogsByHash(ctx context.Context, hash common.Hash) ([][
}
defer tx.Rollback()

chainConfig, err := api.chainConfig(ctx, tx)
if err != nil {
return nil, err
}

block, err := api.blockByHashWithSenders(ctx, tx, hash)
if err != nil {
return nil, err
}
if block == nil {
return nil, nil
}
receipts, err := api.getReceipts(ctx, tx, chainConfig, block, block.Body().SendersFromTxs())
receipts, err := api.getReceipts(ctx, tx, block, block.Body().SendersFromTxs())
if err != nil {
return nil, fmt.Errorf("getReceipts error: %w", err)
}
Expand Down Expand Up @@ -426,7 +421,7 @@ func (api *ErigonImpl) GetBlockReceiptsByBlockHash(ctx context.Context, cannonic
if err != nil {
return nil, err
}
receipts, err := api.getReceipts(ctx, tx, chainConfig, block, block.Body().SendersFromTxs())
receipts, err := api.getReceipts(ctx, tx, block, block.Body().SendersFromTxs())
if err != nil {
return nil, fmt.Errorf("getReceipts error: %w", err)
}
Expand Down
33 changes: 28 additions & 5 deletions turbo/jsonrpc/eth_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,11 @@ type EthAPI interface {
}

type BaseAPI struct {
stateCache kvcache.Cache // thread-safe
blocksLRU *lru.Cache[common.Hash, *types.Block] // thread-safe
// all caches are thread-safe
stateCache kvcache.Cache
blocksLRU *lru.Cache[common.Hash, *types.Block]
receiptsCache *lru.Cache[common.Hash, []*types.Receipt]

filters *rpchelper.Filters
_chainConfig atomic.Pointer[chain.Config]
_genesis atomic.Pointer[types.Block]
Expand All @@ -127,16 +130,36 @@ type BaseAPI struct {
}

func NewBaseApi(f *rpchelper.Filters, stateCache kvcache.Cache, blockReader services.FullBlockReader, agg *libstate.Aggregator, singleNodeMode bool, evmCallTimeout time.Duration, engine consensus.EngineReader, dirs datadir.Dirs) *BaseAPI {
blocksLRUSize := 128 // ~32Mb
var (
blocksLRUSize = 128 // ~32Mb
receiptsCacheLimit = 32
)
// if RPCDaemon deployed as independent process: increase cache sizes
if !singleNodeMode {
blocksLRUSize = 512
blocksLRUSize *= 5
receiptsCacheLimit *= 5
}
blocksLRU, err := lru.New[common.Hash, *types.Block](blocksLRUSize)
if err != nil {
panic(err)
}
receiptsCache, err := lru.New[common.Hash, []*types.Receipt](receiptsCacheLimit)
if err != nil {
panic(err)
}

return &BaseAPI{filters: f, stateCache: stateCache, blocksLRU: blocksLRU, _blockReader: blockReader, _txnReader: blockReader, _agg: agg, evmCallTimeout: evmCallTimeout, _engine: engine, dirs: dirs}
return &BaseAPI{
filters: f,
stateCache: stateCache,
blocksLRU: blocksLRU,
receiptsCache: receiptsCache,
_blockReader: blockReader,
_txnReader: blockReader,
_agg: agg,
evmCallTimeout: evmCallTimeout,
_engine: engine,
dirs: dirs,
}
}

func (api *BaseAPI) chainConfig(ctx context.Context, tx kv.Tx) (*chain.Config, error) {
Expand Down
25 changes: 18 additions & 7 deletions turbo/jsonrpc/eth_receipts.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,22 @@ import (
"github.com/ledgerwatch/erigon/turbo/transactions"
)

func (api *BaseAPI) getReceipts(ctx context.Context, tx kv.Tx, chainConfig *chain.Config, block *types.Block, senders []common.Address) (types.Receipts, error) {
if cached := rawdb.ReadReceipts(tx, block, senders); cached != nil {
return cached, nil
// getReceipts - checking in-mem cache, or else fallback to db, or else fallback to re-exec of block to re-gen receipts
func (api *BaseAPI) getReceipts(ctx context.Context, tx kv.Tx, block *types.Block, senders []common.Address) (types.Receipts, error) {
if receipts, ok := api.receiptsCache.Get(block.Hash()); ok {
return receipts, nil
}

if receipts := rawdb.ReadReceipts(tx, block, senders); receipts != nil {
api.receiptsCache.Add(block.Hash(), receipts)
return receipts, nil
}

engine := api.engine()
chainConfig, err := api.chainConfig(ctx, tx)
if err != nil {
return nil, err
}

_, _, _, ibs, _, err := transactions.ComputeTxEnv(ctx, engine, block, chainConfig, api._blockReader, tx, 0, api.historyV3(tx))
if err != nil {
Expand Down Expand Up @@ -71,6 +82,7 @@ func (api *BaseAPI) getReceipts(ctx context.Context, tx kv.Tx, chainConfig *chai
receipts[i] = receipt
}

api.receiptsCache.Add(block.Hash(), receipts)
return receipts, nil
}

Expand All @@ -86,11 +98,10 @@ func (api *APIImpl) GetLogs(ctx context.Context, crit filters.FilterCriteria) (t
defer tx.Rollback()

if crit.BlockHash != nil {
block, err := api._blockReader.BlockByHash(ctx, tx, *crit.BlockHash)
block, err := api.blockByHashWithSenders(ctx, tx, *crit.BlockHash)
if err != nil {
return nil, err
}

if block == nil {
return nil, fmt.Errorf("block not found: %x", *crit.BlockHash)
}
Expand Down Expand Up @@ -648,7 +659,7 @@ func (api *APIImpl) GetTransactionReceipt(ctx context.Context, txnHash common.Ha
borTx = types.NewBorTransaction()
}
}
receipts, err := api.getReceipts(ctx, tx, cc, block, block.Body().SendersFromTxs())
receipts, err := api.getReceipts(ctx, tx, block, block.Body().SendersFromTxs())
if err != nil {
return nil, fmt.Errorf("getReceipts error: %w", err)
}
Expand Down Expand Up @@ -694,7 +705,7 @@ func (api *APIImpl) GetBlockReceipts(ctx context.Context, numberOrHash rpc.Block
if err != nil {
return nil, err
}
receipts, err := api.getReceipts(ctx, tx, chainConfig, block, block.Body().SendersFromTxs())
receipts, err := api.getReceipts(ctx, tx, block, block.Body().SendersFromTxs())
if err != nil {
return nil, fmt.Errorf("getReceipts error: %w", err)
}
Expand Down
29 changes: 8 additions & 21 deletions turbo/jsonrpc/eth_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,7 @@ func (api *APIImpl) GasPrice(ctx context.Context) (*hexutil.Big, error) {
return nil, err
}
defer tx.Rollback()
cc, err := api.chainConfig(ctx, tx)
if err != nil {
return nil, err
}

oracle := gasprice.NewOracle(NewGasPriceOracleBackend(tx, cc, api.BaseAPI), ethconfig.Defaults.GPO, api.gasCache)
oracle := gasprice.NewOracle(NewGasPriceOracleBackend(tx, api.BaseAPI), ethconfig.Defaults.GPO, api.gasCache)
tipcap, err := oracle.SuggestTipCap(ctx)
gasResult := big.NewInt(0)

Expand All @@ -138,11 +133,7 @@ func (api *APIImpl) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, err
return nil, err
}
defer tx.Rollback()
cc, err := api.chainConfig(ctx, tx)
if err != nil {
return nil, err
}
oracle := gasprice.NewOracle(NewGasPriceOracleBackend(tx, cc, api.BaseAPI), ethconfig.Defaults.GPO, api.gasCache)
oracle := gasprice.NewOracle(NewGasPriceOracleBackend(tx, api.BaseAPI), ethconfig.Defaults.GPO, api.gasCache)
tipcap, err := oracle.SuggestTipCap(ctx)
if err != nil {
return nil, err
Expand All @@ -163,11 +154,7 @@ func (api *APIImpl) FeeHistory(ctx context.Context, blockCount rpc.DecimalOrHex,
return nil, err
}
defer tx.Rollback()
cc, err := api.chainConfig(ctx, tx)
if err != nil {
return nil, err
}
oracle := gasprice.NewOracle(NewGasPriceOracleBackend(tx, cc, api.BaseAPI), ethconfig.Defaults.GPO, api.gasCache)
oracle := gasprice.NewOracle(NewGasPriceOracleBackend(tx, api.BaseAPI), ethconfig.Defaults.GPO, api.gasCache)

oldest, reward, baseFee, gasUsed, err := oracle.FeeHistory(ctx, int(blockCount), lastBlock, rewardPercentiles)
if err != nil {
Expand Down Expand Up @@ -197,12 +184,11 @@ func (api *APIImpl) FeeHistory(ctx context.Context, blockCount rpc.DecimalOrHex,

type GasPriceOracleBackend struct {
tx kv.Tx
cc *chain.Config
baseApi *BaseAPI
}

func NewGasPriceOracleBackend(tx kv.Tx, cc *chain.Config, baseApi *BaseAPI) *GasPriceOracleBackend {
return &GasPriceOracleBackend{tx: tx, cc: cc, baseApi: baseApi}
func NewGasPriceOracleBackend(tx kv.Tx, baseApi *BaseAPI) *GasPriceOracleBackend {
return &GasPriceOracleBackend{tx: tx, baseApi: baseApi}
}

func (b *GasPriceOracleBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
Expand All @@ -219,10 +205,11 @@ func (b *GasPriceOracleBackend) BlockByNumber(ctx context.Context, number rpc.Bl
return b.baseApi.blockByRPCNumber(ctx, number, b.tx)
}
func (b *GasPriceOracleBackend) ChainConfig() *chain.Config {
return b.cc
cc, _ := b.baseApi.chainConfig(context.Background(), b.tx)
return cc
}
func (b *GasPriceOracleBackend) GetReceipts(ctx context.Context, block *types.Block) (types.Receipts, error) {
return rawdb.ReadReceipts(b.tx, block, nil), nil
return b.baseApi.getReceipts(ctx, b.tx, block, nil)
}
func (b *GasPriceOracleBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) {
return nil, nil
Expand Down
12 changes: 9 additions & 3 deletions turbo/jsonrpc/graphql_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (api *GraphQLAPIImpl) GetBlockDetails(ctx context.Context, blockNumber rpc.
return nil, err
}

receipts, err := api.getReceipts(ctx, tx, chainConfig, block, senders)
receipts, err := api.getReceipts(ctx, tx, block, senders)
if err != nil {
return nil, fmt.Errorf("getReceipts error: %w", err)
}
Expand Down Expand Up @@ -107,8 +107,14 @@ func (api *GraphQLAPIImpl) getBlockWithSenders(ctx context.Context, number rpc.B
return nil, nil, err
}

block, senders, err := api._blockReader.BlockWithSenders(ctx, tx, blockHash, blockHeight)
return block, senders, err
block, err := api.blockWithSenders(ctx, tx, blockHash, blockHeight)
if err != nil {
return nil, nil, err
}
if block == nil {
return nil, nil, nil
}
return block, block.Body().SendersFromTxs(), nil
}

func (api *GraphQLAPIImpl) delegateGetBlockByNumber(tx kv.Tx, b *types.Block, number rpc.BlockNumber, inclTx bool) (map[string]interface{}, error) {
Expand Down
12 changes: 9 additions & 3 deletions turbo/jsonrpc/otterscan_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -573,8 +573,14 @@ func (api *OtterscanAPIImpl) getBlockWithSenders(ctx context.Context, number rpc
return nil, nil, err
}

block, senders, err := api._blockReader.BlockWithSenders(ctx, tx, hash, n)
return block, senders, err
block, err := api.blockWithSenders(ctx, tx, hash, n)
if err != nil {
return nil, nil, err
}
if block == nil {
return nil, nil, nil
}
return block, block.Body().SendersFromTxs(), nil
}

func (api *OtterscanAPIImpl) GetBlockTransactions(ctx context.Context, number rpc.BlockNumber, pageNumber uint8, pageSize uint8) (map[string]interface{}, error) {
Expand Down Expand Up @@ -603,7 +609,7 @@ func (api *OtterscanAPIImpl) GetBlockTransactions(ctx context.Context, number rp
}

// Receipts
receipts, err := api.getReceipts(ctx, tx, chainConfig, b, senders)
receipts, err := api.getReceipts(ctx, tx, b, senders)
if err != nil {
return nil, fmt.Errorf("getReceipts error: %v", err)
}
Expand Down
6 changes: 3 additions & 3 deletions turbo/jsonrpc/otterscan_block_details.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (api *OtterscanAPIImpl) GetBlockDetailsByHash(ctx context.Context, hash com
if blockNumber == nil {
return nil, fmt.Errorf("couldn't find block number for hash %v", hash.Bytes())
}
b, senders, err := api._blockReader.BlockWithSenders(ctx, tx, hash, *blockNumber)
b, err := api.blockWithSenders(ctx, tx, hash, *blockNumber)
if err != nil {
return nil, err
}
Expand All @@ -53,7 +53,7 @@ func (api *OtterscanAPIImpl) GetBlockDetailsByHash(ctx context.Context, hash com
}
number := rpc.BlockNumber(b.Number().Int64())

return api.getBlockDetailsImpl(ctx, tx, b, number, senders)
return api.getBlockDetailsImpl(ctx, tx, b, number, b.Body().SendersFromTxs())
}

func (api *OtterscanAPIImpl) getBlockDetailsImpl(ctx context.Context, tx kv.Tx, b *types.Block, number rpc.BlockNumber, senders []common.Address) (map[string]interface{}, error) {
Expand All @@ -70,7 +70,7 @@ func (api *OtterscanAPIImpl) getBlockDetailsImpl(ctx context.Context, tx kv.Tx,
if err != nil {
return nil, err
}
receipts, err := api.getReceipts(ctx, tx, chainConfig, b, senders)
receipts, err := api.getReceipts(ctx, tx, b, senders)
if err != nil {
return nil, fmt.Errorf("getReceipts error: %v", err)
}
Expand Down
8 changes: 5 additions & 3 deletions turbo/jsonrpc/otterscan_search_trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/erigon/core"
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/core/state"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/vm"
Expand Down Expand Up @@ -48,7 +47,7 @@ func (api *OtterscanAPIImpl) traceBlock(dbtx kv.Tx, ctx context.Context, blockNu
return false, nil, err
}

block, senders, err := api._blockReader.BlockWithSenders(ctx, dbtx, blockHash, blockNum)
block, err := api.blockWithSenders(ctx, dbtx, blockHash, blockNum)
if err != nil {
return false, nil, err
}
Expand All @@ -74,7 +73,10 @@ func (api *OtterscanAPIImpl) traceBlock(dbtx kv.Tx, ctx context.Context, blockNu
}
engine := api.engine()

blockReceipts := rawdb.ReadReceipts(dbtx, block, senders)
blockReceipts, err := api.getReceipts(ctx, dbtx, block, block.Body().SendersFromTxs())
if err != nil {
return false, nil, err
}
header := block.Header()
rules := chainConfig.Rules(block.NumberU64(), header.Time)
found := false
Expand Down
3 changes: 2 additions & 1 deletion turbo/jsonrpc/otterscan_transaction_by_sender_and_nonce.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,10 +276,11 @@ func (api *OtterscanAPIImpl) findNonce(ctx context.Context, tx kv.Tx, addr commo
if err != nil {
return false, common.Hash{}, err
}
block, senders, err := api._blockReader.BlockWithSenders(ctx, tx, hash, blockNum)
block, err := api.blockWithSenders(ctx, tx, hash, blockNum)
if err != nil {
return false, common.Hash{}, err
}
senders := block.Body().SendersFromTxs()

txs := block.Transactions()
for i, s := range senders {
Expand Down
4 changes: 2 additions & 2 deletions turbo/jsonrpc/overlay_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ func (api *OverlayAPIImpl) replayBlock(ctx context.Context, blockNum uint64, sta
gp := new(core.GasPool).AddGas(math.MaxUint64).AddBlobGas(math.MaxUint64)
vmConfig := vm.Config{Debug: false}
evm = vm.NewEVM(blockCtx, evmtypes.TxContext{}, statedb, chainConfig, vmConfig)
receipts, err := api.getReceipts(ctx, tx, chainConfig, block, block.Body().SendersFromTxs())
receipts, err := api.getReceipts(ctx, tx, block, block.Body().SendersFromTxs())
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -566,7 +566,7 @@ func (api *OverlayAPIImpl) replayBlock(ctx context.Context, blockNum uint64, sta
func getBeginEnd(ctx context.Context, tx kv.Tx, api *OverlayAPIImpl, crit filters.FilterCriteria) (uint64, uint64, error) {
var begin, end uint64
if crit.BlockHash != nil {
block, err := api._blockReader.BlockByHash(ctx, tx, *crit.BlockHash)
block, err := api.blockByHashWithSenders(ctx, tx, *crit.BlockHash)
if err != nil {
return 0, 0, err
}
Expand Down
Loading