mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-16 00:43:46 +00:00
has call reverted to snapshot
This commit is contained in:
parent
f241a76f4a
commit
580f02527e
12 changed files with 51 additions and 34 deletions
|
|
@ -17,6 +17,7 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
|
@ -536,10 +537,16 @@ func (evm *EVM) captureEnd(isRoot bool, typ OpCode, startGas uint64, leftOverGas
|
||||||
if leftOverGas != 0 {
|
if leftOverGas != 0 {
|
||||||
tracer.OnGasChange(leftOverGas, 0, GasChangeCallLeftOverReturned)
|
tracer.OnGasChange(leftOverGas, 0, GasChangeCallLeftOverReturned)
|
||||||
}
|
}
|
||||||
|
var reverted bool
|
||||||
|
if err != nil {
|
||||||
|
reverted = true
|
||||||
|
}
|
||||||
|
if !evm.chainRules.IsHomestead && errors.Is(err, ErrCodeStoreOutOfGas) {
|
||||||
|
reverted = false
|
||||||
|
}
|
||||||
if isRoot {
|
if isRoot {
|
||||||
tracer.CaptureEnd(ret, startGas-leftOverGas, VMErrorFromErr(err))
|
tracer.CaptureEnd(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted)
|
||||||
} else {
|
} else {
|
||||||
tracer.CaptureExit(ret, startGas-leftOverGas, VMErrorFromErr(err))
|
tracer.CaptureExit(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -859,7 +859,7 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
||||||
interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
|
interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
|
||||||
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
|
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
|
||||||
tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
|
tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
|
||||||
tracer.CaptureExit([]byte{}, 0, nil)
|
tracer.CaptureExit([]byte{}, 0, nil, false)
|
||||||
}
|
}
|
||||||
return nil, errStopToken
|
return nil, errStopToken
|
||||||
}
|
}
|
||||||
|
|
@ -875,7 +875,7 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
|
||||||
interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address())
|
interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address())
|
||||||
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
|
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
|
||||||
tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
|
tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
|
||||||
tracer.CaptureExit([]byte{}, 0, nil)
|
tracer.CaptureExit([]byte{}, 0, nil, false)
|
||||||
}
|
}
|
||||||
return nil, errStopToken
|
return nil, errStopToken
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,18 @@ type EVMLogger interface {
|
||||||
CaptureTxEnd(receipt *types.Receipt, err error)
|
CaptureTxEnd(receipt *types.Receipt, err error)
|
||||||
// Top call frame
|
// Top call frame
|
||||||
CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int)
|
CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int)
|
||||||
CaptureEnd(output []byte, gasUsed uint64, err error)
|
// CaptureEnd is invoked when the processing of the top call ends.
|
||||||
|
// See docs for `CaptureExit` for info on the `reverted` parameter.
|
||||||
|
CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool)
|
||||||
// Rest of call frames
|
// Rest of call frames
|
||||||
CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int)
|
CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int)
|
||||||
CaptureExit(output []byte, gasUsed uint64, err error)
|
// CaptureExit is invoked when the processing of a message ends.
|
||||||
|
// `revert` is true when there was an error during the execution.
|
||||||
|
// Exceptionally, before the homestead hardfork a contract creation that
|
||||||
|
// ran out of gas when attempting to persist the code to database did not
|
||||||
|
// count as a call failure and did not cause a revert of the call. This will
|
||||||
|
// be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`.
|
||||||
|
CaptureExit(output []byte, gasUsed uint64, err error, reverted bool)
|
||||||
// Opcode level
|
// Opcode level
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ func (t *NoopTracer) CaptureStart(from common.Address, to common.Address, create
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, reverted bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
|
@ -67,7 +67,7 @@ func (t *NoopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.
|
||||||
|
|
||||||
// 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, reverted bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*NoopTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) {}
|
func (*NoopTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) {}
|
||||||
|
|
|
||||||
|
|
@ -331,7 +331,7 @@ func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, reverted bool) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.ctx["error"] = t.vm.ToValue(err.Error())
|
t.ctx["error"] = t.vm.ToValue(err.Error())
|
||||||
}
|
}
|
||||||
|
|
@ -369,7 +369,7 @@ func (t *jsTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad
|
||||||
|
|
||||||
// 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 *jsTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
|
func (t *jsTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||||
if !t.traceFrame {
|
if !t.traceFrame {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ func runTrace(tracer directory.Tracer, vmctx *vmContext, chaincfg *params.ChainC
|
||||||
tracer.CaptureTxStart(env, types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller())
|
tracer.CaptureTxStart(env, types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller())
|
||||||
tracer.CaptureStart(contract.Caller(), contract.Address(), false, []byte{}, startGas, value)
|
tracer.CaptureStart(contract.Caller(), contract.Address(), false, []byte{}, startGas, value)
|
||||||
ret, err := env.Interpreter().Run(contract, []byte{}, false)
|
ret, err := env.Interpreter().Run(contract, []byte{}, false)
|
||||||
tracer.CaptureEnd(ret, startGas-contract.Gas, err)
|
tracer.CaptureEnd(ret, startGas-contract.Gas, err, true)
|
||||||
// Rest gas assumes no refund
|
// Rest gas assumes no refund
|
||||||
tracer.CaptureTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil)
|
tracer.CaptureTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -209,7 +209,7 @@ func TestNoStepExec(t *testing.T) {
|
||||||
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer})
|
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer})
|
||||||
tracer.CaptureTxStart(env, types.NewTx(&types.LegacyTx{}), common.Address{})
|
tracer.CaptureTxStart(env, types.NewTx(&types.LegacyTx{}), common.Address{})
|
||||||
tracer.CaptureStart(common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0))
|
tracer.CaptureStart(common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0))
|
||||||
tracer.CaptureEnd(nil, 0, nil)
|
tracer.CaptureEnd(nil, 0, nil, false)
|
||||||
ret, err := tracer.GetResult()
|
ret, err := tracer.GetResult()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
@ -279,7 +279,7 @@ func TestEnterExit(t *testing.T) {
|
||||||
Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0),
|
Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0),
|
||||||
}
|
}
|
||||||
tracer.CaptureEnter(vm.CALL, scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int))
|
tracer.CaptureEnter(vm.CALL, scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int))
|
||||||
tracer.CaptureExit([]byte{}, 400, nil)
|
tracer.CaptureExit([]byte{}, 400, nil, false)
|
||||||
|
|
||||||
have, err := tracer.GetResult()
|
have, err := tracer.GetResult()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ func (p *Printer) CaptureStart(from common.Address, to common.Address, create bo
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||||
func (p *Printer) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
func (p *Printer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||||
fmt.Printf("CaptureEnd: output=%s, gasUsed=%v, err=%v\n", hexutil.Bytes(output), gasUsed, err)
|
fmt.Printf("CaptureEnd: output=%s, gasUsed=%v, err=%v\n", hexutil.Bytes(output), gasUsed, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ func (p *Printer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Add
|
||||||
|
|
||||||
// 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 (p *Printer) CaptureExit(output []byte, gasUsed uint64, err error) {
|
func (p *Printer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||||
fmt.Printf("CaptureExit: output=%s, gasUsed=%v, err=%v\n", hexutil.Bytes(output), gasUsed, err)
|
fmt.Printf("CaptureExit: output=%s, gasUsed=%v, err=%v\n", hexutil.Bytes(output), gasUsed, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,7 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, reverted bool) {
|
||||||
l.output = output
|
l.output = output
|
||||||
l.err = err
|
l.err = err
|
||||||
if l.cfg.Debug {
|
if l.cfg.Debug {
|
||||||
|
|
@ -377,7 +377,7 @@ func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope
|
||||||
fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err)
|
fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, reverted bool) {
|
||||||
type endLog struct {
|
type endLog struct {
|
||||||
Output string `json:"output"`
|
Output string `json:"output"`
|
||||||
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
|
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,8 @@ type callFrame struct {
|
||||||
Logs []callLog `json:"logs,omitempty" rlp:"optional"`
|
Logs []callLog `json:"logs,omitempty" rlp:"optional"`
|
||||||
// Placed at end on purpose. The RLP will be decoded to 0 instead of
|
// Placed at end on purpose. The RLP will be decoded to 0 instead of
|
||||||
// nil if there are non-empty elements after in the struct.
|
// nil if there are non-empty elements after in the struct.
|
||||||
Value *big.Int `json:"value,omitempty" rlp:"optional"`
|
Value *big.Int `json:"value,omitempty" rlp:"optional"`
|
||||||
|
revertedSnapshot bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f callFrame) TypeString() string {
|
func (f callFrame) TypeString() string {
|
||||||
|
|
@ -67,16 +68,17 @@ func (f callFrame) TypeString() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f callFrame) failed() bool {
|
func (f callFrame) failed() bool {
|
||||||
return len(f.Error) > 0
|
return len(f.Error) > 0 && f.revertedSnapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *callFrame) processOutput(output []byte, err error) {
|
func (f *callFrame) processOutput(output []byte, err error, reverted bool) {
|
||||||
output = common.CopyBytes(output)
|
output = common.CopyBytes(output)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
f.Output = output
|
f.Output = output
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.Error = err.Error()
|
f.Error = err.Error()
|
||||||
|
f.revertedSnapshot = reverted
|
||||||
if f.Type == vm.CREATE || f.Type == vm.CREATE2 {
|
if f.Type == vm.CREATE || f.Type == vm.CREATE2 {
|
||||||
f.To = nil
|
f.To = nil
|
||||||
}
|
}
|
||||||
|
|
@ -147,8 +149,8 @@ func (t *callTracer) CaptureStart(from common.Address, to common.Address, create
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||||
func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||||
t.callstack[0].processOutput(output, err)
|
t.callstack[0].processOutput(output, err, reverted)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
|
@ -180,7 +182,7 @@ func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.
|
||||||
|
|
||||||
// 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 *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
|
func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||||
t.depth--
|
t.depth--
|
||||||
if t.config.OnlyTopCall {
|
if t.config.OnlyTopCall {
|
||||||
return
|
return
|
||||||
|
|
@ -195,7 +197,7 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
|
||||||
size -= 1
|
size -= 1
|
||||||
|
|
||||||
call.GasUsed = gasUsed
|
call.GasUsed = gasUsed
|
||||||
call.processOutput(output, err)
|
call.processOutput(output, err, reverted)
|
||||||
t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call)
|
t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -151,8 +151,8 @@ func (t *flatCallTracer) CaptureStart(from common.Address, to common.Address, cr
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||||
func (t *flatCallTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
func (t *flatCallTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||||
t.tracer.CaptureEnd(output, gasUsed, err)
|
t.tracer.CaptureEnd(output, gasUsed, err, reverted)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
|
@ -178,8 +178,8 @@ func (t *flatCallTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com
|
||||||
|
|
||||||
// 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 *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
|
func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||||
t.tracer.CaptureExit(output, gasUsed, err)
|
t.tracer.CaptureExit(output, gasUsed, err, reverted)
|
||||||
|
|
||||||
// Parity traces don't include CALL/STATICCALLs to precompiles.
|
// Parity traces don't include CALL/STATICCALLs to precompiles.
|
||||||
// By default we remove them from the callstack.
|
// By default we remove them from the callstack.
|
||||||
|
|
|
||||||
|
|
@ -68,9 +68,9 @@ func (t *muxTracer) CaptureStart(from common.Address, to common.Address, create
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||||
func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||||
for _, t := range t.tracers {
|
for _, t := range t.tracers {
|
||||||
t.CaptureEnd(output, gasUsed, err)
|
t.CaptureEnd(output, gasUsed, err, reverted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,9 +111,9 @@ func (t *muxTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.A
|
||||||
|
|
||||||
// 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 *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
|
func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||||
for _, t := range t.tracers {
|
for _, t := range t.tracers {
|
||||||
t.CaptureExit(output, gasUsed, err)
|
t.CaptureExit(output, gasUsed, err, reverted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue