mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 19:00:46 +00:00
core: implement eip-7778: block gas accounting without refunds
This commit is contained in:
parent
cee751a1ed
commit
2e5c9c2e0f
8 changed files with 63 additions and 39 deletions
|
|
@ -260,7 +260,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
snapshot = statedb.Snapshot()
|
||||
prevGas = gaspool.Gas()
|
||||
)
|
||||
receipt, err := core.ApplyTransactionWithEVM(msg, gaspool, statedb, vmContext.BlockNumber, blockHash, pre.Env.Timestamp, tx, &gasUsed, evm)
|
||||
receipt, _, err := core.ApplyTransactionWithEVM(msg, gaspool, statedb, vmContext.BlockNumber, blockHash, pre.Env.Timestamp, tx, gasUsed, evm)
|
||||
if err != nil {
|
||||
statedb.RevertToSnapshot(snapshot)
|
||||
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
|
||||
|
|
@ -271,6 +271,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
if receipt.Logs == nil {
|
||||
receipt.Logs = []*types.Log{}
|
||||
}
|
||||
gasUsed += receipt.GasUsed
|
||||
includedTxs = append(includedTxs, tx)
|
||||
if hashError != nil {
|
||||
return nil, nil, nil, NewError(ErrorMissingBlockhash, hashError)
|
||||
|
|
|
|||
|
|
@ -38,11 +38,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
|
||||
cumulativeGas uint64
|
||||
cm *chainMaker
|
||||
parent *types.Block
|
||||
header *types.Header
|
||||
statedb *state.StateDB
|
||||
|
||||
gasPool *GasPool
|
||||
txs []*types.Transaction
|
||||
|
|
@ -115,12 +116,15 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti
|
|||
var (
|
||||
blockContext = NewEVMBlockContext(b.header, bc, &b.header.Coinbase)
|
||||
evm = vm.NewEVM(blockContext, b.statedb, b.cm.config, vmConfig)
|
||||
receipt *types.Receipt
|
||||
err error
|
||||
)
|
||||
b.statedb.SetTxContext(tx.Hash(), len(b.txs))
|
||||
receipt, err := ApplyTransaction(evm, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed)
|
||||
receipt, b.cumulativeGas, err = ApplyTransaction(evm, b.gasPool, b.statedb, b.header, tx, b.cumulativeGas)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b.header.GasUsed += receipt.GasUsed
|
||||
// Merge the tx-local access event into the "block-local" one, in order to collect
|
||||
// all values, so that the witness can be built.
|
||||
if b.statedb.Database().TrieDB().IsVerkle() {
|
||||
|
|
|
|||
|
|
@ -63,12 +63,17 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated
|
|||
var (
|
||||
config = p.chainConfig()
|
||||
receipts types.Receipts
|
||||
usedGas = new(uint64)
|
||||
header = block.Header()
|
||||
blockHash = block.Hash()
|
||||
blockNumber = block.Number()
|
||||
allLogs []*types.Log
|
||||
gp = new(GasPool).AddGas(block.GasLimit())
|
||||
// We are maintaining two counters here:
|
||||
// one counts all the cumulativeGas which includes refunds
|
||||
// while the other counts only the usedGas which excludes refunds after Amsterdam
|
||||
// We need the cumulativeGas for receipts and the usedGas for the block gas limit
|
||||
cumulativeGas = uint64(0)
|
||||
usedGas = uint64(0)
|
||||
)
|
||||
|
||||
var tracingStateDB = vm.StateDB(statedb)
|
||||
|
|
@ -107,13 +112,17 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated
|
|||
telemetry.StringAttribute("tx.hash", tx.Hash().Hex()),
|
||||
telemetry.Int64Attribute("tx.index", int64(i)),
|
||||
)
|
||||
receipt, err := ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, context.Time, tx, usedGas, evm)
|
||||
spanEnd(&err)
|
||||
|
||||
var receipt *types.Receipt
|
||||
receipt, cumulativeGas, err = ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, context.Time, tx, cumulativeGas, evm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||
}
|
||||
usedGas += receipt.GasUsed
|
||||
receipts = append(receipts, receipt)
|
||||
allLogs = append(allLogs, receipt.Logs...)
|
||||
|
||||
spanEnd(&err)
|
||||
}
|
||||
requests, err := postExecution(ctx, config, block, allLogs, evm)
|
||||
if err != nil {
|
||||
|
|
@ -127,7 +136,7 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated
|
|||
Receipts: receipts,
|
||||
Requests: requests,
|
||||
Logs: allLogs,
|
||||
GasUsed: *usedGas,
|
||||
GasUsed: usedGas,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -159,7 +168,7 @@ func postExecution(ctx context.Context, config *params.ChainConfig, block *types
|
|||
// ApplyTransactionWithEVM attempts to apply a transaction to the given state database
|
||||
// and uses the input parameters for its environment similar to ApplyTransaction. However,
|
||||
// this method takes an already created EVM instance as input.
|
||||
func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) {
|
||||
func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, cumulativeGas uint64, evm *vm.EVM) (receipt *types.Receipt, cGas uint64, err error) {
|
||||
if hooks := evm.Config.Tracer; hooks != nil {
|
||||
if hooks.OnTxStart != nil {
|
||||
hooks.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||
|
|
@ -171,7 +180,7 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB,
|
|||
// Apply the transaction to the current state (included in the env).
|
||||
result, err := ApplyMessage(evm, msg, gp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, cumulativeGas, err
|
||||
}
|
||||
// Update the state with pending changes.
|
||||
var root []byte
|
||||
|
|
@ -180,28 +189,32 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB,
|
|||
} else {
|
||||
root = statedb.IntermediateRoot(evm.ChainConfig().IsEIP158(blockNumber)).Bytes()
|
||||
}
|
||||
*usedGas += result.UsedGas
|
||||
cGas = cumulativeGas + result.UsedGas
|
||||
|
||||
// Merge the tx-local access event into the "block-local" one, in order to collect
|
||||
// all values, so that the witness can be built.
|
||||
if statedb.Database().TrieDB().IsVerkle() {
|
||||
statedb.AccessEvents().Merge(evm.AccessEvents)
|
||||
}
|
||||
return MakeReceipt(evm, result, statedb, blockNumber, blockHash, blockTime, tx, *usedGas, root), nil
|
||||
return MakeReceipt(evm, result, statedb, blockNumber, blockHash, blockTime, tx, cGas, root), cGas, nil
|
||||
}
|
||||
|
||||
// MakeReceipt generates the receipt object for a transaction given its execution result.
|
||||
func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, usedGas uint64, root []byte) *types.Receipt {
|
||||
func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, cumulativeGas uint64, root []byte) *types.Receipt {
|
||||
// Create a new receipt for the transaction, storing the intermediate root and gas used
|
||||
// by the tx.
|
||||
receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: usedGas}
|
||||
receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: cumulativeGas}
|
||||
if result.Failed() {
|
||||
receipt.Status = types.ReceiptStatusFailed
|
||||
} else {
|
||||
receipt.Status = types.ReceiptStatusSuccessful
|
||||
}
|
||||
receipt.TxHash = tx.Hash()
|
||||
receipt.GasUsed = result.UsedGas
|
||||
if evm.ChainConfig().IsAmsterdam(blockNumber, blockTime) {
|
||||
receipt.GasUsed = result.MaxUsedGas
|
||||
} else {
|
||||
receipt.GasUsed = result.UsedGas
|
||||
}
|
||||
|
||||
if tx.Type() == types.BlobTxType {
|
||||
receipt.BlobGasUsed = uint64(len(tx.BlobHashes()) * params.BlobTxBlobGasPerBlob)
|
||||
|
|
@ -224,15 +237,15 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b
|
|||
|
||||
// ApplyTransaction attempts to apply a transaction to the given state database
|
||||
// and uses the input parameters for its environment. It returns the receipt
|
||||
// for the transaction, gas used and an error if the transaction failed,
|
||||
// for the transaction and an error if the transaction failed,
|
||||
// indicating the block was invalid.
|
||||
func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, error) {
|
||||
func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, cumulativeGas uint64) (*types.Receipt, uint64, error) {
|
||||
msg, err := TransactionToMessage(tx, types.MakeSigner(evm.ChainConfig(), header.Number, header.Time), header.BaseFee)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, cumulativeGas, err
|
||||
}
|
||||
// Create a new context to be used in the EVM environment
|
||||
return ApplyTransactionWithEVM(msg, gp, statedb, header.Number, header.Hash(), header.Time, tx, usedGas, evm)
|
||||
return ApplyTransactionWithEVM(msg, gp, statedb, header.Number, header.Hash(), header.Time, tx, cumulativeGas, evm)
|
||||
}
|
||||
|
||||
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
|
||||
|
|
|
|||
|
|
@ -542,7 +542,14 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
peakGasUsed = floorDataGas
|
||||
}
|
||||
}
|
||||
// Return gas to the user
|
||||
st.returnGas()
|
||||
// Return gas to the gas pool
|
||||
if rules.IsAmsterdam {
|
||||
st.gp.AddGas(st.initialGas - peakGasUsed)
|
||||
} else {
|
||||
st.gp.AddGas(st.gasRemaining)
|
||||
}
|
||||
|
||||
effectiveTip := msg.GasPrice
|
||||
if rules.IsLondon {
|
||||
|
|
@ -660,10 +667,6 @@ func (st *stateTransition) returnGas() {
|
|||
if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && st.gasRemaining > 0 {
|
||||
st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, tracing.GasChangeTxLeftOverReturned)
|
||||
}
|
||||
|
||||
// Also return remaining gas to the block gas counter so it is
|
||||
// available for the next transaction.
|
||||
st.gp.AddGas(st.gasRemaining)
|
||||
}
|
||||
|
||||
// gasUsed returns the amount of gas used up by the state transition.
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ const (
|
|||
// this generates an increase in gas. There is at most one of such gas change per transaction.
|
||||
GasChangeTxRefunds GasChangeReason = 3
|
||||
// GasChangeTxLeftOverReturned is the amount of gas left over at the end of transaction's execution that will be returned
|
||||
// to the chain. This change will always be a negative change as we "drain" left over gas towards 0. If there was no gas
|
||||
// to the account. This change will always be a negative change as we "drain" left over gas towards 0. If there was no gas
|
||||
// left at the end of execution, no such even will be emitted. The returned gas's value in Wei is returned to caller.
|
||||
// There is at most one of such gas change per transaction.
|
||||
GasChangeTxLeftOverReturned GasChangeReason = 4
|
||||
|
|
|
|||
|
|
@ -1055,7 +1055,7 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
|
|||
|
||||
// Call Prepare to clear out the statedb access list
|
||||
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
||||
_, err = core.ApplyTransactionWithEVM(message, new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, vmctx.Time, tx, &usedGas, evm)
|
||||
_, _, err = core.ApplyTransactionWithEVM(message, new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, vmctx.Time, tx, usedGas, evm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tracing failed: %w", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -620,8 +620,7 @@ func TestSelfdestructStateTracer(t *testing.T) {
|
|||
}
|
||||
context := core.NewEVMBlockContext(block.Header(), blockchain, nil)
|
||||
evm := vm.NewEVM(context, hookedState, tt.genesis.Config, vm.Config{Tracer: tracer.Hooks()})
|
||||
usedGas := uint64(0)
|
||||
_, err = core.ApplyTransactionWithEVM(msg, new(core.GasPool).AddGas(tx.Gas()), statedb, block.Number(), block.Hash(), block.Time(), tx, &usedGas, evm)
|
||||
_, _, err = core.ApplyTransactionWithEVM(msg, new(core.GasPool).AddGas(tx.Gas()), statedb, block.Number(), block.Hash(), block.Time(), tx, uint64(0), evm)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to execute transaction: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,13 +56,14 @@ func (miner *Miner) maxBlobsPerBlock(time uint64) int {
|
|||
// environment is the worker's current environment and holds all
|
||||
// information of the sealing block generation.
|
||||
type environment struct {
|
||||
signer types.Signer
|
||||
state *state.StateDB // apply state changes here
|
||||
tcount int // tx count in cycle
|
||||
size uint64 // size of the block we are building
|
||||
gasPool *core.GasPool // available gas used to pack transactions
|
||||
coinbase common.Address
|
||||
evm *vm.EVM
|
||||
signer types.Signer
|
||||
state *state.StateDB // apply state changes here
|
||||
tcount int // tx count in cycle
|
||||
size uint64 // size of the block we are building
|
||||
gasPool *core.GasPool // available gas used to pack transactions
|
||||
coinbase common.Address
|
||||
evm *vm.EVM
|
||||
cumulativeGas uint64
|
||||
|
||||
header *types.Header
|
||||
txs []*types.Transaction
|
||||
|
|
@ -374,12 +375,15 @@ func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*
|
|||
snap = env.state.Snapshot()
|
||||
gp = env.gasPool.Gas()
|
||||
)
|
||||
receipt, err := core.ApplyTransaction(env.evm, env.gasPool, env.state, env.header, tx, &env.header.GasUsed)
|
||||
receipt, cumulativeGas, err := core.ApplyTransaction(env.evm, env.gasPool, env.state, env.header, tx, env.cumulativeGas)
|
||||
if err != nil {
|
||||
env.state.RevertToSnapshot(snap)
|
||||
env.gasPool.SetGas(gp)
|
||||
return nil, err
|
||||
}
|
||||
return receipt, err
|
||||
env.cumulativeGas = cumulativeGas
|
||||
env.header.GasUsed += receipt.GasUsed
|
||||
return receipt, nil
|
||||
}
|
||||
|
||||
func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
|
||||
|
|
|
|||
Loading…
Reference in a new issue