Skip to content

Commit

Permalink
Reducing block calls (#13157)
Browse files Browse the repository at this point in the history
closes #11347
closes #13156

---------

Co-authored-by: JkLondon <ilya@mikheev.fun>
Co-authored-by: alex.sharov <AskAlexSharov@gmail.com>
  • Loading branch information
3 people authored Dec 24, 2024
1 parent 8c182b2 commit ec2b7b2
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 46 deletions.
6 changes: 6 additions & 0 deletions turbo/jsonrpc/debug_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ func TestTraceBlockByNumber(t *testing.T) {
if err != nil {
t.Errorf("traceBlock %s: %v", tt.txHash, err)
}
if tx == nil {
t.Errorf("nil tx")
}
if tx.BlockHash == nil {
t.Errorf("nil block hash")
}
txcount, err := ethApi.GetBlockTransactionCountByHash(m.Ctx, *tx.BlockHash)
if err != nil {
t.Errorf("traceBlock %s: %v", tt.txHash, err)
Expand Down
42 changes: 27 additions & 15 deletions turbo/jsonrpc/eth_receipts.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ func (api *BaseAPI) getReceipts(ctx context.Context, tx kv.TemporalTx, block *ty
return api.receiptsGenerator.GetReceipts(ctx, chainConfig, tx, block)
}

func (api *BaseAPI) getReceipt(ctx context.Context, cc *chain.Config, tx kv.TemporalTx, block *types.Block, index int, txNum uint64) (*types.Receipt, error) {
return api.receiptsGenerator.GetReceipt(ctx, cc, tx, block, index, txNum)
func (api *BaseAPI) getReceipt(ctx context.Context, cc *chain.Config, tx kv.TemporalTx, header *types.Header, txn types.Transaction, index int, txNum uint64) (*types.Receipt, error) {
return api.receiptsGenerator.GetReceipt(ctx, cc, tx, header, txn, index, txNum)
}

func (api *BaseAPI) getCachedReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, bool) {
Expand Down Expand Up @@ -449,25 +449,37 @@ func (api *APIImpl) GetTransactionReceipt(ctx context.Context, txnHash common.Ha
return nil, nil
}

block, err := api.blockByNumberWithSenders(ctx, tx, blockNum)
header, err := api._blockReader.HeaderByNumber(ctx, tx, blockNum)
if err != nil {
return nil, err
}
if block == nil {
return nil, nil // not error, see https://github.com/erigontech/erigon/issues/1645

txNumsReader := rawdbv3.TxNums.WithCustomReadTxNumFunc(freezeblocks.ReadTxNumFuncFromBlockReader(ctx, api._blockReader))

txNumMin, err := txNumsReader.Min(tx, blockNum)
if err != nil {
return nil, err
}

var txnIndex uint64
var txn types.Transaction
for idx, transaction := range block.Transactions() {
if transaction.Hash() == txnHash {
txn = transaction
txnIndex = uint64(idx)
break
}
if txNumMin+2 > txNum { //TODO: what a magic is this "2" and how to avoid it
return nil, fmt.Errorf("uint underflow txnums error txNum: %d, txNumMin: %d, blockNum: %d", txNum, txNumMin, blockNum)
}

var txnIndex = int(txNum - txNumMin - 2)

txn, err := api._blockReader.TxnByIdxInBlock(ctx, tx, header.Number.Uint64(), txnIndex)
if err != nil {
return nil, err
}

if txn == nil && chainConfig.Bor != nil { //TODO: add tx gran here to.
block, err := api.blockByNumberWithSenders(ctx, tx, blockNum)
if err != nil {
return nil, err
}
if block == nil {
return nil, nil // not error, see https://github.com/erigontech/erigon/issues/1645
}
receipts, err := api.getReceipts(ctx, tx, block)
if err != nil {
return nil, fmt.Errorf("getReceipts error: %w", err)
Expand All @@ -490,12 +502,12 @@ func (api *APIImpl) GetTransactionReceipt(ctx context.Context, txnHash common.Ha
return ethutils.MarshalReceipt(borReceipt, bortypes.NewBorTransaction(), chainConfig, block.HeaderNoCopy(), txnHash, false), nil
}

receipt, err := api.getReceipt(ctx, chainConfig, tx, block, int(txnIndex), txNum)
receipt, err := api.getReceipt(ctx, chainConfig, tx, header, txn, txnIndex, txNum)
if err != nil {
return nil, fmt.Errorf("getReceipt error: %w", err)
}

return ethutils.MarshalReceipt(receipt, block.Transactions()[txnIndex], chainConfig, block.HeaderNoCopy(), txnHash, true), nil
return ethutils.MarshalReceipt(receipt, txn, chainConfig, header, txnHash, true), nil
}

// GetBlockReceipts - receipts for individual block
Expand Down
49 changes: 34 additions & 15 deletions turbo/jsonrpc/eth_txs.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ package jsonrpc
import (
"bytes"
"context"
"fmt"
"math/big"

"github.com/erigontech/erigon-lib/kv/rawdbv3"
"github.com/erigontech/erigon/turbo/snapshotsync/freezeblocks"

"github.com/erigontech/erigon-lib/common/hexutil"

"github.com/erigontech/erigon-lib/common"
Expand Down Expand Up @@ -49,10 +53,13 @@ func (api *APIImpl) GetTransactionByHash(ctx context.Context, txnHash common.Has
}

// https://infura.io/docs/ethereum/json-rpc/eth-getTransactionByHash
blockNum, _, ok, err := api.txnLookup(ctx, tx, txnHash)
blockNum, txNum, ok, err := api.txnLookup(ctx, tx, txnHash)
if err != nil {
return nil, err
}

txNumsReader := rawdbv3.TxNums.WithCustomReadTxNumFunc(freezeblocks.ReadTxNumFuncFromBlockReader(ctx, api._blockReader))

// Private API returns 0 if transaction is not found.
if blockNum == 0 && chainConfig.Bor != nil {
if api.useBridgeReader {
Expand All @@ -66,28 +73,36 @@ func (api *APIImpl) GetTransactionByHash(ctx context.Context, txnHash common.Has
}
}
if ok {
block, err := api.blockByNumberWithSenders(ctx, tx, blockNum)
txNumMin, err := txNumsReader.Min(tx, blockNum)
if err != nil {
return nil, err
}
if block == nil {
return nil, nil

if txNumMin+2 > txNum { //TODO: what a magic is this "2" and how to avoid it
return nil, fmt.Errorf("uint underflow txnums error txNum: %d, txNumMin: %d, blockNum: %d", txNum, txNumMin, blockNum)
}
blockHash := block.Hash()
var txnIndex uint64
var txn types2.Transaction
for i, transaction := range block.Transactions() {
if transaction.Hash() == txnHash {
txn = transaction
txnIndex = uint64(i)
break
}

var txnIndex uint64 = txNum - txNumMin - 2

txn, err := api._txnReader.TxnByIdxInBlock(ctx, tx, blockNum, int(txnIndex))
if err != nil {
return nil, err
}

header, err := api._blockReader.HeaderByNumber(ctx, tx, blockNum)
if err != nil {
return nil, err
}
if header == nil {
return nil, nil
}

blockHash := header.Hash()

// Add GasPrice for the DynamicFeeTransaction
var baseFee *big.Int
if chainConfig.IsLondon(blockNum) && blockHash != (common.Hash{}) {
baseFee = block.BaseFee()
baseFee = header.BaseFee
}

// if no transaction was found then we return nil
Expand All @@ -96,7 +111,11 @@ func (api *APIImpl) GetTransactionByHash(ctx context.Context, txnHash common.Has
return nil, nil
}
borTx := bortypes.NewBorTransaction()
return newRPCBorTransaction(borTx, txnHash, blockHash, blockNum, uint64(len(block.Transactions())), baseFee, chainConfig.ChainID), nil
_, txCount, err := api._blockReader.Body(ctx, tx, blockHash, blockNum)
if err != nil {
return nil, err
}
return newRPCBorTransaction(borTx, txnHash, blockHash, blockNum, uint64(txCount), baseFee, chainConfig.ChainID), nil
}

return NewRPCTransaction(txn, blockHash, blockNum, txnIndex, baseFee), nil
Expand Down
2 changes: 1 addition & 1 deletion turbo/jsonrpc/otterscan_search_v3.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (api *OtterscanAPIImpl) buildSearchResults(ctx context.Context, tx kv.Tempo
rpcTx := NewRPCTransaction(txn, block.Hash(), blockNum, uint64(txIndex), block.BaseFee())
txs = append(txs, rpcTx)

receipt, err := api.receiptsGenerator.GetReceipt(ctx, chainConfig, tx, block, txIndex, txNum+1)
receipt, err := api.receiptsGenerator.GetReceipt(ctx, chainConfig, tx, block.HeaderNoCopy(), txn, txIndex, txNum+1)
if err != nil {
return nil, nil, false, err
}
Expand Down
30 changes: 15 additions & 15 deletions turbo/jsonrpc/receipts/receipts_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,16 @@ func (g *Generator) GetCachedReceipt(ctx context.Context, hash common.Hash) (*ty
return g.receiptCache.Get(hash)
}

func (g *Generator) PrepareEnv(ctx context.Context, block *types.Block, cfg *chain.Config, tx kv.TemporalTx, txIndex int) (*ReceiptEnv, error) {
func (g *Generator) PrepareEnv(ctx context.Context, header *types.Header, cfg *chain.Config, tx kv.TemporalTx, txIndex int) (*ReceiptEnv, error) {
txNumsReader := rawdbv3.TxNums.WithCustomReadTxNumFunc(freezeblocks.ReadTxNumFuncFromBlockReader(ctx, g.blockReader))
ibs, _, _, _, _, err := transactions.ComputeBlockContext(ctx, g.engine, block.HeaderNoCopy(), cfg, g.blockReader, txNumsReader, tx, txIndex)
ibs, _, _, _, _, err := transactions.ComputeBlockContext(ctx, g.engine, header, cfg, g.blockReader, txNumsReader, tx, txIndex)
if err != nil {
return nil, fmt.Errorf("ReceiptsGen: PrepareEnv: bn=%d, %w", block.NumberU64(), err)
return nil, fmt.Errorf("ReceiptsGen: PrepareEnv: bn=%d, %w", header.Number.Uint64(), err)
}

usedGas := new(uint64)
usedBlobGas := new(uint64)
gp := new(core.GasPool).AddGas(block.GasLimit()).AddBlobGas(cfg.GetMaxBlobGasPerBlock())
gp := new(core.GasPool).AddGas(header.GasLimit).AddBlobGas(cfg.GetMaxBlobGasPerBlock())

noopWriter := state.NewNoopWriter()

Expand All @@ -104,7 +104,6 @@ func (g *Generator) PrepareEnv(ctx context.Context, block *types.Block, cfg *cha
}
return h
}
header := block.HeaderNoCopy()
return &ReceiptEnv{
ibs: ibs,
usedGas: usedGas,
Expand All @@ -124,16 +123,17 @@ func (g *Generator) addToCacheReceipt(hash common.Hash, receipt *types.Receipt)
g.receiptCache.Add(hash, receipt.Copy()) // .Copy() helps pprof to attribute memory to cache - instead of evm (where it was allocated).
}

func (g *Generator) GetReceipt(ctx context.Context, cfg *chain.Config, tx kv.TemporalTx, block *types.Block, index int, txNum uint64) (*types.Receipt, error) {
if receipt, ok := g.receiptCache.Get(block.Transactions()[index].Hash()); ok {
func (g *Generator) GetReceipt(ctx context.Context, cfg *chain.Config, tx kv.TemporalTx, header *types.Header, txn types.Transaction, index int, txNum uint64) (*types.Receipt, error) {
if receipts, ok := g.receiptsCache.Get(header.Hash()); ok && len(receipts) > index {
return receipts[index], nil
}
if receipt, ok := g.receiptCache.Get(txn.Hash()); ok {
return receipt, nil
}

if receipts, ok := g.receiptsCache.Get(block.Hash()); ok && len(receipts) > index {
return receipts[index], nil
}
var receipt *types.Receipt
genEnv, err := g.PrepareEnv(ctx, block, cfg, tx, index)

genEnv, err := g.PrepareEnv(ctx, header, cfg, tx, index)
if err != nil {
return nil, err
}
Expand All @@ -143,12 +143,12 @@ func (g *Generator) GetReceipt(ctx context.Context, cfg *chain.Config, tx kv.Tem
return nil, err
}

receipt, _, err = core.ApplyTransaction(cfg, core.GetHashFn(genEnv.header, genEnv.getHeader), g.engine, nil, genEnv.gp, genEnv.ibs, genEnv.noopWriter, genEnv.header, block.Transactions()[index], genEnv.usedGas, genEnv.usedBlobGas, vm.Config{})
receipt, _, err = core.ApplyTransaction(cfg, core.GetHashFn(genEnv.header, genEnv.getHeader), g.engine, nil, genEnv.gp, genEnv.ibs, genEnv.noopWriter, genEnv.header, txn, genEnv.usedGas, genEnv.usedBlobGas, vm.Config{})
if err != nil {
return nil, fmt.Errorf("ReceiptGen.GetReceipt: bn=%d, txnIdx=%d, %w", block.NumberU64(), index, err)
return nil, fmt.Errorf("ReceiptGen.GetReceipt: bn=%d, txnIdx=%d, %w", header.Number.Uint64(), index, err)
}

receipt.BlockHash = block.Hash()
receipt.BlockHash = header.Hash()

receipt.CumulativeGasUsed = cumGasUsed
receipt.TransactionIndex = uint(index)
Expand All @@ -169,7 +169,7 @@ func (g *Generator) GetReceipts(ctx context.Context, cfg *chain.Config, tx kv.Te

receipts := make(types.Receipts, len(block.Transactions()))

genEnv, err := g.PrepareEnv(ctx, block, cfg, tx, 0)
genEnv, err := g.PrepareEnv(ctx, block.HeaderNoCopy(), cfg, tx, 0)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit ec2b7b2

Please sign in to comment.