mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-10 22:13:47 +00:00
Full OnGasConsumed loop and added GasChangeReason
With this change, the full gas loop of a transaction can be tracked going from initial balance (`gasLimit`) back down to 0. I validated on my regression test suite that those conditions applied to all transactions I have: - First `OnGasConsumed` is always going from 0 -> `trx.gasLimit` - Last `OnGasConsumed` "new value" is always 0 - trx.gasLimit - last balance of last `OnGasConsumed` is equal to `trx.gasUsed` The addition of `reason` make it possible for a logger to filter out unwanted signal, for example one could want to drop all OpCode related gas change and only cares about "transaction" level. The reason is also a good thing for visibility and for creating powerful debug tools for Ethereum transaction execution. Also, I would like that we change the `OnGasConsumed` logic from `OnGasConsumed(actual, cost uint64, reason)` to `OnGasConsumed(old, new uint64, reason)`. With the new tracing I've done, we now have negative `cost` that needs to be passed around but the `cost` is `uint64` so it creates overflow. Everything works fine if you record the new/old value `gas-cost` as the final value goes back to a valid range. But it's weird for consumer that would log `cost` that it's `18127127187219...`. An alternative would be to accept a `int64` for the cost which is also valid, not full coverage theorically but I don't see why an operation would cost more than i64 max value. Maybe it make more sense than to have signature `OnGasConsumed(gas uint64, cost int64, reason)`, I'm fine with it also, I leave the decision to you.
This commit is contained in:
parent
00a19d3c57
commit
e0af166ffa
14 changed files with 141 additions and 20 deletions
|
|
@ -263,6 +263,11 @@ func (st *StateTransition) buyGas() error {
|
||||||
if err := st.gp.SubGas(st.msg.GasLimit); err != nil {
|
if err := st.gp.SubGas(st.msg.GasLimit); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if st.evm.Config.Tracer != nil {
|
||||||
|
st.evm.Config.Tracer.OnGasConsumed(0, -st.msg.GasLimit, vm.GasInitialBalance)
|
||||||
|
}
|
||||||
|
|
||||||
st.gasRemaining += st.msg.GasLimit
|
st.gasRemaining += st.msg.GasLimit
|
||||||
|
|
||||||
st.initialGas = st.msg.GasLimit
|
st.initialGas = st.msg.GasLimit
|
||||||
|
|
@ -386,7 +391,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
|
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
|
||||||
}
|
}
|
||||||
if t := st.evm.Config.Tracer; t != nil {
|
if t := st.evm.Config.Tracer; t != nil {
|
||||||
t.OnGasConsumed(st.gasRemaining, gas)
|
t.OnGasConsumed(st.gasRemaining, gas, vm.GasChangeIntrinsicGas)
|
||||||
}
|
}
|
||||||
st.gasRemaining -= gas
|
st.gasRemaining -= gas
|
||||||
|
|
||||||
|
|
@ -452,12 +457,21 @@ func (st *StateTransition) refundGas(refundQuotient uint64) {
|
||||||
if refund > st.state.GetRefund() {
|
if refund > st.state.GetRefund() {
|
||||||
refund = st.state.GetRefund()
|
refund = st.state.GetRefund()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if st.evm.Config.Tracer != nil {
|
||||||
|
st.evm.Config.Tracer.OnGasConsumed(st.gasRemaining, -refund, vm.GasRefunded)
|
||||||
|
}
|
||||||
|
|
||||||
st.gasRemaining += refund
|
st.gasRemaining += refund
|
||||||
|
|
||||||
// Return ETH for remaining gas, exchanged at the original rate.
|
// Return ETH for remaining gas, exchanged at the original rate.
|
||||||
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice)
|
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice)
|
||||||
st.state.AddBalance(st.msg.From, remaining, state.BalanceChangeGasRefund)
|
st.state.AddBalance(st.msg.From, remaining, state.BalanceChangeGasRefund)
|
||||||
|
|
||||||
|
if st.evm.Config.Tracer != nil {
|
||||||
|
st.evm.Config.Tracer.OnGasConsumed(st.gasRemaining, st.gasRemaining, vm.GasBuyBack)
|
||||||
|
}
|
||||||
|
|
||||||
// Also return remaining gas to the block gas counter so it is
|
// Also return remaining gas to the block gas counter so it is
|
||||||
// available for the next transaction.
|
// available for the next transaction.
|
||||||
st.gp.AddGas(st.gasRemaining)
|
st.gp.AddGas(st.gasRemaining)
|
||||||
|
|
|
||||||
|
|
@ -159,12 +159,12 @@ func (c *Contract) Caller() common.Address {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UseGas attempts the use gas and subtracts it and returns true on success
|
// UseGas attempts the use gas and subtracts it and returns true on success
|
||||||
func (c *Contract) UseGas(gas uint64, logger EVMLogger) (ok bool) {
|
func (c *Contract) UseGas(gas uint64, logger EVMLogger, reason GasChangeReason) (ok bool) {
|
||||||
if c.Gas < gas {
|
if c.Gas < gas {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if logger != nil {
|
if logger != nil {
|
||||||
logger.OnGasConsumed(c.Gas, gas)
|
logger.OnGasConsumed(c.Gas, gas, reason)
|
||||||
}
|
}
|
||||||
c.Gas -= gas
|
c.Gas -= gas
|
||||||
return true
|
return true
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uin
|
||||||
return nil, 0, ErrOutOfGas
|
return nil, 0, ErrOutOfGas
|
||||||
}
|
}
|
||||||
if logger != nil {
|
if logger != nil {
|
||||||
logger.OnGasConsumed(suppliedGas, gasCost)
|
logger.OnGasConsumed(suppliedGas, gasCost, GasChangePrecompiledContract)
|
||||||
}
|
}
|
||||||
suppliedGas -= gasCost
|
suppliedGas -= gasCost
|
||||||
output, err := p.Run(input)
|
output, err := p.Run(input)
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||||
} else {
|
} else {
|
||||||
// Handle tracer events for entering and exiting a call frame
|
// Handle tracer events for entering and exiting a call frame
|
||||||
evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
|
evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
|
||||||
|
evm.Config.Tracer.OnGasConsumed(0, -gas, GasInitialBalance)
|
||||||
defer func(startGas uint64) {
|
defer func(startGas uint64) {
|
||||||
|
evm.Config.Tracer.OnGasConsumed(leftOverGas, leftOverGas, GasBuyBack)
|
||||||
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||||
}(gas)
|
}(gas)
|
||||||
}
|
}
|
||||||
|
|
@ -233,6 +235,10 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||||
if err != nil {
|
if err != nil {
|
||||||
evm.StateDB.RevertToSnapshot(snapshot)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
if err != ErrExecutionReverted {
|
if err != ErrExecutionReverted {
|
||||||
|
if evm.Config.Tracer != nil {
|
||||||
|
evm.Config.Tracer.OnGasConsumed(gas, gas, GasChangeFailedExecution)
|
||||||
|
}
|
||||||
|
|
||||||
gas = 0
|
gas = 0
|
||||||
}
|
}
|
||||||
// TODO: consider clearing up unused snapshots:
|
// TODO: consider clearing up unused snapshots:
|
||||||
|
|
@ -253,7 +259,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
||||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||||
if evm.Config.Tracer != nil {
|
if evm.Config.Tracer != nil {
|
||||||
evm.Config.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value)
|
evm.Config.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value)
|
||||||
|
evm.Config.Tracer.OnGasConsumed(0, -gas, GasInitialBalance)
|
||||||
defer func(startGas uint64) {
|
defer func(startGas uint64) {
|
||||||
|
evm.Config.Tracer.OnGasConsumed(leftOverGas, leftOverGas, GasBuyBack)
|
||||||
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||||
}(gas)
|
}(gas)
|
||||||
}
|
}
|
||||||
|
|
@ -285,6 +293,10 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
evm.StateDB.RevertToSnapshot(snapshot)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
if err != ErrExecutionReverted {
|
if err != ErrExecutionReverted {
|
||||||
|
if evm.Config.Tracer != nil {
|
||||||
|
evm.Config.Tracer.OnGasConsumed(gas, gas, GasChangeFailedExecution)
|
||||||
|
}
|
||||||
|
|
||||||
gas = 0
|
gas = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -304,7 +316,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
||||||
parent := caller.(*Contract)
|
parent := caller.(*Contract)
|
||||||
// DELEGATECALL inherits value from parent call
|
// DELEGATECALL inherits value from parent call
|
||||||
evm.Config.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, parent.value)
|
evm.Config.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, parent.value)
|
||||||
|
evm.Config.Tracer.OnGasConsumed(0, -gas, GasInitialBalance)
|
||||||
defer func(startGas uint64) {
|
defer func(startGas uint64) {
|
||||||
|
evm.Config.Tracer.OnGasConsumed(leftOverGas, leftOverGas, GasBuyBack)
|
||||||
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||||
}(gas)
|
}(gas)
|
||||||
}
|
}
|
||||||
|
|
@ -328,6 +342,10 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
||||||
if err != nil {
|
if err != nil {
|
||||||
evm.StateDB.RevertToSnapshot(snapshot)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
if err != ErrExecutionReverted {
|
if err != ErrExecutionReverted {
|
||||||
|
if evm.Config.Tracer != nil {
|
||||||
|
evm.Config.Tracer.OnGasConsumed(gas, gas, GasChangeFailedExecution)
|
||||||
|
}
|
||||||
|
|
||||||
gas = 0
|
gas = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -342,7 +360,9 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
||||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||||
if evm.Config.Tracer != nil {
|
if evm.Config.Tracer != nil {
|
||||||
evm.Config.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil)
|
evm.Config.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil)
|
||||||
|
evm.Config.Tracer.OnGasConsumed(0, -gas, GasInitialBalance)
|
||||||
defer func(startGas uint64) {
|
defer func(startGas uint64) {
|
||||||
|
evm.Config.Tracer.OnGasConsumed(leftOverGas, leftOverGas, GasBuyBack)
|
||||||
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||||
}(gas)
|
}(gas)
|
||||||
}
|
}
|
||||||
|
|
@ -383,6 +403,10 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
||||||
if err != nil {
|
if err != nil {
|
||||||
evm.StateDB.RevertToSnapshot(snapshot)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
if err != ErrExecutionReverted {
|
if err != ErrExecutionReverted {
|
||||||
|
if evm.Config.Tracer != nil {
|
||||||
|
evm.Config.Tracer.OnGasConsumed(gas, gas, GasChangeFailedExecution)
|
||||||
|
}
|
||||||
|
|
||||||
gas = 0
|
gas = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -411,7 +435,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
}()
|
}()
|
||||||
} else {
|
} else {
|
||||||
evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value)
|
evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value)
|
||||||
|
evm.Config.Tracer.OnGasConsumed(0, -gas, GasInitialBalance)
|
||||||
defer func() {
|
defer func() {
|
||||||
|
evm.Config.Tracer.OnGasConsumed(leftoverGas, leftoverGas, GasBuyBack)
|
||||||
evm.Config.Tracer.CaptureExit(ret, gas-leftoverGas, err)
|
evm.Config.Tracer.CaptureExit(ret, gas-leftoverGas, err)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
@ -437,6 +463,10 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
// Ensure there's no existing contract already at the designated address
|
// Ensure there's no existing contract already at the designated address
|
||||||
contractHash := evm.StateDB.GetCodeHash(address)
|
contractHash := evm.StateDB.GetCodeHash(address)
|
||||||
if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) {
|
if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) {
|
||||||
|
if evm.Config.Tracer != nil {
|
||||||
|
evm.Config.Tracer.OnGasConsumed(gas, gas, GasChangeFailedExecution)
|
||||||
|
}
|
||||||
|
|
||||||
return nil, common.Address{}, 0, ErrContractAddressCollision
|
return nil, common.Address{}, 0, ErrContractAddressCollision
|
||||||
}
|
}
|
||||||
// Create a new account on the state
|
// Create a new account on the state
|
||||||
|
|
@ -470,7 +500,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
// by the error checking condition below.
|
// by the error checking condition below.
|
||||||
if err == nil {
|
if err == nil {
|
||||||
createDataGas := uint64(len(ret)) * params.CreateDataGas
|
createDataGas := uint64(len(ret)) * params.CreateDataGas
|
||||||
if contract.UseGas(createDataGas, evm.Config.Tracer) {
|
if contract.UseGas(createDataGas, evm.Config.Tracer, GasChangeCodeStorage) {
|
||||||
evm.StateDB.SetCode(address, ret)
|
evm.StateDB.SetCode(address, ret)
|
||||||
} else {
|
} else {
|
||||||
err = ErrCodeStoreOutOfGas
|
err = ErrCodeStoreOutOfGas
|
||||||
|
|
@ -483,7 +513,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) {
|
if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) {
|
||||||
evm.StateDB.RevertToSnapshot(snapshot)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
if err != ErrExecutionReverted {
|
if err != ErrExecutionReverted {
|
||||||
contract.UseGas(contract.Gas, evm.Config.Tracer)
|
contract.UseGas(contract.Gas, evm.Config.Tracer, GasChangeFailedExecution)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -592,7 +592,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
||||||
// reuse size int for stackvalue
|
// reuse size int for stackvalue
|
||||||
stackvalue := size
|
stackvalue := size
|
||||||
|
|
||||||
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer)
|
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, GasChangeContractCreation)
|
||||||
//TODO: use uint256.Int instead of converting with toBig()
|
//TODO: use uint256.Int instead of converting with toBig()
|
||||||
var bigVal = big0
|
var bigVal = big0
|
||||||
if !value.IsZero() {
|
if !value.IsZero() {
|
||||||
|
|
@ -612,6 +612,11 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
||||||
stackvalue.SetBytes(addr.Bytes())
|
stackvalue.SetBytes(addr.Bytes())
|
||||||
}
|
}
|
||||||
scope.Stack.push(&stackvalue)
|
scope.Stack.push(&stackvalue)
|
||||||
|
|
||||||
|
if interpreter.evm.Config.Tracer != nil {
|
||||||
|
interpreter.evm.Config.Tracer.OnGasConsumed(scope.Contract.Gas, -returnGas, GasChangeCallLeftOverRefunded)
|
||||||
|
}
|
||||||
|
|
||||||
scope.Contract.Gas += returnGas
|
scope.Contract.Gas += returnGas
|
||||||
|
|
||||||
if suberr == ErrExecutionReverted {
|
if suberr == ErrExecutionReverted {
|
||||||
|
|
@ -635,7 +640,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
|
||||||
)
|
)
|
||||||
// Apply EIP150
|
// Apply EIP150
|
||||||
gas -= gas / 64
|
gas -= gas / 64
|
||||||
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer)
|
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, GasChangeContractCreation2)
|
||||||
// reuse size int for stackvalue
|
// reuse size int for stackvalue
|
||||||
stackvalue := size
|
stackvalue := size
|
||||||
//TODO: use uint256.Int instead of converting with toBig()
|
//TODO: use uint256.Int instead of converting with toBig()
|
||||||
|
|
@ -652,6 +657,11 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
|
||||||
stackvalue.SetBytes(addr.Bytes())
|
stackvalue.SetBytes(addr.Bytes())
|
||||||
}
|
}
|
||||||
scope.Stack.push(&stackvalue)
|
scope.Stack.push(&stackvalue)
|
||||||
|
|
||||||
|
if interpreter.evm.Config.Tracer != nil {
|
||||||
|
interpreter.evm.Config.Tracer.OnGasConsumed(scope.Contract.Gas, -returnGas, GasChangeCallLeftOverRefunded)
|
||||||
|
}
|
||||||
|
|
||||||
scope.Contract.Gas += returnGas
|
scope.Contract.Gas += returnGas
|
||||||
|
|
||||||
if suberr == ErrExecutionReverted {
|
if suberr == ErrExecutionReverted {
|
||||||
|
|
@ -697,6 +707,11 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
|
||||||
if err == nil || err == ErrExecutionReverted {
|
if err == nil || err == ErrExecutionReverted {
|
||||||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if interpreter.evm.Config.Tracer != nil {
|
||||||
|
interpreter.evm.Config.Tracer.OnGasConsumed(scope.Contract.Gas, -returnGas, GasChangeCallLeftOverRefunded)
|
||||||
|
}
|
||||||
|
|
||||||
scope.Contract.Gas += returnGas
|
scope.Contract.Gas += returnGas
|
||||||
|
|
||||||
interpreter.returnData = ret
|
interpreter.returnData = ret
|
||||||
|
|
@ -732,6 +747,11 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
||||||
if err == nil || err == ErrExecutionReverted {
|
if err == nil || err == ErrExecutionReverted {
|
||||||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if interpreter.evm.Config.Tracer != nil {
|
||||||
|
interpreter.evm.Config.Tracer.OnGasConsumed(scope.Contract.Gas, -returnGas, GasChangeCallLeftOverRefunded)
|
||||||
|
}
|
||||||
|
|
||||||
scope.Contract.Gas += returnGas
|
scope.Contract.Gas += returnGas
|
||||||
|
|
||||||
interpreter.returnData = ret
|
interpreter.returnData = ret
|
||||||
|
|
@ -760,6 +780,11 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
||||||
if err == nil || err == ErrExecutionReverted {
|
if err == nil || err == ErrExecutionReverted {
|
||||||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if interpreter.evm.Config.Tracer != nil {
|
||||||
|
interpreter.evm.Config.Tracer.OnGasConsumed(scope.Contract.Gas, -returnGas, GasChangeCallLeftOverRefunded)
|
||||||
|
}
|
||||||
|
|
||||||
scope.Contract.Gas += returnGas
|
scope.Contract.Gas += returnGas
|
||||||
|
|
||||||
interpreter.returnData = ret
|
interpreter.returnData = ret
|
||||||
|
|
@ -788,6 +813,11 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
||||||
if err == nil || err == ErrExecutionReverted {
|
if err == nil || err == ErrExecutionReverted {
|
||||||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if interpreter.evm.Config.Tracer != nil {
|
||||||
|
interpreter.evm.Config.Tracer.OnGasConsumed(scope.Contract.Gas, -returnGas, GasChangeCallLeftOverRefunded)
|
||||||
|
}
|
||||||
|
|
||||||
scope.Contract.Gas += returnGas
|
scope.Contract.Gas += returnGas
|
||||||
|
|
||||||
interpreter.returnData = ret
|
interpreter.returnData = ret
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
} else if sLen > operation.maxStack {
|
} else if sLen > operation.maxStack {
|
||||||
return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack}
|
return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack}
|
||||||
}
|
}
|
||||||
if !contract.UseGas(cost, in.evm.Config.Tracer) {
|
if !contract.UseGas(cost, in.evm.Config.Tracer, GasChangeOpCode) {
|
||||||
return nil, ErrOutOfGas
|
return nil, ErrOutOfGas
|
||||||
}
|
}
|
||||||
if operation.dynamicGas != nil {
|
if operation.dynamicGas != nil {
|
||||||
|
|
@ -211,7 +211,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
var dynamicCost uint64
|
var dynamicCost uint64
|
||||||
dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize)
|
dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize)
|
||||||
cost += dynamicCost // for tracing
|
cost += dynamicCost // for tracing
|
||||||
if err != nil || !contract.UseGas(dynamicCost, in.evm.Config.Tracer) {
|
if err != nil || !contract.UseGas(dynamicCost, in.evm.Config.Tracer, GasChangeOpCode) {
|
||||||
return nil, ErrOutOfGas
|
return nil, ErrOutOfGas
|
||||||
}
|
}
|
||||||
// Do tracing before memory expansion
|
// Do tracing before memory expansion
|
||||||
|
|
|
||||||
|
|
@ -43,5 +43,52 @@ type EVMLogger interface {
|
||||||
CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error)
|
CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error)
|
||||||
CaptureKeccakPreimage(hash common.Hash, data []byte)
|
CaptureKeccakPreimage(hash common.Hash, data []byte)
|
||||||
// Misc
|
// Misc
|
||||||
OnGasConsumed(gas, amount uint64)
|
OnGasConsumed(gas, amount uint64, reason GasChangeReason)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GasChangeReason is used to indicate the reason for a gas change, useful
|
||||||
|
// for tracing and reporting.
|
||||||
|
type GasChangeReason byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
GasChangeUnspecified GasChangeReason = iota
|
||||||
|
|
||||||
|
// GasInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call
|
||||||
|
GasInitialBalance
|
||||||
|
// GasRefunded is the amount of gas that will be refunded to the caller for data returned to the chain
|
||||||
|
// PR Review: Is that the right description? Called in core/state_transition.go#StateTransition.refundGas
|
||||||
|
GasRefunded
|
||||||
|
// GasBuyBack is the amount of gas that will be bought back by the chain and returned in Wei to the caller
|
||||||
|
GasBuyBack
|
||||||
|
// GasChangeIntrinsicGas is the amount of gas that will be charged for the intrinsic cost of the transaction, there is
|
||||||
|
// always exactly one of those per transaction
|
||||||
|
GasChangeIntrinsicGas
|
||||||
|
|
||||||
|
// PR Review: `GasChangeContractCreation/2` are actually the EIP150 burn cost of CREATE/CREATE2 respectively.
|
||||||
|
// I think our old name `GasChangeContractCreation/2` is not really accurate. I don't
|
||||||
|
// think that using EIP150 as a name is a good idea as rules can change in the future. So
|
||||||
|
// maybe we can just call them `GasChangeCreateBurn/GasChangeCreate2Burn`? Burn might
|
||||||
|
// feels like the wrong term, `Stipend` came to mind also but I'm unsure.
|
||||||
|
//
|
||||||
|
// I would like also to keep the distinction between CREATE and CREATE2 however, it's an
|
||||||
|
// important thing IMO as they are different and could use different rules in the future.
|
||||||
|
|
||||||
|
// GasChangeContractCreation is the amount of gas that will be burned for a CREATE, today controlled by EIP150 rules
|
||||||
|
GasChangeContractCreation
|
||||||
|
// GasChangeContractCreation is the amount of gas that will be burned for a CREATE2, today controlled by EIP150 rules
|
||||||
|
GasChangeContractCreation2
|
||||||
|
// GasChangeCodeStorage is the amount of gas that will be charged for code storage
|
||||||
|
GasChangeCodeStorage
|
||||||
|
// GasChangeOpCode is the amount of gas that will be charged for an opcode executed by the EVM, exact opcode that was
|
||||||
|
// performed can be check by `CaptureState` handling
|
||||||
|
GasChangeOpCode
|
||||||
|
// GasChangePrecompiledContract is the amount of gas that will be charged for a precompiled contract execution
|
||||||
|
GasChangePrecompiledContract
|
||||||
|
// GasChangeStorageColdAccess is the amount of gas that will be charged for a cold storage access as controlled by EIP2929 rules
|
||||||
|
GasChangeStorageColdAccess
|
||||||
|
|
||||||
|
// GasChangeCallLeftOverRefunded is the amount of gas that will be refunded to the caller after the execution of the call, if there is left over at the end of execution
|
||||||
|
GasChangeCallLeftOverRefunded
|
||||||
|
// GasChangeFailedExecution is the burning of the remaining gas when the execution failed without a revert
|
||||||
|
GasChangeFailedExecution
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc) gasFunc {
|
||||||
evm.StateDB.AddAddressToAccessList(addr)
|
evm.StateDB.AddAddressToAccessList(addr)
|
||||||
// Charge the remaining difference here already, to correctly calculate available
|
// Charge the remaining difference here already, to correctly calculate available
|
||||||
// gas for call
|
// gas for call
|
||||||
if !contract.UseGas(coldCost, evm.Config.Tracer) {
|
if !contract.UseGas(coldCost, evm.Config.Tracer, GasChangeStorageColdAccess) {
|
||||||
return 0, ErrOutOfGas
|
return 0, ErrOutOfGas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ func (*AccessListTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64,
|
||||||
|
|
||||||
func (*AccessListTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
|
func (*AccessListTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
|
||||||
|
|
||||||
func (*AccessListTracer) OnGasConsumed(gas, amount uint64) {}
|
func (*AccessListTracer) OnGasConsumed(gas, amount uint64, reason vm.GasChangeReason) {}
|
||||||
|
|
||||||
func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {}
|
func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ func (l *StructLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, s
|
||||||
// CaptureKeccakPreimage is called during the KECCAK256 opcode.
|
// CaptureKeccakPreimage is called during the KECCAK256 opcode.
|
||||||
func (l *StructLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
|
func (l *StructLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
|
||||||
|
|
||||||
func (l *StructLogger) OnGasConsumed(gas, amount uint64) {}
|
func (l *StructLogger) OnGasConsumed(gas, amount uint64, reason vm.GasChangeReason) {}
|
||||||
|
|
||||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||||
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
||||||
|
|
@ -410,7 +410,7 @@ func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope
|
||||||
|
|
||||||
func (t *mdLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
|
func (t *mdLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
|
||||||
|
|
||||||
func (t *mdLogger) OnGasConsumed(gas, amount uint64) {}
|
func (t *mdLogger) OnGasConsumed(gas, amount uint64, reason vm.GasChangeReason) {}
|
||||||
|
|
||||||
func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
||||||
fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n",
|
fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n",
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco
|
||||||
// CaptureKeccakPreimage is called during the KECCAK256 opcode.
|
// CaptureKeccakPreimage is called during the KECCAK256 opcode.
|
||||||
func (l *JSONLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
|
func (l *JSONLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
|
||||||
|
|
||||||
func (l *JSONLogger) OnGasConsumed(gas, amount uint64) {}
|
func (l *JSONLogger) OnGasConsumed(gas, amount uint64, reason vm.GasChangeReason) {}
|
||||||
|
|
||||||
// CaptureEnd is triggered at end of execution.
|
// CaptureEnd is triggered at end of execution.
|
||||||
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
||||||
|
|
|
||||||
|
|
@ -96,9 +96,9 @@ func (t *muxTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureGasConsumed is called when gas is consumed.
|
// CaptureGasConsumed is called when gas is consumed.
|
||||||
func (t *muxTracer) OnGasConsumed(gas, amount uint64) {
|
func (t *muxTracer) OnGasConsumed(gas, amount uint64, reason vm.GasChangeReason) {
|
||||||
for _, t := range t.tracers {
|
for _, t := range t.tracers {
|
||||||
t.OnGasConsumed(gas, amount)
|
t.OnGasConsumed(gas, amount, reason)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ func (t *NoopTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *
|
||||||
func (t *NoopTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
|
func (t *NoopTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
|
||||||
|
|
||||||
// OnGasConsumed is called when gas is consumed.
|
// OnGasConsumed is called when gas is consumed.
|
||||||
func (t *NoopTracer) OnGasConsumed(gas, amount uint64) {}
|
func (t *NoopTracer) OnGasConsumed(gas, amount uint64, reason vm.GasChangeReason) {}
|
||||||
|
|
||||||
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
|
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
|
||||||
func (t *NoopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
func (t *NoopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,6 @@ func (p *Printer) OnNewAccount(a common.Address) {
|
||||||
fmt.Printf("OnNewAccount: a=%v\n", a)
|
fmt.Printf("OnNewAccount: a=%v\n", a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Printer) OnGasConsumed(gas, amount uint64) {
|
func (p *Printer) OnGasConsumed(gas, amount uint64, reason vm.GasChangeReason) {
|
||||||
fmt.Printf("OnGasConsumed: gas=%v, amount=%v\n", gas, amount)
|
fmt.Printf("OnGasConsumed: gas=%v, amount=%v\n", gas, amount)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue