Skip to content

Commit

Permalink
e3: abstract 1 tx exec, to avoid variables bloating (#6563)
Browse files Browse the repository at this point in the history
  • Loading branch information
AskAlexSharov committed Jan 12, 2023
1 parent 41e9356 commit 7e9522d
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 53 deletions.
132 changes: 81 additions & 51 deletions cmd/rpcdaemon/commands/eth_receipts.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import (
common2 "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/erigon-lib/kv/bitmapdb"
"github.com/ledgerwatch/erigon/consensus"
"github.com/ledgerwatch/erigon/core/state/temporal"
"github.com/ledgerwatch/erigon/core/vm/evmtypes"
"github.com/ledgerwatch/erigon/turbo/services"
"github.com/ledgerwatch/log/v3"

"github.com/ledgerwatch/erigon/common"
Expand All @@ -23,7 +26,6 @@ import (
"github.com/ledgerwatch/erigon/core/state"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/vm"
"github.com/ledgerwatch/erigon/core/vm/evmtypes"
"github.com/ledgerwatch/erigon/eth/filters"
"github.com/ledgerwatch/erigon/ethdb/cbor"
"github.com/ledgerwatch/erigon/params"
Expand Down Expand Up @@ -330,10 +332,10 @@ func applyFiltersV3(out *roaring64.Bitmap, tx kv.TemporalTx, begin, end uint64,
}

func (api *APIImpl) getLogsV3(ctx context.Context, tx kv.TemporalTx, begin, end uint64, crit filters.FilterCriteria) ([]*types.Log, error) {
logs := []*types.Log{}

txNumbers := bitmapdb.NewBitmap64()
defer bitmapdb.ReturnToPool64(txNumbers)

logs := []*types.Log{}
if err := applyFiltersV3(txNumbers, tx, begin, end, crit); err != nil {
return logs, err
}
Expand All @@ -346,29 +348,18 @@ func (api *APIImpl) getLogsV3(ctx context.Context, tx kv.TemporalTx, begin, end
addrMap[v] = struct{}{}
}

var lastBlockNum uint64
var blockHash common.Hash
var header *types.Header
var signer *types.Signer
var rules *params.Rules
var skipAnalysis bool

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

evm := vm.NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chainConfig, vm.Config{})
vmConfig := vm.Config{SkipAnalysis: skipAnalysis}
var blockCtx evmtypes.BlockContext
exec := newIntraBlockExec(tx, chainConfig, api.engine())

var lastBlockNum uint64
var blockHash common.Hash
var header *types.Header
var minTxNumInBlock, maxTxNumInBlock uint64 // end is an inclusive bound
var blockNum uint64
var ok bool
stateReader := state.NewHistoryReaderV3()
stateReader.SetTx(tx)
ibs := state.New(stateReader)

iter := txNumbers.Iterator()
for iter.HasNext() {
Expand All @@ -395,20 +386,13 @@ func (api *APIImpl) getLogsV3(ctx context.Context, tx kv.TemporalTx, begin, end
if header, err = api._blockReader.HeaderByNumber(ctx, tx, blockNum); err != nil {
return nil, err
}
lastBlockNum = blockNum
blockHash = header.Hash()
signer = types.MakeSigner(chainConfig, blockNum)
if chainConfig == nil {
log.Warn("chainConfig is nil")
continue
}
if header == nil {
log.Warn("header is nil", "blockNum", blockNum)
continue
}
rules = chainConfig.Rules(blockNum, header.Time)
vmConfig.SkipAnalysis = core.SkipAnalysis(chainConfig, blockNum)

lastBlockNum = blockNum
blockHash = header.Hash()
exec.changeBlock(header)
minTxNumInBlock, err = rawdb.TxNums.Min(tx, blockNum)
if err != nil {
return nil, err
Expand All @@ -417,7 +401,6 @@ func (api *APIImpl) getLogsV3(ctx context.Context, tx kv.TemporalTx, begin, end
if err != nil {
return nil, err
}
blockCtx = transactions.NewEVMBlockContext(engine, header, true /* requireCanonical */, tx, api._blockReader)
}

txIndex := int(txNum) - int(minTxNumInBlock) - 1
Expand All @@ -429,37 +412,22 @@ func (api *APIImpl) getLogsV3(ctx context.Context, tx kv.TemporalTx, begin, end
if txn == nil {
continue
}
stateReader.SetTxNum(txNum)
txHash := txn.Hash()
msg, err := txn.AsMessage(*signer, header.BaseFee, rules)
rawLogs, err := exec.execTx(txNum, txIndex, txn)
if err != nil {
return nil, err
}

ibs.Reset()
ibs.Prepare(txHash, blockHash, txIndex)

evm.ResetBetweenBlocks(blockCtx, core.NewEVMTxContext(msg), ibs, vmConfig, rules)

gp := new(core.GasPool).AddGas(msg.Gas())
_, err = core.ApplyMessage(evm, msg, gp, true /* refunds */, false /* gasBailout */)
if err != nil {
return nil, fmt.Errorf("%w: blockNum=%d, txNum=%d, %s", err, blockNum, txNum, ibs.Error())
}

rawLogs := ibs.GetLogs(txHash)

//TODO: logIndex within the block! no way to calc it now
logIndex := uint(0)
for _, log := range rawLogs {
log.Index = logIndex
logIndex++
}
//logIndex := uint(0)
//for _, log := range rawLogs {
// log.Index = logIndex
// logIndex++
//}
filtered := types.Logs(rawLogs).Filter(addrMap, crit.Topics)
for _, log := range filtered {
log.BlockNumber = blockNum
log.BlockHash = blockHash
log.TxHash = txHash
log.TxHash = txn.Hash()
}
logs = append(logs, filtered...)
}
Expand All @@ -469,6 +437,67 @@ func (api *APIImpl) getLogsV3(ctx context.Context, tx kv.TemporalTx, begin, end
return logs, nil
}

type intraBlockExec struct {
ibs *state.IntraBlockState
stateReader *state.HistoryReaderV3
engine consensus.EngineReader
tx kv.TemporalTx
br services.FullBlockReader
chainConfig *params.ChainConfig
evm *vm.EVM

// calculated by .changeBlock()
blockHash common.Hash
blockNum uint64
header *types.Header
blockCtx *evmtypes.BlockContext
rules *params.Rules
signer *types.Signer
vmConfig *vm.Config
}

func newIntraBlockExec(tx kv.TemporalTx, chainConfig *params.ChainConfig, engine consensus.EngineReader) *intraBlockExec {
stateReader := state.NewHistoryReaderV3()
stateReader.SetTx(tx)
return &intraBlockExec{
engine: engine,
chainConfig: chainConfig,
stateReader: stateReader,
evm: vm.NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chainConfig, vm.Config{}),
vmConfig: &vm.Config{},
ibs: state.New(stateReader),
}
}

func (e *intraBlockExec) changeBlock(header *types.Header) {
e.blockNum = header.Number.Uint64()
blockCtx := transactions.NewEVMBlockContext(e.engine, header, true /* requireCanonical */, e.tx, e.br)
e.blockCtx = &blockCtx
e.blockHash = header.Hash()
e.header = header
e.rules = e.chainConfig.Rules(e.blockNum, header.Time)
e.signer = types.MakeSigner(e.chainConfig, e.blockNum)
e.vmConfig.SkipAnalysis = core.SkipAnalysis(e.chainConfig, e.blockNum)
}

func (e *intraBlockExec) execTx(txNum uint64, txIndex int, txn types.Transaction) ([]*types.Log, error) {
e.stateReader.SetTxNum(txNum)
txHash := txn.Hash()
e.ibs.Reset()
e.ibs.Prepare(txHash, e.blockHash, txIndex)
gp := new(core.GasPool).AddGas(txn.GetGas())
msg, err := txn.AsMessage(*e.signer, e.header.BaseFee, e.rules)
if err != nil {
return nil, err
}
e.evm.ResetBetweenBlocks(*e.blockCtx, core.NewEVMTxContext(msg), e.ibs, *e.vmConfig, e.rules)
_, err = core.ApplyMessage(e.evm, msg, gp, true /* refunds */, false /* gasBailout */)
if err != nil {
return nil, fmt.Errorf("%w: blockNum=%d, txNum=%d, %s", err, e.blockNum, txNum, e.ibs.Error())
}
return e.ibs.GetLogs(txHash), nil
}

// The Topic list restricts matches to particular event topics. Each event has a list
// of topics. Topics matches a prefix of that list. An empty element slice matches any
// topic. Non-empty elements represent an alternative that matches any of the
Expand Down Expand Up @@ -509,6 +538,7 @@ func getTopicsBitmapV3(tx kv.TemporalTx, topics [][]common.Hash, from, to uint64
}
return result, nil
}

func getAddrsBitmapV3(tx kv.TemporalTx, addrs []common.Address, from, to uint64) (*roaring64.Bitmap, error) {
if len(addrs) == 0 {
return nil, nil
Expand Down
4 changes: 2 additions & 2 deletions turbo/transactions/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,10 @@ func DoCall(
}

func NewEVMBlockContext(engine consensus.EngineReader, header *types.Header, requireCanonical bool, tx kv.Tx, headerReader services.HeaderReader) evmtypes.BlockContext {
return core.NewEVMBlockContext(header, getHashGetter(requireCanonical, tx, headerReader), engine, nil /* author */)
return core.NewEVMBlockContext(header, MakeHeaderGetter(requireCanonical, tx, headerReader), engine, nil /* author */)
}

func getHashGetter(requireCanonical bool, tx kv.Tx, headerReader services.HeaderReader) func(uint64) common.Hash {
func MakeHeaderGetter(requireCanonical bool, tx kv.Tx, headerReader services.HeaderReader) func(uint64) common.Hash {
return func(n uint64) common.Hash {
h, err := headerReader.HeaderByNumber(context.Background(), tx, n)
if err != nil {
Expand Down

0 comments on commit 7e9522d

Please sign in to comment.