mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 03:10:48 +00:00
core, eth, internal, miner: rework the gaspool
This commit is contained in:
parent
2e5c9c2e0f
commit
c6f6dbc50c
23 changed files with 215 additions and 145 deletions
|
|
@ -149,15 +149,13 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
isEIP4762 = chainConfig.IsVerkle(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp)
|
isEIP4762 = chainConfig.IsVerkle(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp)
|
||||||
statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre, isEIP4762)
|
statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre, isEIP4762)
|
||||||
signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp)
|
signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp)
|
||||||
gaspool = new(core.GasPool)
|
gaspool = core.NewGasPool(pre.Env.GasLimit)
|
||||||
blockHash = common.Hash{0x13, 0x37}
|
blockHash = common.Hash{0x13, 0x37}
|
||||||
rejectedTxs []*rejectedTx
|
rejectedTxs []*rejectedTx
|
||||||
includedTxs types.Transactions
|
includedTxs types.Transactions
|
||||||
gasUsed = uint64(0)
|
|
||||||
blobGasUsed = uint64(0)
|
blobGasUsed = uint64(0)
|
||||||
receipts = make(types.Receipts, 0)
|
receipts = make(types.Receipts, 0)
|
||||||
)
|
)
|
||||||
gaspool.AddGas(pre.Env.GasLimit)
|
|
||||||
vmContext := vm.BlockContext{
|
vmContext := vm.BlockContext{
|
||||||
CanTransfer: core.CanTransfer,
|
CanTransfer: core.CanTransfer,
|
||||||
Transfer: core.Transfer,
|
Transfer: core.Transfer,
|
||||||
|
|
@ -258,20 +256,19 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
statedb.SetTxContext(tx.Hash(), len(receipts))
|
statedb.SetTxContext(tx.Hash(), len(receipts))
|
||||||
var (
|
var (
|
||||||
snapshot = statedb.Snapshot()
|
snapshot = statedb.Snapshot()
|
||||||
prevGas = gaspool.Gas()
|
gp = gaspool.Snapshot()
|
||||||
)
|
)
|
||||||
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, evm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
statedb.RevertToSnapshot(snapshot)
|
statedb.RevertToSnapshot(snapshot)
|
||||||
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
|
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
|
||||||
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
||||||
gaspool.SetGas(prevGas)
|
gaspool.Set(gp)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if receipt.Logs == nil {
|
if receipt.Logs == nil {
|
||||||
receipt.Logs = []*types.Log{}
|
receipt.Logs = []*types.Log{}
|
||||||
}
|
}
|
||||||
gasUsed += receipt.GasUsed
|
|
||||||
includedTxs = append(includedTxs, tx)
|
includedTxs = append(includedTxs, tx)
|
||||||
if hashError != nil {
|
if hashError != nil {
|
||||||
return nil, nil, nil, NewError(ErrorMissingBlockhash, hashError)
|
return nil, nil, nil, NewError(ErrorMissingBlockhash, hashError)
|
||||||
|
|
@ -353,7 +350,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
Receipts: receipts,
|
Receipts: receipts,
|
||||||
Rejected: rejectedTxs,
|
Rejected: rejectedTxs,
|
||||||
Difficulty: (*math.HexOrDecimal256)(vmContext.Difficulty),
|
Difficulty: (*math.HexOrDecimal256)(vmContext.Difficulty),
|
||||||
GasUsed: (math.HexOrDecimal64)(gasUsed),
|
GasUsed: (math.HexOrDecimal64)(gaspool.Used()),
|
||||||
BaseFee: (*math.HexOrDecimal256)(vmContext.BaseFee),
|
BaseFee: (*math.HexOrDecimal256)(vmContext.BaseFee),
|
||||||
}
|
}
|
||||||
if pre.Env.Withdrawals != nil {
|
if pre.Env.Withdrawals != nil {
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,11 @@ import (
|
||||||
// BlockGen creates blocks for testing.
|
// BlockGen creates blocks for testing.
|
||||||
// See GenerateChain for a detailed explanation.
|
// See GenerateChain for a detailed explanation.
|
||||||
type BlockGen struct {
|
type BlockGen struct {
|
||||||
i int
|
i int
|
||||||
cumulativeGas uint64
|
cm *chainMaker
|
||||||
cm *chainMaker
|
parent *types.Block
|
||||||
parent *types.Block
|
header *types.Header
|
||||||
header *types.Header
|
statedb *state.StateDB
|
||||||
statedb *state.StateDB
|
|
||||||
|
|
||||||
gasPool *GasPool
|
gasPool *GasPool
|
||||||
txs []*types.Transaction
|
txs []*types.Transaction
|
||||||
|
|
@ -64,7 +63,7 @@ func (b *BlockGen) SetCoinbase(addr common.Address) {
|
||||||
panic("coinbase can only be set once")
|
panic("coinbase can only be set once")
|
||||||
}
|
}
|
||||||
b.header.Coinbase = addr
|
b.header.Coinbase = addr
|
||||||
b.gasPool = new(GasPool).AddGas(b.header.GasLimit)
|
b.gasPool = NewGasPool(b.header.GasLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetExtra sets the extra data field of the generated block.
|
// SetExtra sets the extra data field of the generated block.
|
||||||
|
|
@ -120,11 +119,12 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
b.statedb.SetTxContext(tx.Hash(), len(b.txs))
|
b.statedb.SetTxContext(tx.Hash(), len(b.txs))
|
||||||
receipt, b.cumulativeGas, err = ApplyTransaction(evm, b.gasPool, b.statedb, b.header, tx, b.cumulativeGas)
|
receipt, err = ApplyTransaction(evm, b.gasPool, b.statedb, b.header, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
b.header.GasUsed += receipt.GasUsed
|
b.header.GasUsed = b.gasPool.Used()
|
||||||
|
|
||||||
// Merge the tx-local access event into the "block-local" one, in order to collect
|
// Merge the tx-local access event into the "block-local" one, in order to collect
|
||||||
// all values, so that the witness can be built.
|
// all values, so that the witness can be built.
|
||||||
if b.statedb.Database().TrieDB().IsVerkle() {
|
if b.statedb.Database().TrieDB().IsVerkle() {
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,10 @@ var (
|
||||||
// by a transaction is higher than what's left in the block.
|
// by a transaction is higher than what's left in the block.
|
||||||
ErrGasLimitReached = errors.New("gas limit reached")
|
ErrGasLimitReached = errors.New("gas limit reached")
|
||||||
|
|
||||||
|
// ErrGasLimitOverflow is returned by the gas pool if the remaining gas
|
||||||
|
// exceeds the maximum value of uint64.
|
||||||
|
ErrGasLimitOverflow = errors.New("gas limit overflow")
|
||||||
|
|
||||||
// ErrInsufficientFundsForTransfer is returned if the transaction sender doesn't
|
// ErrInsufficientFundsForTransfer is returned if the transaction sender doesn't
|
||||||
// have enough funds for transfer(topmost call only).
|
// have enough funds for transfer(topmost call only).
|
||||||
ErrInsufficientFundsForTransfer = errors.New("insufficient funds for transfer")
|
ErrInsufficientFundsForTransfer = errors.New("insufficient funds for transfer")
|
||||||
|
|
|
||||||
|
|
@ -21,39 +21,87 @@ import (
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GasPool tracks the amount of gas available during execution of the transactions
|
// GasPool tracks the amount of gas available for transaction execution
|
||||||
// in a block. The zero value is a pool with zero gas available.
|
// within a block, along with the cumulative gas consumed.
|
||||||
type GasPool uint64
|
type GasPool struct {
|
||||||
|
remaining uint64
|
||||||
|
initial uint64
|
||||||
|
cumulativeUsed uint64
|
||||||
|
}
|
||||||
|
|
||||||
// AddGas makes gas available for execution.
|
// NewGasPool initializes the gasPool with the given amount.
|
||||||
func (gp *GasPool) AddGas(amount uint64) *GasPool {
|
func NewGasPool(amount uint64) *GasPool {
|
||||||
if uint64(*gp) > math.MaxUint64-amount {
|
return &GasPool{
|
||||||
panic("gas pool pushed above uint64")
|
remaining: amount,
|
||||||
|
initial: amount,
|
||||||
}
|
}
|
||||||
*(*uint64)(gp) += amount
|
|
||||||
return gp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubGas deducts the given amount from the pool if enough gas is
|
// SubGas deducts the given amount from the pool if enough gas is
|
||||||
// available and returns an error otherwise.
|
// available and returns an error otherwise.
|
||||||
func (gp *GasPool) SubGas(amount uint64) error {
|
func (gp *GasPool) SubGas(amount uint64) error {
|
||||||
if uint64(*gp) < amount {
|
if gp.remaining < amount {
|
||||||
return ErrGasLimitReached
|
return ErrGasLimitReached
|
||||||
}
|
}
|
||||||
*(*uint64)(gp) -= amount
|
gp.remaining -= amount
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReturnGas adds the refunded gas back to the pool and updates
|
||||||
|
// the cumulative gas usage accordingly.
|
||||||
|
func (gp *GasPool) ReturnGas(returned uint64, gasUsed uint64) error {
|
||||||
|
if gp.remaining > math.MaxUint64-returned {
|
||||||
|
return fmt.Errorf("%w: remaining: %d, returned: %d", ErrGasLimitOverflow, gp.remaining, returned)
|
||||||
|
}
|
||||||
|
// The returned gas calculation differs across forks.
|
||||||
|
//
|
||||||
|
// - Pre-Amsterdam:
|
||||||
|
// returned = purchased - remaining (refund included)
|
||||||
|
//
|
||||||
|
// - Post-Amsterdam:
|
||||||
|
// returned = purchased - gasUsed (refund excluded)
|
||||||
|
gp.remaining += returned
|
||||||
|
|
||||||
|
// gasUsed = max(txGasUsed - gasRefund, calldataFloorGasCost)
|
||||||
|
// regardless of Amsterdam is activated or not.
|
||||||
|
gp.cumulativeUsed += gasUsed
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gas returns the amount of gas remaining in the pool.
|
// Gas returns the amount of gas remaining in the pool.
|
||||||
func (gp *GasPool) Gas() uint64 {
|
func (gp *GasPool) Gas() uint64 {
|
||||||
return uint64(*gp)
|
return gp.remaining
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGas sets the amount of gas with the provided number.
|
// CumulativeUsed returns the amount of cumulative consumed gas (refunded included).
|
||||||
func (gp *GasPool) SetGas(gas uint64) {
|
func (gp *GasPool) CumulativeUsed() uint64 {
|
||||||
*(*uint64)(gp) = gas
|
return gp.cumulativeUsed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used returns the amount of consumed gas.
|
||||||
|
func (gp *GasPool) Used() uint64 {
|
||||||
|
if gp.initial < gp.remaining {
|
||||||
|
panic("gas used underflow")
|
||||||
|
}
|
||||||
|
return gp.initial - gp.remaining
|
||||||
|
}
|
||||||
|
|
||||||
|
// Snapshot returns the deep-copied object as the snapshot.
|
||||||
|
func (gp *GasPool) Snapshot() *GasPool {
|
||||||
|
return &GasPool{
|
||||||
|
initial: gp.initial,
|
||||||
|
remaining: gp.remaining,
|
||||||
|
cumulativeUsed: gp.cumulativeUsed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the content of gasPool with the provided one.
|
||||||
|
func (gp *GasPool) Set(other *GasPool) {
|
||||||
|
gp.initial = other.initial
|
||||||
|
gp.remaining = other.remaining
|
||||||
|
gp.cumulativeUsed = other.cumulativeUsed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gp *GasPool) String() string {
|
func (gp *GasPool) String() string {
|
||||||
return fmt.Sprintf("%d", *gp)
|
return fmt.Sprintf("initial: %d, remaining: %d, cumulative used: %d", gp.initial, gp.remaining, gp.cumulativeUsed)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
||||||
|
|
||||||
// We attempt to apply a transaction. The goal is not to execute
|
// We attempt to apply a transaction. The goal is not to execute
|
||||||
// the transaction successfully, rather to warm up touched data slots.
|
// the transaction successfully, rather to warm up touched data slots.
|
||||||
if _, err := ApplyMessage(evm, msg, new(GasPool).AddGas(block.GasLimit())); err != nil {
|
if _, err := ApplyMessage(evm, msg, nil); err != nil {
|
||||||
fails.Add(1)
|
fails.Add(1)
|
||||||
return nil // Ugh, something went horribly wrong, bail out
|
return nil // Ugh, something went horribly wrong, bail out
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,15 +67,8 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated
|
||||||
blockHash = block.Hash()
|
blockHash = block.Hash()
|
||||||
blockNumber = block.Number()
|
blockNumber = block.Number()
|
||||||
allLogs []*types.Log
|
allLogs []*types.Log
|
||||||
gp = new(GasPool).AddGas(block.GasLimit())
|
gp = NewGasPool(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)
|
var tracingStateDB = vm.StateDB(statedb)
|
||||||
if hooks := cfg.Tracer; hooks != nil {
|
if hooks := cfg.Tracer; hooks != nil {
|
||||||
tracingStateDB = state.NewHookedState(statedb, hooks)
|
tracingStateDB = state.NewHookedState(statedb, hooks)
|
||||||
|
|
@ -114,11 +107,10 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated
|
||||||
)
|
)
|
||||||
|
|
||||||
var receipt *types.Receipt
|
var receipt *types.Receipt
|
||||||
receipt, cumulativeGas, err = ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, context.Time, tx, cumulativeGas, evm)
|
receipt, err = ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, context.Time, tx, evm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||||
}
|
}
|
||||||
usedGas += receipt.GasUsed
|
|
||||||
receipts = append(receipts, receipt)
|
receipts = append(receipts, receipt)
|
||||||
allLogs = append(allLogs, receipt.Logs...)
|
allLogs = append(allLogs, receipt.Logs...)
|
||||||
|
|
||||||
|
|
@ -136,7 +128,7 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated
|
||||||
Receipts: receipts,
|
Receipts: receipts,
|
||||||
Requests: requests,
|
Requests: requests,
|
||||||
Logs: allLogs,
|
Logs: allLogs,
|
||||||
GasUsed: usedGas,
|
GasUsed: gp.Used(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,7 +160,7 @@ func postExecution(ctx context.Context, config *params.ChainConfig, block *types
|
||||||
// ApplyTransactionWithEVM attempts to apply a transaction to the given state database
|
// ApplyTransactionWithEVM attempts to apply a transaction to the given state database
|
||||||
// and uses the input parameters for its environment similar to ApplyTransaction. However,
|
// and uses the input parameters for its environment similar to ApplyTransaction. However,
|
||||||
// this method takes an already created EVM instance as input.
|
// 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, cumulativeGas uint64, evm *vm.EVM) (receipt *types.Receipt, cGas uint64, err error) {
|
func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, evm *vm.EVM) (receipt *types.Receipt, err error) {
|
||||||
if hooks := evm.Config.Tracer; hooks != nil {
|
if hooks := evm.Config.Tracer; hooks != nil {
|
||||||
if hooks.OnTxStart != nil {
|
if hooks.OnTxStart != nil {
|
||||||
hooks.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
hooks.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
|
|
@ -180,7 +172,7 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB,
|
||||||
// Apply the transaction to the current state (included in the env).
|
// Apply the transaction to the current state (included in the env).
|
||||||
result, err := ApplyMessage(evm, msg, gp)
|
result, err := ApplyMessage(evm, msg, gp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cumulativeGas, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Update the state with pending changes.
|
// Update the state with pending changes.
|
||||||
var root []byte
|
var root []byte
|
||||||
|
|
@ -189,20 +181,21 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB,
|
||||||
} else {
|
} else {
|
||||||
root = statedb.IntermediateRoot(evm.ChainConfig().IsEIP158(blockNumber)).Bytes()
|
root = statedb.IntermediateRoot(evm.ChainConfig().IsEIP158(blockNumber)).Bytes()
|
||||||
}
|
}
|
||||||
cGas = cumulativeGas + result.UsedGas
|
|
||||||
|
|
||||||
// Merge the tx-local access event into the "block-local" one, in order to collect
|
// Merge the tx-local access event into the "block-local" one, in order to collect
|
||||||
// all values, so that the witness can be built.
|
// all values, so that the witness can be built.
|
||||||
if statedb.Database().TrieDB().IsVerkle() {
|
if statedb.Database().TrieDB().IsVerkle() {
|
||||||
statedb.AccessEvents().Merge(evm.AccessEvents)
|
statedb.AccessEvents().Merge(evm.AccessEvents)
|
||||||
}
|
}
|
||||||
return MakeReceipt(evm, result, statedb, blockNumber, blockHash, blockTime, tx, cGas, root), cGas, nil
|
return MakeReceipt(evm, result, statedb, blockNumber, blockHash, blockTime, tx, gp.CumulativeUsed(), root), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeReceipt generates the receipt object for a transaction given its execution result.
|
// 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, cumulativeGas 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
|
// Create a new receipt for the transaction, storing the intermediate root
|
||||||
// by the tx.
|
// and gas used by the tx.
|
||||||
|
//
|
||||||
|
// The cumulative gas used equals the sum of gasUsed across all preceding
|
||||||
|
// txs with refunded gas deducted.
|
||||||
receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: cumulativeGas}
|
receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: cumulativeGas}
|
||||||
if result.Failed() {
|
if result.Failed() {
|
||||||
receipt.Status = types.ReceiptStatusFailed
|
receipt.Status = types.ReceiptStatusFailed
|
||||||
|
|
@ -210,11 +203,10 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b
|
||||||
receipt.Status = types.ReceiptStatusSuccessful
|
receipt.Status = types.ReceiptStatusSuccessful
|
||||||
}
|
}
|
||||||
receipt.TxHash = tx.Hash()
|
receipt.TxHash = tx.Hash()
|
||||||
if evm.ChainConfig().IsAmsterdam(blockNumber, blockTime) {
|
|
||||||
receipt.GasUsed = result.MaxUsedGas
|
// GasUsed = max(tx_gas_used - gas_refund, calldata_floor_gas_cost), unchanged
|
||||||
} else {
|
// in the Amsterdam fork.
|
||||||
receipt.GasUsed = result.UsedGas
|
receipt.GasUsed = result.UsedGas
|
||||||
}
|
|
||||||
|
|
||||||
if tx.Type() == types.BlobTxType {
|
if tx.Type() == types.BlobTxType {
|
||||||
receipt.BlobGasUsed = uint64(len(tx.BlobHashes()) * params.BlobTxBlobGasPerBlob)
|
receipt.BlobGasUsed = uint64(len(tx.BlobHashes()) * params.BlobTxBlobGasPerBlob)
|
||||||
|
|
@ -239,13 +231,13 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b
|
||||||
// and uses the input parameters for its environment. It returns the receipt
|
// and uses the input parameters for its environment. It returns the receipt
|
||||||
// for the transaction and an error if the transaction failed,
|
// for the transaction and an error if the transaction failed,
|
||||||
// indicating the block was invalid.
|
// indicating the block was invalid.
|
||||||
func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, cumulativeGas uint64) (*types.Receipt, uint64, error) {
|
func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction) (*types.Receipt, error) {
|
||||||
msg, err := TransactionToMessage(tx, types.MakeSigner(evm.ChainConfig(), header.Number, header.Time), header.BaseFee)
|
msg, err := TransactionToMessage(tx, types.MakeSigner(evm.ChainConfig(), header.Number, header.Time), header.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cumulativeGas, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Create a new context to be used in the EVM environment
|
// Create a new context to be used in the EVM environment
|
||||||
return ApplyTransactionWithEVM(msg, gp, statedb, header.Number, header.Hash(), header.Time, tx, cumulativeGas, evm)
|
return ApplyTransactionWithEVM(msg, gp, statedb, header.Number, header.Hash(), header.Time, tx, evm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
|
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ import (
|
||||||
// ExecutionResult includes all output after executing given evm
|
// ExecutionResult includes all output after executing given evm
|
||||||
// message no matter the execution itself is successful or not.
|
// message no matter the execution itself is successful or not.
|
||||||
type ExecutionResult struct {
|
type ExecutionResult struct {
|
||||||
UsedGas uint64 // Total used gas, not including the refunded gas
|
UsedGas uint64 // Total used gas, refunded gas is deducted
|
||||||
MaxUsedGas uint64 // Maximum gas consumed during execution, excluding gas refunds.
|
MaxUsedGas uint64 // Maximum gas consumed during execution, excluding gas refunds.
|
||||||
Err error // Any error encountered during the execution(listed in core/vm/errors.go)
|
Err error // Any error encountered during the execution(listed in core/vm/errors.go)
|
||||||
ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
|
ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
|
||||||
|
|
@ -210,6 +210,11 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
|
||||||
// indicates a core error meaning that the message would always fail for that particular
|
// indicates a core error meaning that the message would always fail for that particular
|
||||||
// state and would never be accepted within a block.
|
// state and would never be accepted within a block.
|
||||||
func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) {
|
func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) {
|
||||||
|
// Do not panic if the gas pool is nil. This is allowed when executing
|
||||||
|
// a single message via RPC invocation.
|
||||||
|
if gp == nil {
|
||||||
|
gp = NewGasPool(msg.GasLimit)
|
||||||
|
}
|
||||||
evm.SetTxContext(NewEVMTxContext(msg))
|
evm.SetTxContext(NewEVMTxContext(msg))
|
||||||
return newStateTransition(evm, msg, gp).execute()
|
return newStateTransition(evm, msg, gp).execute()
|
||||||
}
|
}
|
||||||
|
|
@ -300,8 +305,8 @@ func (st *stateTransition) buyGas() error {
|
||||||
st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, tracing.GasChangeTxInitialBalance)
|
st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, tracing.GasChangeTxInitialBalance)
|
||||||
}
|
}
|
||||||
st.gasRemaining = st.msg.GasLimit
|
st.gasRemaining = st.msg.GasLimit
|
||||||
|
|
||||||
st.initialGas = st.msg.GasLimit
|
st.initialGas = st.msg.GasLimit
|
||||||
|
|
||||||
mgvalU256, _ := uint256.FromBig(mgval)
|
mgvalU256, _ := uint256.FromBig(mgval)
|
||||||
st.state.SubBalance(st.msg.From, mgvalU256, tracing.BalanceDecreaseGasBuy)
|
st.state.SubBalance(st.msg.From, mgvalU256, tracing.BalanceDecreaseGasBuy)
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -544,13 +549,18 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
}
|
}
|
||||||
// Return gas to the user
|
// Return gas to the user
|
||||||
st.returnGas()
|
st.returnGas()
|
||||||
|
|
||||||
// Return gas to the gas pool
|
// Return gas to the gas pool
|
||||||
if rules.IsAmsterdam {
|
if rules.IsAmsterdam {
|
||||||
st.gp.AddGas(st.initialGas - peakGasUsed)
|
// Refund is excluded for returning
|
||||||
|
err = st.gp.ReturnGas(st.initialGas-peakGasUsed, st.gasUsed())
|
||||||
} else {
|
} else {
|
||||||
st.gp.AddGas(st.gasRemaining)
|
// Refund is included for returning
|
||||||
|
err = st.gp.ReturnGas(st.gasRemaining, st.gasUsed())
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
effectiveTip := msg.GasPrice
|
effectiveTip := msg.GasPrice
|
||||||
if rules.IsLondon {
|
if rules.IsLondon {
|
||||||
effectiveTip = new(big.Int).Sub(msg.GasPrice, st.evm.Context.BaseFee)
|
effectiveTip = new(big.Int).Sub(msg.GasPrice, st.evm.Context.BaseFee)
|
||||||
|
|
@ -571,7 +581,6 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
st.evm.AccessEvents.AddAccount(st.evm.Context.Coinbase, true, math.MaxUint64)
|
st.evm.AccessEvents.AddAccount(st.evm.Context.Coinbase, true, math.MaxUint64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ExecutionResult{
|
return &ExecutionResult{
|
||||||
UsedGas: st.gasUsed(),
|
UsedGas: st.gasUsed(),
|
||||||
MaxUsedGas: peakGasUsed,
|
MaxUsedGas: peakGasUsed,
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -268,7 +267,7 @@ func run(ctx context.Context, call *core.Message, opts *Options) (*core.Executio
|
||||||
evm.Cancel()
|
evm.Cancel()
|
||||||
}()
|
}()
|
||||||
// Execute the call, returning a wrapped error or the result
|
// Execute the call, returning a wrapped error or the result
|
||||||
result, err := core.ApplyMessage(evm, call, new(core.GasPool).AddGas(math.MaxUint64))
|
result, err := core.ApplyMessage(evm, call, nil)
|
||||||
if vmerr := dirtyState.Error(); vmerr != nil {
|
if vmerr := dirtyState.Error(); vmerr != nil {
|
||||||
return nil, vmerr
|
return nil, vmerr
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -265,7 +265,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
|
||||||
|
|
||||||
// Not yet the searched for transaction, execute on top of the current state
|
// Not yet the searched for transaction, execute on top of the current state
|
||||||
statedb.SetTxContext(tx.Hash(), idx)
|
statedb.SetTxContext(tx.Hash(), idx)
|
||||||
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
if _, err := core.ApplyMessage(evm, msg, nil); err != nil {
|
||||||
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
||||||
}
|
}
|
||||||
// Ensure any modifications are committed to the state
|
// Ensure any modifications are committed to the state
|
||||||
|
|
|
||||||
|
|
@ -551,7 +551,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
|
||||||
}
|
}
|
||||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
|
if _, err := core.ApplyMessage(evm, msg, nil); err != nil {
|
||||||
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
|
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
|
||||||
// We intentionally don't return the error here: if we do, then the RPC server will not
|
// We intentionally don't return the error here: if we do, then the RPC server will not
|
||||||
// return the roots. Most likely, the caller already knows that a certain transaction fails to
|
// return the roots. Most likely, the caller already knows that a certain transaction fails to
|
||||||
|
|
@ -707,7 +707,7 @@ txloop:
|
||||||
// Generate the next state snapshot fast without tracing
|
// Generate the next state snapshot fast without tracing
|
||||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
|
if _, err := core.ApplyMessage(evm, msg, nil); err != nil {
|
||||||
failed = err
|
failed = err
|
||||||
break txloop
|
break txloop
|
||||||
}
|
}
|
||||||
|
|
@ -792,7 +792,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
||||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
if txHash != (common.Hash{}) && tx.Hash() != txHash {
|
if txHash != (common.Hash{}) && tx.Hash() != txHash {
|
||||||
// Process the tx to update state, but don't trace it.
|
// Process the tx to update state, but don't trace it.
|
||||||
_, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
_, err := core.ApplyMessage(evm, msg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return dumps, err
|
return dumps, err
|
||||||
}
|
}
|
||||||
|
|
@ -827,7 +827,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
||||||
if tracer.OnTxStart != nil {
|
if tracer.OnTxStart != nil {
|
||||||
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
}
|
}
|
||||||
_, err = core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
_, err = core.ApplyMessage(evm, msg, nil)
|
||||||
if writer != nil {
|
if writer != nil {
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
}
|
}
|
||||||
|
|
@ -1011,7 +1011,6 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
|
||||||
tracer *Tracer
|
tracer *Tracer
|
||||||
err error
|
err error
|
||||||
timeout = defaultTraceTimeout
|
timeout = defaultTraceTimeout
|
||||||
usedGas uint64
|
|
||||||
)
|
)
|
||||||
if config == nil {
|
if config == nil {
|
||||||
config = &TraceConfig{}
|
config = &TraceConfig{}
|
||||||
|
|
@ -1055,7 +1054,8 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
|
||||||
|
|
||||||
// Call Prepare to clear out the statedb access list
|
// Call Prepare to clear out the statedb access list
|
||||||
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
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, core.NewGasPool(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, vmctx.Time, tx, evm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("tracing failed: %w", err)
|
return nil, fmt.Errorf("tracing failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
|
||||||
return tx, context, statedb, release, nil
|
return tx, context, statedb, release, nil
|
||||||
}
|
}
|
||||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
if _, err := core.ApplyMessage(evm, msg, nil); err != nil {
|
||||||
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
||||||
}
|
}
|
||||||
statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number()))
|
statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number()))
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, logState, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
evm := vm.NewEVM(context, logState, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
||||||
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
vmRet, err := core.ApplyMessage(evm, msg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to execute transaction: %v", err)
|
t.Fatalf("failed to execute transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -224,7 +224,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
|
||||||
if tracer.OnTxStart != nil {
|
if tracer.OnTxStart != nil {
|
||||||
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
}
|
}
|
||||||
_, err = core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
_, err = core.ApplyMessage(evm, msg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed to execute transaction: %v", err)
|
b.Fatalf("failed to execute transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -374,7 +374,7 @@ func TestInternals(t *testing.T) {
|
||||||
t.Fatalf("test %v: failed to create message: %v", tc.name, err)
|
t.Fatalf("test %v: failed to create message: %v", tc.name, err)
|
||||||
}
|
}
|
||||||
tc.tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
tc.tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
vmRet, err := core.ApplyMessage(evm, msg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err)
|
t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ func TestErc7562Tracer(t *testing.T) {
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, logState, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
evm := vm.NewEVM(context, logState, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
||||||
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
vmRet, err := core.ApplyMessage(evm, msg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to execute transaction: %v", err)
|
t.Fatalf("failed to execute transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
||||||
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
vmRet, err := core.ApplyMessage(evm, msg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute transaction: %v", err)
|
return fmt.Errorf("failed to execute transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ func testPrestateTracer(tracerName string, dirPath string, t *testing.T) {
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
||||||
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
vmRet, err := core.ApplyMessage(evm, msg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to execute transaction: %v", err)
|
t.Fatalf("failed to execute transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -620,7 +620,7 @@ func TestSelfdestructStateTracer(t *testing.T) {
|
||||||
}
|
}
|
||||||
context := core.NewEVMBlockContext(block.Header(), blockchain, nil)
|
context := core.NewEVMBlockContext(block.Header(), blockchain, nil)
|
||||||
evm := vm.NewEVM(context, hookedState, tt.genesis.Config, vm.Config{Tracer: tracer.Hooks()})
|
evm := vm.NewEVM(context, hookedState, tt.genesis.Config, vm.Config{Tracer: tracer.Hooks()})
|
||||||
_, _, err = core.ApplyTransactionWithEVM(msg, new(core.GasPool).AddGas(tx.Gas()), statedb, block.Number(), block.Hash(), block.Time(), tx, uint64(0), evm)
|
_, err = core.ApplyTransactionWithEVM(msg, core.NewGasPool(msg.GasLimit), statedb, block.Number(), block.Hash(), block.Time(), tx, evm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to execute transaction: %v", err)
|
t.Fatalf("failed to execute transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ func BenchmarkTransactionTraceV2(b *testing.B) {
|
||||||
evm.Config.Tracer = tracer
|
evm.Config.Tracer = tracer
|
||||||
|
|
||||||
snap := state.StateDB.Snapshot()
|
snap := state.StateDB.Snapshot()
|
||||||
_, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
_, err := core.ApplyMessage(evm, msg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -741,11 +741,10 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S
|
||||||
// Make sure the context is cancelled when the call has completed
|
// Make sure the context is cancelled when the call has completed
|
||||||
// this makes sure resources are cleaned up.
|
// this makes sure resources are cleaned up.
|
||||||
defer cancel()
|
defer cancel()
|
||||||
gp := new(core.GasPool)
|
|
||||||
|
gp := core.NewGasPool(globalGasCap)
|
||||||
if globalGasCap == 0 {
|
if globalGasCap == 0 {
|
||||||
gp.AddGas(gomath.MaxUint64)
|
gp = core.NewGasPool(gomath.MaxUint64)
|
||||||
} else {
|
|
||||||
gp.AddGas(globalGasCap)
|
|
||||||
}
|
}
|
||||||
return applyMessage(ctx, b, args, state, header, timeout, gp, &blockCtx, &vm.Config{NoBaseFee: true}, precompiles)
|
return applyMessage(ctx, b, args, state, header, timeout, gp, &blockCtx, &vm.Config{NoBaseFee: true}, precompiles)
|
||||||
}
|
}
|
||||||
|
|
@ -855,12 +854,11 @@ func (api *BlockChainAPI) SimulateV1(ctx context.Context, opts simOpts, blockNrO
|
||||||
gasCap = gomath.MaxUint64
|
gasCap = gomath.MaxUint64
|
||||||
}
|
}
|
||||||
sim := &simulator{
|
sim := &simulator{
|
||||||
b: api.b,
|
b: api.b,
|
||||||
state: state,
|
state: state,
|
||||||
base: base,
|
base: base,
|
||||||
chainConfig: api.b.ChainConfig(),
|
chainConfig: api.b.ChainConfig(),
|
||||||
// Each tx and all the series of txes shouldn't consume more gas than cap
|
gasRemaining: gasCap,
|
||||||
gp: new(core.GasPool).AddGas(gasCap),
|
|
||||||
traceTransfers: opts.TraceTransfers,
|
traceTransfers: opts.TraceTransfers,
|
||||||
validate: opts.Validation,
|
validate: opts.Validation,
|
||||||
fullTx: opts.ReturnFullTransactions,
|
fullTx: opts.ReturnFullTransactions,
|
||||||
|
|
@ -1369,7 +1367,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
|
||||||
if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 {
|
if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 {
|
||||||
evm.Context.BlobBaseFee = new(big.Int)
|
evm.Context.BlobBaseFee = new(big.Int)
|
||||||
}
|
}
|
||||||
res, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
res, err := core.ApplyMessage(evm, msg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction(types.LegacyTxType).Hash(), err)
|
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction(types.LegacyTxType).Hash(), err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2507,7 +2507,7 @@ func TestSimulateV1ChainLinkage(t *testing.T) {
|
||||||
state: stateDB,
|
state: stateDB,
|
||||||
base: baseHeader,
|
base: baseHeader,
|
||||||
chainConfig: backend.ChainConfig(),
|
chainConfig: backend.ChainConfig(),
|
||||||
gp: new(core.GasPool).AddGas(math.MaxUint64),
|
gasRemaining: math.MaxUint64,
|
||||||
traceTransfers: false,
|
traceTransfers: false,
|
||||||
validate: false,
|
validate: false,
|
||||||
fullTx: false,
|
fullTx: false,
|
||||||
|
|
@ -2592,7 +2592,7 @@ func TestSimulateV1TxSender(t *testing.T) {
|
||||||
state: stateDB,
|
state: stateDB,
|
||||||
base: baseHeader,
|
base: baseHeader,
|
||||||
chainConfig: backend.ChainConfig(),
|
chainConfig: backend.ChainConfig(),
|
||||||
gp: new(core.GasPool).AddGas(math.MaxUint64),
|
gasRemaining: math.MaxUint64,
|
||||||
traceTransfers: false,
|
traceTransfers: false,
|
||||||
validate: false,
|
validate: false,
|
||||||
fullTx: true,
|
fullTx: true,
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ type simulator struct {
|
||||||
state *state.StateDB
|
state *state.StateDB
|
||||||
base *types.Header
|
base *types.Header
|
||||||
chainConfig *params.ChainConfig
|
chainConfig *params.ChainConfig
|
||||||
gp *core.GasPool
|
gasRemaining uint64
|
||||||
traceTransfers bool
|
traceTransfers bool
|
||||||
validate bool
|
validate bool
|
||||||
fullTx bool
|
fullTx bool
|
||||||
|
|
@ -200,7 +200,13 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]*simBlo
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
headers[bi] = result.Header()
|
headers[bi] = result.Header()
|
||||||
results[bi] = &simBlockResult{fullTx: sim.fullTx, chainConfig: sim.chainConfig, Block: result, Calls: callResults, senders: senders}
|
results[bi] = &simBlockResult{
|
||||||
|
fullTx: sim.fullTx,
|
||||||
|
chainConfig: sim.chainConfig,
|
||||||
|
Block: result,
|
||||||
|
Calls: callResults,
|
||||||
|
senders: senders,
|
||||||
|
}
|
||||||
parent = result.Header()
|
parent = result.Header()
|
||||||
}
|
}
|
||||||
return results, nil
|
return results, nil
|
||||||
|
|
@ -234,15 +240,19 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
||||||
blockContext.BlobBaseFee = block.BlockOverrides.BlobBaseFee.ToInt()
|
blockContext.BlobBaseFee = block.BlockOverrides.BlobBaseFee.ToInt()
|
||||||
}
|
}
|
||||||
precompiles := sim.activePrecompiles(header)
|
precompiles := sim.activePrecompiles(header)
|
||||||
|
|
||||||
// State overrides are applied prior to execution of a block
|
// State overrides are applied prior to execution of a block
|
||||||
if err := block.StateOverrides.Apply(sim.state, precompiles); err != nil {
|
if err := block.StateOverrides.Apply(sim.state, precompiles); err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
gasUsed, blobGasUsed uint64
|
gp = core.NewGasPool(blockContext.GasLimit)
|
||||||
txes = make([]*types.Transaction, len(block.Calls))
|
blobGasUsed uint64
|
||||||
callResults = make([]simCallResult, len(block.Calls))
|
|
||||||
receipts = make([]*types.Receipt, len(block.Calls))
|
txes = make([]*types.Transaction, len(block.Calls))
|
||||||
|
callResults = make([]simCallResult, len(block.Calls))
|
||||||
|
receipts = make([]*types.Receipt, len(block.Calls))
|
||||||
|
|
||||||
// Block hash will be repaired after execution.
|
// Block hash will be repaired after execution.
|
||||||
tracer = newTracer(sim.traceTransfers, blockContext.BlockNumber.Uint64(), blockContext.Time, common.Hash{}, common.Hash{}, 0)
|
tracer = newTracer(sim.traceTransfers, blockContext.BlockNumber.Uint64(), blockContext.Time, common.Hash{}, common.Hash{}, 0)
|
||||||
vmConfig = &vm.Config{
|
vmConfig = &vm.Config{
|
||||||
|
|
@ -272,10 +282,11 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
||||||
}
|
}
|
||||||
var allLogs []*types.Log
|
var allLogs []*types.Log
|
||||||
for i, call := range block.Calls {
|
for i, call := range block.Calls {
|
||||||
|
// Terminate if the context is cancelled
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
if err := sim.sanitizeCall(&call, sim.state, header, blockContext, &gasUsed); err != nil {
|
if err := sim.sanitizeCall(&call, sim.state, header, gp); err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
|
|
@ -285,10 +296,11 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
||||||
txes[i] = tx
|
txes[i] = tx
|
||||||
senders[txHash] = call.from()
|
senders[txHash] = call.from()
|
||||||
tracer.reset(txHash, uint(i))
|
tracer.reset(txHash, uint(i))
|
||||||
sim.state.SetTxContext(txHash, i)
|
|
||||||
// EoA check is always skipped, even in validation mode.
|
// EoA check is always skipped, even in validation mode.
|
||||||
|
sim.state.SetTxContext(txHash, i)
|
||||||
msg := call.ToMessage(header.BaseFee, !sim.validate)
|
msg := call.ToMessage(header.BaseFee, !sim.validate)
|
||||||
result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp)
|
result, err := applyMessageWithEVM(ctx, evm, msg, timeout, gp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
txErr := txValidationError(err)
|
txErr := txValidationError(err)
|
||||||
return nil, nil, nil, txErr
|
return nil, nil, nil, txErr
|
||||||
|
|
@ -300,9 +312,16 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
||||||
} else {
|
} else {
|
||||||
root = sim.state.IntermediateRoot(sim.chainConfig.IsEIP158(blockContext.BlockNumber)).Bytes()
|
root = sim.state.IntermediateRoot(sim.chainConfig.IsEIP158(blockContext.BlockNumber)).Bytes()
|
||||||
}
|
}
|
||||||
gasUsed += result.UsedGas
|
receipts[i] = core.MakeReceipt(evm, result, sim.state, blockContext.BlockNumber, common.Hash{}, blockContext.Time, tx, gp.CumulativeUsed(), root)
|
||||||
receipts[i] = core.MakeReceipt(evm, result, sim.state, blockContext.BlockNumber, common.Hash{}, blockContext.Time, tx, gasUsed, root)
|
|
||||||
blobGasUsed += receipts[i].BlobGasUsed
|
blobGasUsed += receipts[i].BlobGasUsed
|
||||||
|
|
||||||
|
// Make sure the gas cap is still enforced. It's only for
|
||||||
|
// internally protection.
|
||||||
|
if sim.gasRemaining < result.UsedGas {
|
||||||
|
return nil, nil, nil, fmt.Errorf("gas cap reached, required: %d, remaining: %d", result.UsedGas, sim.gasRemaining)
|
||||||
|
}
|
||||||
|
sim.gasRemaining -= result.UsedGas
|
||||||
|
|
||||||
logs := tracer.Logs()
|
logs := tracer.Logs()
|
||||||
callRes := simCallResult{ReturnValue: result.Return(), Logs: logs, GasUsed: hexutil.Uint64(result.UsedGas)}
|
callRes := simCallResult{ReturnValue: result.Return(), Logs: logs, GasUsed: hexutil.Uint64(result.UsedGas)}
|
||||||
if result.Failed() {
|
if result.Failed() {
|
||||||
|
|
@ -320,12 +339,14 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
||||||
}
|
}
|
||||||
callResults[i] = callRes
|
callResults[i] = callRes
|
||||||
}
|
}
|
||||||
header.GasUsed = gasUsed
|
// Assign total consumed gas to the header
|
||||||
|
header.GasUsed = gp.Used()
|
||||||
if sim.chainConfig.IsCancun(header.Number, header.Time) {
|
if sim.chainConfig.IsCancun(header.Number, header.Time) {
|
||||||
header.BlobGasUsed = &blobGasUsed
|
header.BlobGasUsed = &blobGasUsed
|
||||||
}
|
}
|
||||||
var requests [][]byte
|
|
||||||
// Process EIP-7685 requests
|
// Process EIP-7685 requests
|
||||||
|
var requests [][]byte
|
||||||
if sim.chainConfig.IsPrague(header.Number, header.Time) {
|
if sim.chainConfig.IsPrague(header.Number, header.Time) {
|
||||||
requests = [][]byte{}
|
requests = [][]byte{}
|
||||||
// EIP-6110
|
// EIP-6110
|
||||||
|
|
@ -345,7 +366,11 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
||||||
reqHash := types.CalcRequestsHash(requests)
|
reqHash := types.CalcRequestsHash(requests)
|
||||||
header.RequestsHash = &reqHash
|
header.RequestsHash = &reqHash
|
||||||
}
|
}
|
||||||
blockBody := &types.Body{Transactions: txes, Withdrawals: *block.BlockOverrides.Withdrawals}
|
|
||||||
|
blockBody := &types.Body{
|
||||||
|
Transactions: txes,
|
||||||
|
Withdrawals: *block.BlockOverrides.Withdrawals,
|
||||||
|
}
|
||||||
chainHeadReader := &simChainHeadReader{ctx, sim.b}
|
chainHeadReader := &simChainHeadReader{ctx, sim.b}
|
||||||
b, err := sim.b.Engine().FinalizeAndAssemble(chainHeadReader, header, sim.state, blockBody, receipts)
|
b, err := sim.b.Engine().FinalizeAndAssemble(chainHeadReader, header, sim.state, blockBody, receipts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -366,23 +391,20 @@ func repairLogs(calls []simCallResult, hash common.Hash) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sim *simulator) sanitizeCall(call *TransactionArgs, state vm.StateDB, header *types.Header, blockContext vm.BlockContext, gasUsed *uint64) error {
|
func (sim *simulator) sanitizeCall(call *TransactionArgs, state vm.StateDB, header *types.Header, gp *core.GasPool) error {
|
||||||
if call.Nonce == nil {
|
if call.Nonce == nil {
|
||||||
nonce := state.GetNonce(call.from())
|
nonce := state.GetNonce(call.from())
|
||||||
call.Nonce = (*hexutil.Uint64)(&nonce)
|
call.Nonce = (*hexutil.Uint64)(&nonce)
|
||||||
}
|
}
|
||||||
// Let the call run wild unless explicitly specified.
|
// Let the call run wild unless explicitly specified.
|
||||||
|
remaining := gp.Gas()
|
||||||
if call.Gas == nil {
|
if call.Gas == nil {
|
||||||
remaining := blockContext.GasLimit - *gasUsed
|
|
||||||
call.Gas = (*hexutil.Uint64)(&remaining)
|
call.Gas = (*hexutil.Uint64)(&remaining)
|
||||||
}
|
}
|
||||||
if *gasUsed+uint64(*call.Gas) > blockContext.GasLimit {
|
if remaining < uint64(*call.Gas) {
|
||||||
return &blockGasLimitReachedError{fmt.Sprintf("block gas limit reached: %d >= %d", *gasUsed, blockContext.GasLimit)}
|
return &blockGasLimitReachedError{fmt.Sprintf("block gas limit reached: remaining: %d, required: %d", remaining, *call.Gas)}
|
||||||
}
|
}
|
||||||
if err := call.CallDefaults(sim.gp.Gas(), header.BaseFee, sim.chainConfig.ChainID); err != nil {
|
return call.CallDefaults(0, header.BaseFee, sim.chainConfig.ChainID)
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sim *simulator) activePrecompiles(base *types.Header) vm.PrecompiledContracts {
|
func (sim *simulator) activePrecompiles(base *types.Header) vm.PrecompiledContracts {
|
||||||
|
|
@ -473,12 +495,14 @@ func (sim *simulator) makeHeaders(blocks []simBlock) ([]*types.Header, error) {
|
||||||
}
|
}
|
||||||
overrides := block.BlockOverrides
|
overrides := block.BlockOverrides
|
||||||
|
|
||||||
var withdrawalsHash *common.Hash
|
|
||||||
number := overrides.Number.ToInt()
|
number := overrides.Number.ToInt()
|
||||||
timestamp := (uint64)(*overrides.Time)
|
timestamp := (uint64)(*overrides.Time)
|
||||||
|
|
||||||
|
var withdrawalsHash *common.Hash
|
||||||
if sim.chainConfig.IsShanghai(number, timestamp) {
|
if sim.chainConfig.IsShanghai(number, timestamp) {
|
||||||
withdrawalsHash = &types.EmptyWithdrawalsHash
|
withdrawalsHash = &types.EmptyWithdrawalsHash
|
||||||
}
|
}
|
||||||
|
|
||||||
var parentBeaconRoot *common.Hash
|
var parentBeaconRoot *common.Hash
|
||||||
if sim.chainConfig.IsCancun(number, timestamp) {
|
if sim.chainConfig.IsCancun(number, timestamp) {
|
||||||
parentBeaconRoot = &common.Hash{}
|
parentBeaconRoot = &common.Hash{}
|
||||||
|
|
@ -508,7 +532,11 @@ func (sim *simulator) makeHeaders(blocks []simBlock) ([]*types.Header, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sim *simulator) newSimulatedChainContext(ctx context.Context, headers []*types.Header) *ChainContext {
|
func (sim *simulator) newSimulatedChainContext(ctx context.Context, headers []*types.Header) *ChainContext {
|
||||||
return NewChainContext(ctx, &simBackend{base: sim.base, b: sim.b, headers: headers})
|
return NewChainContext(ctx, &simBackend{
|
||||||
|
base: sim.base,
|
||||||
|
b: sim.b,
|
||||||
|
headers: headers,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type simBackend struct {
|
type simBackend struct {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package ethapi
|
package ethapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -80,7 +81,10 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) {
|
||||||
err: "block timestamps must be in order: 72 <= 72",
|
err: "block timestamps must be in order: 72 <= 72",
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
sim := &simulator{base: &types.Header{Number: big.NewInt(int64(tc.baseNumber)), Time: tc.baseTimestamp}}
|
sim := &simulator{
|
||||||
|
base: &types.Header{Number: big.NewInt(int64(tc.baseNumber)), Time: tc.baseTimestamp},
|
||||||
|
gasRemaining: math.MaxUint64,
|
||||||
|
}
|
||||||
res, err := sim.sanitizeChain(tc.blocks)
|
res, err := sim.sanitizeChain(tc.blocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == tc.err {
|
if err.Error() == tc.err {
|
||||||
|
|
|
||||||
|
|
@ -56,14 +56,13 @@ func (miner *Miner) maxBlobsPerBlock(time uint64) int {
|
||||||
// environment is the worker's current environment and holds all
|
// environment is the worker's current environment and holds all
|
||||||
// information of the sealing block generation.
|
// information of the sealing block generation.
|
||||||
type environment struct {
|
type environment struct {
|
||||||
signer types.Signer
|
signer types.Signer
|
||||||
state *state.StateDB // apply state changes here
|
state *state.StateDB // apply state changes here
|
||||||
tcount int // tx count in cycle
|
tcount int // tx count in cycle
|
||||||
size uint64 // size of the block we are building
|
size uint64 // size of the block we are building
|
||||||
gasPool *core.GasPool // available gas used to pack transactions
|
gasPool *core.GasPool // available gas used to pack transactions
|
||||||
coinbase common.Address
|
coinbase common.Address
|
||||||
evm *vm.EVM
|
evm *vm.EVM
|
||||||
cumulativeGas uint64
|
|
||||||
|
|
||||||
header *types.Header
|
header *types.Header
|
||||||
txs []*types.Transaction
|
txs []*types.Transaction
|
||||||
|
|
@ -320,6 +319,7 @@ func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase
|
||||||
state: state,
|
state: state,
|
||||||
size: uint64(header.Size()),
|
size: uint64(header.Size()),
|
||||||
coinbase: coinbase,
|
coinbase: coinbase,
|
||||||
|
gasPool: core.NewGasPool(header.GasLimit),
|
||||||
header: header,
|
header: header,
|
||||||
witness: state.Witness(),
|
witness: state.Witness(),
|
||||||
evm: vm.NewEVM(core.NewEVMBlockContext(header, miner.chain, &coinbase), state, miner.chainConfig, vm.Config{}),
|
evm: vm.NewEVM(core.NewEVMBlockContext(header, miner.chain, &coinbase), state, miner.chainConfig, vm.Config{}),
|
||||||
|
|
@ -373,27 +373,20 @@ func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transactio
|
||||||
func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*types.Receipt, error) {
|
func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*types.Receipt, error) {
|
||||||
var (
|
var (
|
||||||
snap = env.state.Snapshot()
|
snap = env.state.Snapshot()
|
||||||
gp = env.gasPool.Gas()
|
gp = env.gasPool.Snapshot()
|
||||||
)
|
)
|
||||||
receipt, cumulativeGas, err := core.ApplyTransaction(env.evm, env.gasPool, env.state, env.header, tx, env.cumulativeGas)
|
receipt, err := core.ApplyTransaction(env.evm, env.gasPool, env.state, env.header, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
env.state.RevertToSnapshot(snap)
|
env.state.RevertToSnapshot(snap)
|
||||||
env.gasPool.SetGas(gp)
|
env.gasPool.Set(gp)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
env.cumulativeGas = cumulativeGas
|
env.header.GasUsed = env.gasPool.Used()
|
||||||
env.header.GasUsed += receipt.GasUsed
|
|
||||||
return receipt, nil
|
return receipt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
|
func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
|
||||||
var (
|
isCancun := miner.chainConfig.IsCancun(env.header.Number, env.header.Time)
|
||||||
isCancun = miner.chainConfig.IsCancun(env.header.Number, env.header.Time)
|
|
||||||
gasLimit = env.header.GasLimit
|
|
||||||
)
|
|
||||||
if env.gasPool == nil {
|
|
||||||
env.gasPool = new(core.GasPool).AddGas(gasLimit)
|
|
||||||
}
|
|
||||||
for {
|
for {
|
||||||
// Check interruption signal and abort building if it's fired.
|
// Check interruption signal and abort building if it's fired.
|
||||||
if interrupt != nil {
|
if interrupt != nil {
|
||||||
|
|
|
||||||
|
|
@ -342,9 +342,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
||||||
}
|
}
|
||||||
// Execute the message.
|
// Execute the message.
|
||||||
snapshot := st.StateDB.Snapshot()
|
snapshot := st.StateDB.Snapshot()
|
||||||
gaspool := new(core.GasPool)
|
vmRet, err := core.ApplyMessage(evm, msg, core.NewGasPool(block.GasLimit()))
|
||||||
gaspool.AddGas(block.GasLimit())
|
|
||||||
vmRet, err := core.ApplyMessage(evm, msg, gaspool)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
st.StateDB.RevertToSnapshot(snapshot)
|
st.StateDB.RevertToSnapshot(snapshot)
|
||||||
if tracer := evm.Config.Tracer; tracer != nil && tracer.OnTxEnd != nil {
|
if tracer := evm.Config.Tracer; tracer != nil && tracer.OnTxEnd != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue