Skip to content

Commit

Permalink
Calculate FeeCurrencyContext once per Block (#267)
Browse files Browse the repository at this point in the history
* Pass feeCurrencyContext to blockContext

* Remove commented line

* Change to reduce the diff with upstream
  • Loading branch information
gastonponti committed Nov 20, 2024
1 parent c07df60 commit 3205d38
Show file tree
Hide file tree
Showing 15 changed files with 94 additions and 66 deletions.
6 changes: 3 additions & 3 deletions core/celo_evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (
"github.com/ethereum/go-ethereum/params"
)

func setCeloFieldsInBlockContext(blockContext *vm.BlockContext, header *types.Header, config *params.ChainConfig, statedb vm.StateDB) {
func GetFeeCurrencyContext(header *types.Header, config *params.ChainConfig, statedb vm.StateDB) *common.FeeCurrencyContext {
if !config.IsCel2(header.Time) {
return
return &common.FeeCurrencyContext{}
}

caller := &contracts.CeloBackend{ChainConfig: config, State: statedb}
Expand All @@ -20,7 +20,7 @@ func setCeloFieldsInBlockContext(blockContext *vm.BlockContext, header *types.He
if err != nil {
log.Error("Error fetching exchange rates!", "err", err)
}
blockContext.FeeCurrencyContext = feeCurrencyContext
return &feeCurrencyContext
}

func GetExchangeRates(header *types.Header, config *params.ChainConfig, statedb vm.StateDB) common.ExchangeRates {
Expand Down
22 changes: 15 additions & 7 deletions core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@ import (
// BlockGen creates blocks for testing.
// See GenerateChain for a detailed explanation.
type BlockGen struct {
i int
cm *chainMaker
parent *types.Block
header *types.Header
statedb *state.StateDB
i int
cm *chainMaker
parent *types.Block
header *types.Header
statedb *state.StateDB
feeCurrencyContext *common.FeeCurrencyContext

gasPool *GasPool
txs []*types.Transaction
Expand All @@ -54,6 +55,10 @@ type BlockGen struct {
engine consensus.Engine
}

func (b *BlockGen) updateFeeCurrencyContext() {
b.feeCurrencyContext = GetFeeCurrencyContext(b.header, b.cm.config, b.statedb)
}

// SetCoinbase sets the coinbase of the generated block.
// It can be called at most once.
func (b *BlockGen) SetCoinbase(addr common.Address) {
Expand Down Expand Up @@ -99,7 +104,7 @@ func (b *BlockGen) Difficulty() *big.Int {
func (b *BlockGen) SetParentBeaconRoot(root common.Hash) {
b.header.ParentBeaconRoot = &root
var (
blockContext = NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase, b.cm.config, b.statedb)
blockContext = NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase, b.cm.config, b.statedb, b.feeCurrencyContext)
vmenv = vm.NewEVM(blockContext, vm.TxContext{}, b.statedb, b.cm.config, vm.Config{})
)
ProcessBeaconBlockRoot(root, vmenv, b.statedb)
Expand All @@ -117,7 +122,7 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti
b.SetCoinbase(common.Address{})
}
b.statedb.SetTxContext(tx.Hash(), len(b.txs))
receipt, err := ApplyTransaction(b.cm.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig)
receipt, err := ApplyTransaction(b.cm.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig, b.feeCurrencyContext)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -329,6 +334,8 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
b.header.Difficulty = big.NewInt(0)
}
}
b.updateFeeCurrencyContext()

// Mutate the state and block according to any hard-fork specs
if daoBlock := config.DAOForkBlock; daoBlock != nil {
limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
Expand Down Expand Up @@ -430,6 +437,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
genblock := func(i int, parent *types.Block, triedb *triedb.Database, statedb *state.StateDB) (*types.Block, types.Receipts) {
b := &BlockGen{i: i, cm: cm, parent: parent, statedb: statedb, engine: engine}
b.header = cm.makeHeader(parent, statedb, b.engine)
b.updateFeeCurrencyContext()

// TODO uncomment when proof generation is merged
// Save pre state for proof generation
Expand Down
6 changes: 4 additions & 2 deletions core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type ChainContext interface {
}

// NewEVMBlockContext creates a new context for use in the EVM.
func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common.Address, config *params.ChainConfig, statedb vm.StateDB) vm.BlockContext {
func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common.Address, config *params.ChainConfig, statedb vm.StateDB, feeCurrencyContext *common.FeeCurrencyContext) vm.BlockContext {
var (
beneficiary common.Address
baseFee *big.Int
Expand Down Expand Up @@ -78,7 +78,9 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
L1CostFunc: types.NewL1CostFunc(config, statedb),
}

setCeloFieldsInBlockContext(&blockContext, header, config, statedb)
if config.IsCel2(header.Time) {
blockContext.FeeCurrencyContext = *feeCurrencyContext
}

return blockContext
}
Expand Down
11 changes: 6 additions & 5 deletions core/state_prefetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,12 @@ func newStatePrefetcher(config *params.ChainConfig, chain *HeaderChain) *statePr
// only goal is to pre-cache transaction signatures and state trie nodes.
func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *atomic.Bool) {
var (
header = block.Header()
gaspool = new(GasPool).AddGas(block.GasLimit())
blockContext = NewEVMBlockContext(header, p.chain, nil, p.config, statedb)
evm = vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
signer = types.MakeSigner(p.config, header.Number, header.Time)
header = block.Header()
gaspool = new(GasPool).AddGas(block.GasLimit())
feeCurrencyContext = GetFeeCurrencyContext(header, p.config, statedb)
blockContext = NewEVMBlockContext(header, p.chain, nil, p.config, statedb, feeCurrencyContext)
evm = vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
signer = types.MakeSigner(p.config, header.Number, header.Time)
)
// Iterate over and process the individual transactions
byzantium := p.config.IsByzantium(block.Number())
Expand Down
11 changes: 6 additions & 5 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
context vm.BlockContext
signer = types.MakeSigner(p.config, header.Number, header.Time)
)
context = NewEVMBlockContext(header, p.chain, nil, p.config, statedb)
feeCurrencyContext := GetFeeCurrencyContext(header, p.config, statedb)
context = NewEVMBlockContext(header, p.chain, nil, p.config, statedb, feeCurrencyContext)
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg)
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
Expand Down Expand Up @@ -197,13 +198,13 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
// and uses the input parameters for its environment. It returns the receipt
// for the transaction, gas used and an error if the transaction failed,
// indicating the block was invalid.
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
// Create a new context to be used in the EVM environment
blockContext := NewEVMBlockContext(header, bc, author, config, statedb)
msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number, header.Time), header.BaseFee, blockContext.FeeCurrencyContext.ExchangeRates)
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config, feeCurrencyContext *common.FeeCurrencyContext) (*types.Receipt, error) {
msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number, header.Time), header.BaseFee, feeCurrencyContext.ExchangeRates)
if err != nil {
return nil, err
}
// Create a new context to be used in the EVM environment
blockContext := NewEVMBlockContext(header, bc, author, config, statedb, feeCurrencyContext)
txContext := NewEVMTxContext(msg)
vmenv := vm.NewEVM(blockContext, txContext, statedb, config, cfg)
return ApplyTransactionWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
Expand Down
3 changes: 2 additions & 1 deletion eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *st
if blockCtx != nil {
context = *blockCtx
} else {
context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil, b.eth.blockchain.Config(), state)
feeCurrencyContext := core.GetFeeCurrencyContext(header, b.eth.blockchain.Config(), state)
context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil, b.eth.blockchain.Config(), state, feeCurrencyContext)
}
return vm.NewEVM(context, txContext, state, b.ChainConfig(), *vmConfig)
}
Expand Down
5 changes: 3 additions & 2 deletions eth/gasestimator/gasestimator.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,9 @@ func execute(ctx context.Context, call *core.Message, opts *Options, gasLimit ui
func run(ctx context.Context, call *core.Message, opts *Options) (*core.ExecutionResult, error) {
// Assemble the call and the call context
var (
msgContext = core.NewEVMTxContext(call)
evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil, opts.Config, opts.State)
feeCurrencyContext = core.GetFeeCurrencyContext(opts.Header, opts.Config, opts.State)
msgContext = core.NewEVMTxContext(call)
evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil, opts.Config, opts.State, feeCurrencyContext)

dirtyState = opts.State.Copy()
evm = vm.NewEVM(evmContext, msgContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true})
Expand Down
5 changes: 3 additions & 2 deletions eth/state_accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,10 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
if err != nil {
return nil, vm.BlockContext{}, nil, nil, err
}
feeCurrencyContext := core.GetFeeCurrencyContext(block.Header(), eth.blockchain.Config(), statedb)
// Insert parent beacon block root in the state as per EIP-4788.
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil, eth.blockchain.Config(), statedb)
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil, eth.blockchain.Config(), statedb, feeCurrencyContext)
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{})
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
}
Expand All @@ -245,7 +246,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
// Recompute transactions up to the target index.
signer := types.MakeSigner(eth.blockchain.Config(), block.Number(), block.Time())
for idx, tx := range block.Transactions() {
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil, eth.blockchain.Config(), statedb)
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil, eth.blockchain.Config(), statedb, feeCurrencyContext)
// Assemble the transaction call message and return if the requested offset
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee(), context.FeeCurrencyContext.ExchangeRates)
txContext := core.NewEVMTxContext(msg)
Expand Down
47 changes: 27 additions & 20 deletions eth/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,12 +266,13 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
// Fetch and execute the block trace taskCh
for task := range taskCh {
var (
signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number(), task.block.Time())
blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), task.statedb)
feeCurrencyContext = core.GetFeeCurrencyContext(end.Header(), api.backend.ChainConfig(), task.statedb)
signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number(), task.block.Time())
blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), task.statedb, feeCurrencyContext)
)
// Trace all the transactions contained within
for i, tx := range task.block.Transactions() {
msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee(), blockCtx.FeeCurrencyContext.ExchangeRates)
msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee(), feeCurrencyContext.ExchangeRates)
txctx := &Context{
BlockHash: task.block.Hash(),
BlockNumber: task.block.Number(),
Expand Down Expand Up @@ -379,7 +380,8 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
// Insert block's parent beacon block root in the state
// as per EIP-4788.
if beaconRoot := next.BeaconRoot(); beaconRoot != nil {
context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), statedb)
feeCurrencyContext := core.GetFeeCurrencyContext(end.Header(), api.backend.ChainConfig(), statedb)
context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), statedb, feeCurrencyContext)
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
}
Expand Down Expand Up @@ -557,7 +559,8 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
roots []common.Hash
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
chainConfig = api.backend.ChainConfig()
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, chainConfig, statedb)
feeCurrencyContext = core.GetFeeCurrencyContext(block.Header(), chainConfig, statedb)
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, chainConfig, statedb, feeCurrencyContext)
deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
)
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
Expand Down Expand Up @@ -633,19 +636,20 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
}
// Native tracers have low overhead
var (
txs = block.Transactions()
blockHash = block.Hash()
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), statedb)
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
results = make([]*txTraceResult, len(txs))
txs = block.Transactions()
blockHash = block.Hash()
feeCurrencyContext = core.GetFeeCurrencyContext(block.Header(), api.backend.ChainConfig(), statedb)
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), statedb, feeCurrencyContext)
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
results = make([]*txTraceResult, len(txs))
)
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
}
for i, tx := range txs {
// Generate the next state snapshot fast without tracing
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee(), blockCtx.FeeCurrencyContext.ExchangeRates)
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee(), feeCurrencyContext.ExchangeRates)
txctx := &Context{
BlockHash: blockHash,
BlockNumber: block.Number(),
Expand Down Expand Up @@ -678,6 +682,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
threads = len(txs)
}
exchangeRates := core.GetExchangeRates(block.Header(), api.backend.ChainConfig(), statedb)
feeCurrencyContext := core.GetFeeCurrencyContext(block.Header(), api.backend.ChainConfig(), statedb)
jobs := make(chan *txTraceTask, threads)
for th := 0; th < threads; th++ {
pend.Add(1)
Expand All @@ -696,7 +701,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
// as the GetHash function of BlockContext is not safe for
// concurrent use.
// See: https://github.com/ethereum/go-ethereum/issues/29114
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), task.statedb)
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), task.statedb, feeCurrencyContext)
res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config)
if err != nil {
results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()}
Expand All @@ -709,7 +714,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat

// Feed the transactions into the tracers and return
var failed error
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), statedb)
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), statedb, feeCurrencyContext)
txloop:
for i, tx := range txs {
// Send the trace task over for execution
Expand Down Expand Up @@ -783,11 +788,12 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block

// Execute transaction, either tracing all or just the requested one
var (
dumps []string
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
chainConfig = api.backend.ChainConfig()
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, chainConfig, statedb)
canon = true
dumps []string
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
chainConfig = api.backend.ChainConfig()
feeCurrencyContext = core.GetFeeCurrencyContext(block.Header(), chainConfig, statedb)
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, chainConfig, statedb, feeCurrencyContext)
canon = true
)
// Check if there are any overrides: the caller may wish to enable a future
// fork when executing this block. Note, such overrides are only applicable to the
Expand Down Expand Up @@ -989,7 +995,8 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
}
defer release()

vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), statedb)
feeCurrencyContext := core.GetFeeCurrencyContext(block.Header(), api.backend.ChainConfig(), statedb)
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), statedb, feeCurrencyContext)
// Apply the customization rules if required.
if config != nil {
if err := config.StateOverrides.Apply(statedb); err != nil {
Expand All @@ -1002,7 +1009,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
return nil, err
}
var (
msg = args.ToMessage(vmctx.BaseFee, vmctx.FeeCurrencyContext.ExchangeRates)
msg = args.ToMessage(vmctx.BaseFee, feeCurrencyContext.ExchangeRates)
tx = args.ToTransaction()
traceConfig *TraceConfig
)
Expand Down
3 changes: 2 additions & 1 deletion eth/tracers/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,11 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
if txIndex == 0 && len(block.Transactions()) == 0 {
return nil, vm.BlockContext{}, statedb, release, nil
}
feeCurrencyContext := core.GetFeeCurrencyContext(block.Header(), b.chainConfig, statedb)
// Recompute transactions up to the target index.
signer := types.MakeSigner(b.chainConfig, block.Number(), block.Time())
context := core.NewEVMBlockContext(block.Header(), b.chain, nil, b.chainConfig, statedb, feeCurrencyContext)
for idx, tx := range block.Transactions() {
context := core.NewEVMBlockContext(block.Header(), b.chain, nil, b.chainConfig, statedb)
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee(), context.FeeCurrencyContext.ExchangeRates)
txContext := core.NewEVMTxContext(msg)
if idx == txIndex {
Expand Down
3 changes: 2 additions & 1 deletion internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1199,8 +1199,9 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S
// this makes sure resources are cleaned up.
defer cancel()

feeCurrencyContext := core.GetFeeCurrencyContext(header, b.ChainConfig(), state)
// Get a new instance of the EVM.
blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil, b.ChainConfig(), state)
blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil, b.ChainConfig(), state, feeCurrencyContext)
if blockOverrides != nil {
blockOverrides.Apply(&blockCtx)
}
Expand Down
Loading

0 comments on commit 3205d38

Please sign in to comment.