mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-10 22:13:47 +00:00
add gas consumption hook
This commit is contained in:
parent
84d6432708
commit
ee791b2b20
20 changed files with 73 additions and 42 deletions
|
|
@ -348,6 +348,9 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
if st.gasRemaining < gas {
|
if st.gasRemaining < gas {
|
||||||
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 {
|
||||||
|
t.OnGasConsumed(st.gasRemaining, gas)
|
||||||
|
}
|
||||||
st.gasRemaining -= gas
|
st.gasRemaining -= gas
|
||||||
|
|
||||||
// Check clause 6
|
// Check clause 6
|
||||||
|
|
|
||||||
|
|
@ -159,10 +159,13 @@ 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) (ok bool) {
|
func (c *Contract) UseGas(gas uint64, logger EVMLogger) (ok bool) {
|
||||||
if c.Gas < gas {
|
if c.Gas < gas {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if logger != nil {
|
||||||
|
logger.OnGasConsumed(c.Gas, gas)
|
||||||
|
}
|
||||||
c.Gas -= gas
|
c.Gas -= gas
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -168,11 +168,14 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
|
||||||
// - the returned bytes,
|
// - the returned bytes,
|
||||||
// - the _remaining_ gas,
|
// - the _remaining_ gas,
|
||||||
// - any error that occurred
|
// - any error that occurred
|
||||||
func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) {
|
func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger EVMLogger) (ret []byte, remainingGas uint64, err error) {
|
||||||
gasCost := p.RequiredGas(input)
|
gasCost := p.RequiredGas(input)
|
||||||
if suppliedGas < gasCost {
|
if suppliedGas < gasCost {
|
||||||
return nil, 0, ErrOutOfGas
|
return nil, 0, ErrOutOfGas
|
||||||
}
|
}
|
||||||
|
if logger != nil {
|
||||||
|
logger.OnGasConsumed(suppliedGas, gasCost)
|
||||||
|
}
|
||||||
suppliedGas -= gasCost
|
suppliedGas -= gasCost
|
||||||
output, err := p.Run(input)
|
output, err := p.Run(input)
|
||||||
return output, suppliedGas, err
|
return output, suppliedGas, err
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
|
||||||
in := common.Hex2Bytes(test.Input)
|
in := common.Hex2Bytes(test.Input)
|
||||||
gas := p.RequiredGas(in)
|
gas := p.RequiredGas(in)
|
||||||
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
|
||||||
if res, _, err := RunPrecompiledContract(p, in, gas); err != nil {
|
if res, _, err := RunPrecompiledContract(p, in, gas, nil); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
} else if common.Bytes2Hex(res) != test.Expected {
|
} else if common.Bytes2Hex(res) != test.Expected {
|
||||||
t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res))
|
t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res))
|
||||||
|
|
@ -119,7 +119,7 @@ func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) {
|
||||||
gas := p.RequiredGas(in) - 1
|
gas := p.RequiredGas(in) - 1
|
||||||
|
|
||||||
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
|
||||||
_, _, err := RunPrecompiledContract(p, in, gas)
|
_, _, err := RunPrecompiledContract(p, in, gas, nil)
|
||||||
if err.Error() != "out of gas" {
|
if err.Error() != "out of gas" {
|
||||||
t.Errorf("Expected error [out of gas], got [%v]", err)
|
t.Errorf("Expected error [out of gas], got [%v]", err)
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +136,7 @@ func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing
|
||||||
in := common.Hex2Bytes(test.Input)
|
in := common.Hex2Bytes(test.Input)
|
||||||
gas := p.RequiredGas(in)
|
gas := p.RequiredGas(in)
|
||||||
t.Run(test.Name, func(t *testing.T) {
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
_, _, err := RunPrecompiledContract(p, in, gas)
|
_, _, err := RunPrecompiledContract(p, in, gas, nil)
|
||||||
if err.Error() != test.ExpectedError {
|
if err.Error() != test.ExpectedError {
|
||||||
t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err)
|
t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err)
|
||||||
}
|
}
|
||||||
|
|
@ -168,7 +168,7 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
|
||||||
bench.ResetTimer()
|
bench.ResetTimer()
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
copy(data, in)
|
copy(data, in)
|
||||||
res, _, err = RunPrecompiledContract(p, data, reqGas)
|
res, _, err = RunPrecompiledContract(p, data, reqGas, nil)
|
||||||
}
|
}
|
||||||
bench.StopTimer()
|
bench.StopTimer()
|
||||||
elapsed := uint64(time.Since(start))
|
elapsed := uint64(time.Since(start))
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||||
}
|
}
|
||||||
|
|
||||||
if isPrecompile {
|
if isPrecompile {
|
||||||
ret, gas, err = RunPrecompiledContract(p, input, gas)
|
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
|
||||||
} else {
|
} else {
|
||||||
// Initialise a new contract and set the code that is to be used by the EVM.
|
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||||
// The contract is a scoped environment for this execution context only.
|
// The contract is a scoped environment for this execution context only.
|
||||||
|
|
@ -285,7 +285,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
||||||
|
|
||||||
// It is allowed to call precompiles, even via delegatecall
|
// It is allowed to call precompiles, even via delegatecall
|
||||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||||
ret, gas, err = RunPrecompiledContract(p, input, gas)
|
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
|
||||||
} else {
|
} else {
|
||||||
addrCopy := addr
|
addrCopy := addr
|
||||||
// Initialise a new contract and set the code that is to be used by the EVM.
|
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||||
|
|
@ -330,7 +330,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
||||||
|
|
||||||
// It is allowed to call precompiles, even via delegatecall
|
// It is allowed to call precompiles, even via delegatecall
|
||||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||||
ret, gas, err = RunPrecompiledContract(p, input, gas)
|
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
|
||||||
} else {
|
} else {
|
||||||
addrCopy := addr
|
addrCopy := addr
|
||||||
// Initialise a new contract and make initialise the delegate values
|
// Initialise a new contract and make initialise the delegate values
|
||||||
|
|
@ -379,7 +379,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||||
ret, gas, err = RunPrecompiledContract(p, input, gas)
|
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
|
||||||
} else {
|
} else {
|
||||||
// At this point, we use a copy of address. If we don't, the go compiler will
|
// At this point, we use a copy of address. If we don't, the go compiler will
|
||||||
// leak the 'contract' to the outer scope, and make allocation for 'contract'
|
// leak the 'contract' to the outer scope, and make allocation for 'contract'
|
||||||
|
|
@ -480,7 +480,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) {
|
if contract.UseGas(createDataGas, evm.Config.Tracer) {
|
||||||
evm.StateDB.SetCode(address, ret)
|
evm.StateDB.SetCode(address, ret)
|
||||||
} else {
|
} else {
|
||||||
err = ErrCodeStoreOutOfGas
|
err = ErrCodeStoreOutOfGas
|
||||||
|
|
@ -493,7 +493,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)
|
contract.UseGas(contract.Gas, evm.Config.Tracer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -591,7 +591,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)
|
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer)
|
||||||
//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() {
|
||||||
|
|
@ -634,7 +634,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
|
||||||
)
|
)
|
||||||
// Apply EIP150
|
// Apply EIP150
|
||||||
gas -= gas / 64
|
gas -= gas / 64
|
||||||
scope.Contract.UseGas(gas)
|
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer)
|
||||||
// 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()
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
if !contract.UseGas(cost, in.evm.Config.Tracer) {
|
||||||
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) {
|
if err != nil || !contract.UseGas(dynamicCost, in.evm.Config.Tracer) {
|
||||||
return nil, ErrOutOfGas
|
return nil, ErrOutOfGas
|
||||||
}
|
}
|
||||||
// Do tracing before memory expansion
|
// Do tracing before memory expansion
|
||||||
|
|
|
||||||
|
|
@ -41,4 +41,6 @@ type EVMLogger interface {
|
||||||
CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error)
|
CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error)
|
||||||
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
|
||||||
|
OnGasConsumed(gas, amount uint64)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
if !contract.UseGas(coldCost, evm.Config.Tracer) {
|
||||||
return 0, ErrOutOfGas
|
return 0, ErrOutOfGas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,8 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b
|
||||||
// jsTracer is an implementation of the Tracer interface which evaluates
|
// jsTracer is an implementation of the Tracer interface which evaluates
|
||||||
// JS functions on the relevant EVM hooks. It uses Goja as its JS engine.
|
// JS functions on the relevant EVM hooks. It uses Goja as its JS engine.
|
||||||
type jsTracer struct {
|
type jsTracer struct {
|
||||||
|
tracers.NoopTracer
|
||||||
|
|
||||||
vm *goja.Runtime
|
vm *goja.Runtime
|
||||||
env *vm.EVM
|
env *vm.EVM
|
||||||
toBig toBigFn // Converts a hex string into a JS bigint
|
toBig toBigFn // Converts a hex string into a JS bigint
|
||||||
|
|
@ -286,9 +288,6 @@ func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureKeccakPreimage is called during the KECCAK256 opcode.
|
|
||||||
func (t *jsTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
|
|
||||||
|
|
||||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||||
func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
||||||
t.ctx["output"] = t.vm.ToValue(output)
|
t.ctx["output"] = t.vm.ToValue(output)
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,8 @@ 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) CaptureEnd(output []byte, gasUsed uint64, err error) {}
|
func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {}
|
||||||
|
|
||||||
func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,8 @@ 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) {}
|
||||||
|
|
||||||
// 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) {
|
||||||
l.output = output
|
l.output = output
|
||||||
|
|
@ -389,6 +391,8 @@ 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) 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",
|
||||||
output, gasUsed, err)
|
output, gasUsed, err)
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,8 @@ 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) {}
|
||||||
|
|
||||||
// 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) {
|
||||||
type endLog struct {
|
type endLog struct {
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ func init() {
|
||||||
// 0xc281d19e-0: 1
|
// 0xc281d19e-0: 1
|
||||||
// }
|
// }
|
||||||
type fourByteTracer struct {
|
type fourByteTracer struct {
|
||||||
noopTracer
|
tracers.NoopTracer
|
||||||
ids map[string]int // ids aggregates the 4byte ids found
|
ids map[string]int // ids aggregates the 4byte ids found
|
||||||
interrupt atomic.Bool // Atomic flag to signal execution interruption
|
interrupt atomic.Bool // Atomic flag to signal execution interruption
|
||||||
reason error // Textual reason for the interruption
|
reason error // Textual reason for the interruption
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ type callFrameMarshaling struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type callTracer struct {
|
type callTracer struct {
|
||||||
noopTracer
|
tracers.NoopTracer
|
||||||
callstack []callFrame
|
callstack []callFrame
|
||||||
config callTracerConfig
|
config callTracerConfig
|
||||||
gasLimit uint64
|
gasLimit uint64
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ type flatCallResultMarshaling struct {
|
||||||
// flatCallTracer reports call frame information of a tx in a flat format, i.e.
|
// flatCallTracer reports call frame information of a tx in a flat format, i.e.
|
||||||
// as opposed to the nested format of `callTracer`.
|
// as opposed to the nested format of `callTracer`.
|
||||||
type flatCallTracer struct {
|
type flatCallTracer struct {
|
||||||
noopTracer
|
tracers.NoopTracer
|
||||||
tracer *callTracer
|
tracer *callTracer
|
||||||
config flatCallTracerConfig
|
config flatCallTracerConfig
|
||||||
ctx *tracers.Context // Holds tracer context data
|
ctx *tracers.Context // Holds tracer context data
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,13 @@ func (t *muxTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CaptureGasConsumed is called when gas is consumed.
|
||||||
|
func (t *muxTracer) OnGasConsumed(gas, amount uint64) {
|
||||||
|
for _, t := range t.tracers {
|
||||||
|
t.OnGasConsumed(gas, amount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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 *muxTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
func (t *muxTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||||
for _, t := range t.tracers {
|
for _, t := range t.tracers {
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ type accountMarshaling struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type prestateTracer struct {
|
type prestateTracer struct {
|
||||||
noopTracer
|
tracers.NoopTracer
|
||||||
env *vm.EVM
|
env *vm.EVM
|
||||||
pre state
|
pre state
|
||||||
post state
|
post state
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package native
|
package tracers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
@ -22,59 +22,61 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
tracers.DefaultDirectory.Register("noopTracer", newNoopTracer, false)
|
DefaultDirectory.Register("noopTracer", newNoopTracer, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// noopTracer is a go implementation of the Tracer interface which
|
// NoopTracer is a go implementation of the Tracer interface which
|
||||||
// performs no action. It's mostly useful for testing purposes.
|
// performs no action. It's mostly useful for testing purposes.
|
||||||
type noopTracer struct{}
|
type NoopTracer struct{}
|
||||||
|
|
||||||
// newNoopTracer returns a new noop tracer.
|
// newNoopTracer returns a new noop tracer.
|
||||||
func newNoopTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) {
|
func newNoopTracer(ctx *Context, _ json.RawMessage) (Tracer, error) {
|
||||||
return &noopTracer{}, nil
|
return &NoopTracer{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
|
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
|
||||||
func (t *noopTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
func (t *NoopTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||||
func (t *noopTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
func (t *NoopTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
|
// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
|
||||||
func (t *noopTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
func (t *NoopTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureFault implements the EVMLogger interface to trace an execution fault.
|
// CaptureFault implements the EVMLogger interface to trace an execution fault.
|
||||||
func (t *noopTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) {
|
func (t *NoopTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureKeccakPreimage is called during the KECCAK256 opcode.
|
// CaptureKeccakPreimage is called during the KECCAK256 opcode.
|
||||||
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.
|
||||||
|
func (t *NoopTracer) OnGasConsumed(gas, amount uint64) {}
|
||||||
|
|
||||||
// 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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureExit is called when EVM exits a scope, even if the scope didn't
|
// CaptureExit is called when EVM exits a scope, even if the scope didn't
|
||||||
// execute any code.
|
// execute any code.
|
||||||
func (t *noopTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
|
func (t *NoopTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*noopTracer) CaptureTxStart(gasLimit uint64) {}
|
func (*NoopTracer) CaptureTxStart(gasLimit uint64) {}
|
||||||
|
|
||||||
func (*noopTracer) CaptureTxEnd(restGas uint64) {}
|
func (*NoopTracer) CaptureTxEnd(restGas uint64) {}
|
||||||
|
|
||||||
// GetResult returns an empty json object.
|
// GetResult returns an empty json object.
|
||||||
func (t *noopTracer) GetResult() (json.RawMessage, error) {
|
func (t *NoopTracer) GetResult() (json.RawMessage, error) {
|
||||||
return json.RawMessage(`{}`), nil
|
return json.RawMessage(`{}`), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop terminates execution of the tracer at the first opportune moment.
|
// Stop terminates execution of the tracer at the first opportune moment.
|
||||||
func (t *noopTracer) Stop(err error) {
|
func (t *NoopTracer) Stop(err error) {
|
||||||
}
|
}
|
||||||
|
|
@ -93,3 +93,7 @@ func (p *Printer) OnLog(l *types.Log) {
|
||||||
func (p *Printer) OnNewAccount(a common.Address) {
|
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) {
|
||||||
|
fmt.Printf("OnGasConsumed: gas=%v, amount=%v\n", gas, amount)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue