From 5138feb53ef4efeeda394f70a9b4eda304de6d27 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 4 Mar 2022 15:33:53 +0100 Subject: [PATCH 01/18] core,eth: add empty tx logger hooks --- core/state_transition.go | 4 ++++ core/vm/logger.go | 2 ++ eth/tracers/js/tracer.go | 3 +++ eth/tracers/logger/access_list_tracer.go | 3 +++ eth/tracers/logger/logger.go | 6 ++++++ eth/tracers/logger/logger_json.go | 3 +++ eth/tracers/native/4byte.go | 3 +++ eth/tracers/native/call.go | 3 +++ eth/tracers/native/noop.go | 10 ++++++++++ eth/tracers/native/prestate.go | 3 +++ 10 files changed, 40 insertions(+) diff --git a/core/state_transition.go b/core/state_transition.go index 05d5633075b9..ba6727545383 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -302,6 +302,10 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { if st.gas < gas { return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas) } + if st.evm.Config.Debug { + st.evm.Config.Tracer.CaptureTxStart() + defer st.evm.Config.Tracer.CaptureTxEnd() + } st.gas -= gas // Check clause 6 diff --git a/core/vm/logger.go b/core/vm/logger.go index 3af5aec19932..b66cac5d75e2 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -35,4 +35,6 @@ type EVMLogger interface { CaptureExit(output []byte, gasUsed uint64, err error) CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) + CaptureTxStart() + CaptureTxEnd() } diff --git a/eth/tracers/js/tracer.go b/eth/tracers/js/tracer.go index 30c5c2cf149a..0d848cbf96fd 100644 --- a/eth/tracers/js/tracer.go +++ b/eth/tracers/js/tracer.go @@ -679,6 +679,9 @@ func wrapError(context string, err error) error { return fmt.Errorf("%v in server-side tracer function '%v'", err, context) } +func (*jsTracer) CaptureTxStart() {} +func (*jsTracer) CaptureTxEnd() {} + // CaptureStart implements the Tracer interface to initialize the tracing operation. func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { jst.env = env diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 181fc47acb22..89ecdbdab426 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -174,6 +174,9 @@ func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {} +func (*AccessListTracer) CaptureTxStart() {} +func (*AccessListTracer) CaptureTxEnd() {} + // AccessList returns the current accesslist maintained by the tracer. func (a *AccessListTracer) AccessList() types.AccessList { return a.list.accessList() diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index d0c7bff89368..70b2e39fd0d6 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -223,6 +223,9 @@ func (l *StructLogger) CaptureEnter(typ vm.OpCode, from common.Address, to commo func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} +func (*StructLogger) CaptureTxStart() {} +func (*StructLogger) CaptureTxEnd() {} + // StructLogs returns the captured log entries. func (l *StructLogger) StructLogs() []StructLog { return l.logs } @@ -347,3 +350,6 @@ func (t *mdLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad } func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} + +func (*mdLogger) CaptureTxStart() {} +func (*mdLogger) CaptureTxEnd() {} diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 4a7abacba249..b3958b06cb23 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -98,3 +98,6 @@ func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common. } func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} + +func (*JSONLogger) CaptureTxStart() {} +func (*JSONLogger) CaptureTxEnd() {} diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index ad1d89071c52..296f88f72a18 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -131,6 +131,9 @@ func (t *fourByteTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, func (t *fourByteTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { } +func (*fourByteTracer) CaptureTxStart() {} +func (*fourByteTracer) CaptureTxEnd() {} + // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). func (t *fourByteTracer) GetResult() (json.RawMessage, error) { diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 08dc76aa6174..353915a32859 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -142,6 +142,9 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } +func (*callTracer) CaptureTxStart() {} +func (*callTracer) CaptureTxEnd() {} + // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). func (t *callTracer) GetResult() (json.RawMessage, error) { diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index 15b7dbccb7cf..a1e27641389c 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -18,6 +18,7 @@ package native import ( "encoding/json" + "fmt" "math/big" "time" @@ -41,10 +42,12 @@ func newNoopTracer() tracers.Tracer { // 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) { + fmt.Printf("start\n") } // CaptureEnd is called after the call finishes to finalize the tracing. func (t *noopTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { + fmt.Printf("end\n") } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. @@ -64,6 +67,13 @@ func (t *noopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (t *noopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } +func (*noopTracer) CaptureTxStart() { + fmt.Printf("txstart\n") +} +func (*noopTracer) CaptureTxEnd() { + fmt.Printf("txend\n") +} + // GetResult returns an empty json object. func (t *noopTracer) GetResult() (json.RawMessage, error) { return json.RawMessage(`{}`), nil diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 598663ac81c0..4d5ed2e57389 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -145,6 +145,9 @@ func (t *prestateTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (t *prestateTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } +func (*prestateTracer) CaptureTxStart() {} +func (*prestateTracer) CaptureTxEnd() {} + // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). func (t *prestateTracer) GetResult() (json.RawMessage, error) { From cd7d18441149c19dbb0e9f0834f19ec521b8b01c Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 7 Mar 2022 14:13:10 +0100 Subject: [PATCH 02/18] core,eth: add initial and remaining gas to tx hooks --- core/state_transition.go | 30 +++++++++++++++--------- core/vm/logger.go | 4 ++-- eth/tracers/js/tracer.go | 4 ++-- eth/tracers/logger/access_list_tracer.go | 4 ++-- eth/tracers/logger/logger.go | 8 +++---- eth/tracers/logger/logger_json.go | 4 ++-- eth/tracers/native/4byte.go | 4 ++-- eth/tracers/native/call.go | 4 ++-- eth/tracers/native/noop.go | 8 +++---- eth/tracers/native/prestate.go | 4 ++-- 10 files changed, 41 insertions(+), 33 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index ba6727545383..3798e876f5f5 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -287,25 +287,33 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { if err := st.preCheck(); err != nil { return nil, err } - msg := st.msg - sender := vm.AccountRef(msg.From()) - homestead := st.evm.ChainConfig().IsHomestead(st.evm.Context.BlockNumber) - istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.Context.BlockNumber) - london := st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) - contractCreation := msg.To() == nil + + var err error + if st.evm.Config.Debug { + st.evm.Config.Tracer.CaptureTxStart(st.initialGas) + defer func() { + st.evm.Config.Tracer.CaptureTxEnd(st.gas, err) + }() + } + + var ( + msg = st.msg + sender = vm.AccountRef(msg.From()) + homestead = st.evm.ChainConfig().IsHomestead(st.evm.Context.BlockNumber) + istanbul = st.evm.ChainConfig().IsIstanbul(st.evm.Context.BlockNumber) + london = st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) + contractCreation = msg.To() == nil + gas uint64 + ) // Check clauses 4-5, subtract intrinsic gas if everything is correct - gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul) + gas, err = IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul) if err != nil { return nil, err } if st.gas < gas { return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas) } - if st.evm.Config.Debug { - st.evm.Config.Tracer.CaptureTxStart() - defer st.evm.Config.Tracer.CaptureTxEnd() - } st.gas -= gas // Check clause 6 diff --git a/core/vm/logger.go b/core/vm/logger.go index b66cac5d75e2..4928b52f9f36 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -35,6 +35,6 @@ type EVMLogger interface { CaptureExit(output []byte, gasUsed uint64, err error) CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) - CaptureTxStart() - CaptureTxEnd() + CaptureTxStart(gasLimit uint64) + CaptureTxEnd(remainingGas uint64, err error) } diff --git a/eth/tracers/js/tracer.go b/eth/tracers/js/tracer.go index 0d848cbf96fd..59ed3082ddf2 100644 --- a/eth/tracers/js/tracer.go +++ b/eth/tracers/js/tracer.go @@ -679,8 +679,8 @@ func wrapError(context string, err error) error { return fmt.Errorf("%v in server-side tracer function '%v'", err, context) } -func (*jsTracer) CaptureTxStart() {} -func (*jsTracer) CaptureTxEnd() {} +func (*jsTracer) CaptureTxStart(_ uint64) {} +func (*jsTracer) CaptureTxEnd(_ uint64, _ error) {} // CaptureStart implements the Tracer interface to initialize the tracing operation. func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 89ecdbdab426..74f9a5f4d9bc 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -174,8 +174,8 @@ func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*AccessListTracer) CaptureTxStart() {} -func (*AccessListTracer) CaptureTxEnd() {} +func (*AccessListTracer) CaptureTxStart(_ uint64) {} +func (*AccessListTracer) CaptureTxEnd(_ uint64, _ error) {} // AccessList returns the current accesslist maintained by the tracer. func (a *AccessListTracer) AccessList() types.AccessList { diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 70b2e39fd0d6..443b233c5552 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -223,8 +223,8 @@ func (l *StructLogger) CaptureEnter(typ vm.OpCode, from common.Address, to commo func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*StructLogger) CaptureTxStart() {} -func (*StructLogger) CaptureTxEnd() {} +func (*StructLogger) CaptureTxStart(_ uint64) {} +func (*StructLogger) CaptureTxEnd(_ uint64, _ error) {} // StructLogs returns the captured log entries. func (l *StructLogger) StructLogs() []StructLog { return l.logs } @@ -351,5 +351,5 @@ func (t *mdLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*mdLogger) CaptureTxStart() {} -func (*mdLogger) CaptureTxEnd() {} +func (*mdLogger) CaptureTxStart(_ uint64) {} +func (*mdLogger) CaptureTxEnd(_ uint64, _ error) {} diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index b3958b06cb23..8ea0bea2b3d1 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -99,5 +99,5 @@ func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*JSONLogger) CaptureTxStart() {} -func (*JSONLogger) CaptureTxEnd() {} +func (*JSONLogger) CaptureTxStart(_ uint64) {} +func (*JSONLogger) CaptureTxEnd(_ uint64, _ error) {} diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 296f88f72a18..4b2fe265e307 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -131,8 +131,8 @@ func (t *fourByteTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, func (t *fourByteTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { } -func (*fourByteTracer) CaptureTxStart() {} -func (*fourByteTracer) CaptureTxEnd() {} +func (*fourByteTracer) CaptureTxStart(_ uint64) {} +func (*fourByteTracer) CaptureTxEnd(_ uint64, _ error) {} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 353915a32859..9a7cb80f0ece 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -142,8 +142,8 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } -func (*callTracer) CaptureTxStart() {} -func (*callTracer) CaptureTxEnd() {} +func (*callTracer) CaptureTxStart(_ uint64) {} +func (*callTracer) CaptureTxEnd(_ uint64, _ error) {} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index a1e27641389c..ff5990db4b77 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -67,11 +67,11 @@ func (t *noopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (t *noopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (*noopTracer) CaptureTxStart() { - fmt.Printf("txstart\n") +func (*noopTracer) CaptureTxStart(gasLimit uint64) { + fmt.Printf("txstart %d\n", gasLimit) } -func (*noopTracer) CaptureTxEnd() { - fmt.Printf("txend\n") +func (*noopTracer) CaptureTxEnd(remainingGas uint64, err error) { + fmt.Printf("txend %d %v\n", remainingGas, err) } // GetResult returns an empty json object. diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 4d5ed2e57389..27f23e082ee7 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -145,8 +145,8 @@ func (t *prestateTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (t *prestateTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (*prestateTracer) CaptureTxStart() {} -func (*prestateTracer) CaptureTxEnd() {} +func (*prestateTracer) CaptureTxStart(_ uint64) {} +func (*prestateTracer) CaptureTxEnd(_ uint64, _ error) {} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). From 45e6a7b1ccf6420683e825532617198517943bc7 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 7 Mar 2022 15:05:20 +0100 Subject: [PATCH 03/18] store tx gasLimit in js tracer --- eth/tracers/js/tracer.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/eth/tracers/js/tracer.go b/eth/tracers/js/tracer.go index 59ed3082ddf2..0f8e20efadf7 100644 --- a/eth/tracers/js/tracer.go +++ b/eth/tracers/js/tracer.go @@ -419,6 +419,7 @@ type jsTracer struct { activePrecompiles []common.Address // Updated on CaptureStart based on given rules traceSteps bool // When true, will invoke step() on each opcode traceCallFrames bool // When true, will invoke enter() and exit() js funcs + gasLimit uint64 // Amount of gas bought for the whole tx } // New instantiates a new tracer instance. code specifies a Javascript snippet, @@ -679,8 +680,11 @@ func wrapError(context string, err error) error { return fmt.Errorf("%v in server-side tracer function '%v'", err, context) } -func (*jsTracer) CaptureTxStart(_ uint64) {} -func (*jsTracer) CaptureTxEnd(_ uint64, _ error) {} +func (jst *jsTracer) CaptureTxStart(gasLimit uint64) { + jst.gasLimit = gasLimit +} + +func (*jsTracer) CaptureTxEnd(remainingGas uint64, _ error) {} // CaptureStart implements the Tracer interface to initialize the tracing operation. func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { @@ -711,6 +715,7 @@ func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Ad return } jst.ctx["intrinsicGas"] = intrinsicGas + fmt.Printf("Computed intrinsicGas %d\tTrue intrinsic %d\n", intrinsicGas, jst.gasLimit-gas) } // CaptureState implements the Tracer interface to trace a single step of VM execution. From d7fc0aa60913f5fe77115cf43f4ae3091089a10d Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 7 Mar 2022 15:10:15 +0100 Subject: [PATCH 04/18] use gasLimit to compute intrinsic cost for js tracer --- eth/tracers/js/tracer.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/eth/tracers/js/tracer.go b/eth/tracers/js/tracer.go index 0f8e20efadf7..37208c5ff5e1 100644 --- a/eth/tracers/js/tracer.go +++ b/eth/tracers/js/tracer.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" tracers2 "github.com/ethereum/go-ethereum/eth/tracers" @@ -707,15 +706,8 @@ func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Ad rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil) jst.activePrecompiles = vm.ActivePrecompiles(rules) - // Compute intrinsic gas - isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber) - isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber) - intrinsicGas, err := core.IntrinsicGas(input, nil, jst.ctx["type"] == "CREATE", isHomestead, isIstanbul) - if err != nil { - return - } - jst.ctx["intrinsicGas"] = intrinsicGas - fmt.Printf("Computed intrinsicGas %d\tTrue intrinsic %d\n", intrinsicGas, jst.gasLimit-gas) + // Intrinsic costs are the only things reduced from initial gas to this point + jst.ctx["intrinsicGas"] = jst.gasLimit - gas } // CaptureState implements the Tracer interface to trace a single step of VM execution. From 48937ffbe9b69f45458044754a5df56d9e6ae690 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 7 Mar 2022 15:45:36 +0100 Subject: [PATCH 05/18] re-use rules in transitiondb --- core/state_transition.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index 3798e876f5f5..a41b62f0ec88 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -299,15 +299,13 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { var ( msg = st.msg sender = vm.AccountRef(msg.From()) - homestead = st.evm.ChainConfig().IsHomestead(st.evm.Context.BlockNumber) - istanbul = st.evm.ChainConfig().IsIstanbul(st.evm.Context.BlockNumber) - london = st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) + rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil) contractCreation = msg.To() == nil gas uint64 ) // Check clauses 4-5, subtract intrinsic gas if everything is correct - gas, err = IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul) + gas, err = IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul) if err != nil { return nil, err } @@ -322,7 +320,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } // Set up the initial access list. - if rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil); rules.IsBerlin { + if rules.IsBerlin { st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) } var ( @@ -337,7 +335,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value) } - if !london { + if !rules.IsLondon { // Before EIP-3529: refunds were capped to gasUsed / 2 st.refundGas(params.RefundQuotient) } else { @@ -345,7 +343,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { st.refundGas(params.RefundQuotientEIP3529) } effectiveTip := st.gasPrice - if london { + if rules.IsLondon { effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee)) } st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip)) From cbb23c8f4033984dc9875cd188f12c60a8488291 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 7 Mar 2022 19:02:14 +0100 Subject: [PATCH 06/18] rm logs --- eth/tracers/native/noop.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index ff5990db4b77..da556c29e32b 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -67,12 +67,9 @@ func (t *noopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (t *noopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (*noopTracer) CaptureTxStart(gasLimit uint64) { - fmt.Printf("txstart %d\n", gasLimit) -} -func (*noopTracer) CaptureTxEnd(remainingGas uint64, err error) { - fmt.Printf("txend %d %v\n", remainingGas, err) -} +func (*noopTracer) CaptureTxStart(_ uint64) {} + +func (*noopTracer) CaptureTxEnd(_ uint64, _ error) {} // GetResult returns an empty json object. func (t *noopTracer) GetResult() (json.RawMessage, error) { From a76d5ac3dfee2ec874e1a47cd2d14b04a22cb94c Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 7 Mar 2022 19:05:37 +0100 Subject: [PATCH 07/18] rm logs --- eth/tracers/native/noop.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index da556c29e32b..9e541d622c5c 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -18,7 +18,6 @@ package native import ( "encoding/json" - "fmt" "math/big" "time" @@ -42,12 +41,10 @@ func newNoopTracer() tracers.Tracer { // 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) { - fmt.Printf("start\n") } // CaptureEnd is called after the call finishes to finalize the tracing. func (t *noopTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { - fmt.Printf("end\n") } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. From 6cfef9f5a50d8a89a440e9988adec530f00e618b Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 9 Mar 2022 16:56:44 +0100 Subject: [PATCH 08/18] Mv some fields from Start to TxStart --- core/state_transition.go | 16 ++++----- core/vm/evm.go | 6 ++-- core/vm/logger.go | 15 ++++++--- core/vm/runtime/runtime_test.go | 2 +- eth/tracers/js/tracer.go | 25 ++++++++------- eth/tracers/logger/access_list_tracer.go | 8 +++-- eth/tracers/logger/logger.go | 34 +++++++++++++------- eth/tracers/logger/logger_json.go | 8 +++-- eth/tracers/native/4byte.go | 25 ++++++++------- eth/tracers/native/call.go | 26 +++++++++++---- eth/tracers/native/noop.go | 8 +++-- eth/tracers/native/prestate.go | 41 +++++++++++++----------- 12 files changed, 127 insertions(+), 87 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index a41b62f0ec88..bbc34fb9ead0 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -288,15 +288,8 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, err } - var err error - if st.evm.Config.Debug { - st.evm.Config.Tracer.CaptureTxStart(st.initialGas) - defer func() { - st.evm.Config.Tracer.CaptureTxEnd(st.gas, err) - }() - } - var ( + err error msg = st.msg sender = vm.AccountRef(msg.From()) rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil) @@ -304,6 +297,13 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { gas uint64 ) + if st.evm.Config.Debug { + st.evm.Config.Tracer.CaptureTxStart(sender.Address(), contractCreation, st.data, st.initialGas, st.value, rules) + defer func() { + st.evm.Config.Tracer.CaptureTxEnd(st.gas, err) + }() + } + // Check clauses 4-5, subtract intrinsic gas if everything is correct gas, err = IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul) if err != nil { diff --git a/core/vm/evm.go b/core/vm/evm.go index dd55618bf812..a743b5c8a1f3 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -182,7 +182,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // Calling a non existing account, don't do anything, but ping the tracer if evm.Config.Debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) + evm.Config.Tracer.CaptureStart(evm, addr, gas) evm.Config.Tracer.CaptureEnd(ret, 0, 0, nil) } else { evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) @@ -198,7 +198,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // Capture the tracer start/end events in debug mode if evm.Config.Debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) + evm.Config.Tracer.CaptureStart(evm, addr, gas) defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters evm.Config.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err) }(gas, time.Now()) @@ -442,7 +442,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if evm.Config.Debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value) + evm.Config.Tracer.CaptureStart(evm, address, gas) } else { evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value) } diff --git a/core/vm/logger.go b/core/vm/logger.go index 4928b52f9f36..516e7dffe5d2 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -21,6 +21,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/params" ) // EVMLogger is used to collect execution traces from an EVM transaction @@ -29,12 +30,16 @@ import ( // Note that reference types are actual VM data structures; make copies // if you need to retain them beyond the current call. type EVMLogger interface { - CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) - CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) + // Transaction-scoped + CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) + CaptureTxEnd(remainingGas uint64, err error) + // Main call frame + CaptureStart(env *EVM, to common.Address, gas uint64) + CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) + // Nested call frames CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) CaptureExit(output []byte, gasUsed uint64, err error) + // Opcode-scoped + 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) - CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) - CaptureTxStart(gasLimit uint64) - CaptureTxEnd(remainingGas uint64, err error) } diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 97673b490636..204e9a3a3a3a 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -331,7 +331,7 @@ type stepCounter struct { steps int } -func (s *stepCounter) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (s *stepCounter) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { } func (s *stepCounter) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { diff --git a/eth/tracers/js/tracer.go b/eth/tracers/js/tracer.go index 37208c5ff5e1..441bc5eaf54c 100644 --- a/eth/tracers/js/tracer.go +++ b/eth/tracers/js/tracer.go @@ -35,6 +35,7 @@ import ( tracers2 "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/eth/tracers/js/internal/tracers" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" "gopkg.in/olebedev/go-duktape.v3" ) @@ -679,32 +680,32 @@ func wrapError(context string, err error) error { return fmt.Errorf("%v in server-side tracer function '%v'", err, context) } -func (jst *jsTracer) CaptureTxStart(gasLimit uint64) { +func (jst *jsTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { jst.gasLimit = gasLimit + jst.ctx["type"] = "CALL" + if create { + jst.ctx["type"] = "CREATE" + } + jst.ctx["from"] = from + jst.ctx["input"] = input + jst.ctx["value"] = value + + // Update list of precompiles based on current block + jst.activePrecompiles = vm.ActivePrecompiles(rules) } func (*jsTracer) CaptureTxEnd(remainingGas uint64, _ error) {} // CaptureStart implements the Tracer interface to initialize the tracing operation. -func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (jst *jsTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { jst.env = env - jst.ctx["type"] = "CALL" - if create { - jst.ctx["type"] = "CREATE" - } - jst.ctx["from"] = from jst.ctx["to"] = to - jst.ctx["input"] = input jst.ctx["gas"] = gas jst.ctx["gasPrice"] = env.TxContext.GasPrice - jst.ctx["value"] = value // Initialize the context jst.ctx["block"] = env.Context.BlockNumber.Uint64() jst.dbWrapper.db = env.StateDB - // Update list of precompiles based on current block - rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil) - jst.activePrecompiles = vm.ActivePrecompiles(rules) // Intrinsic costs are the only things reduced from initial gas to this point jst.ctx["intrinsicGas"] = jst.gasLimit - gas diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 74f9a5f4d9bc..fe01c822d72c 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/params" ) // accessList is an accumulator for the set of accounts and storage slots an EVM @@ -138,7 +139,7 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi } } -func (a *AccessListTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (a *AccessListTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { } // CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist. @@ -174,8 +175,9 @@ func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*AccessListTracer) CaptureTxStart(_ uint64) {} -func (*AccessListTracer) CaptureTxEnd(_ uint64, _ error) {} +func (*AccessListTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +} +func (*AccessListTracer) CaptureTxEnd(remainingGas uint64, err error) {} // AccessList returns the current accesslist maintained by the tracer. func (a *AccessListTracer) AccessList() types.AccessList { diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 443b233c5552..8fd1eeae78cb 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -134,7 +134,7 @@ func (l *StructLogger) Reset() { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (l *StructLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (l *StructLogger) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { l.env = env } @@ -223,8 +223,9 @@ func (l *StructLogger) CaptureEnter(typ vm.OpCode, from common.Address, to commo func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*StructLogger) CaptureTxStart(_ uint64) {} -func (*StructLogger) CaptureTxEnd(_ uint64, _ error) {} +func (*StructLogger) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +} +func (*StructLogger) CaptureTxEnd(remainingGas uint64, err error) {} // StructLogs returns the captured log entries. func (l *StructLogger) StructLogs() []StructLog { return l.logs } @@ -286,6 +287,11 @@ type mdLogger struct { out io.Writer cfg *Config env *vm.EVM + + from common.Address + create bool + input []byte + value *big.Int } // NewMarkdownLogger creates a logger which outputs information in a format adapted @@ -298,16 +304,16 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { return l } -func (t *mdLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (t *mdLogger) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { t.env = env - if !create { + if !t.create { fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `0x%x`\nGas: `%d`\nValue `%v` wei\n", - from.String(), to.String(), - input, gas, value) + t.from.String(), to.String(), + t.input, gas, t.value) } else { fmt.Fprintf(t.out, "From: `%v`\nCreate at: `%v`\nData: `0x%x`\nGas: `%d`\nValue `%v` wei\n", - from.String(), to.String(), - input, gas, value) + t.from.String(), to.String(), + t.input, gas, t.value) } fmt.Fprintf(t.out, ` @@ -351,5 +357,11 @@ func (t *mdLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*mdLogger) CaptureTxStart(_ uint64) {} -func (*mdLogger) CaptureTxEnd(_ uint64, _ error) {} +func (t *mdLogger) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { + t.from = from + t.create = create + t.input = input + t.value = value +} + +func (*mdLogger) CaptureTxEnd(remainingGas uint64, err error) {} diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 8ea0bea2b3d1..d107ef8be5fd 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/params" ) type JSONLogger struct { @@ -43,7 +44,7 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger { return l } -func (l *JSONLogger) CaptureStart(env *vm.EVM, from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (l *JSONLogger) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { l.env = env } @@ -99,5 +100,6 @@ func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*JSONLogger) CaptureTxStart(_ uint64) {} -func (*JSONLogger) CaptureTxEnd(_ uint64, _ error) {} +func (*JSONLogger) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +} +func (*JSONLogger) CaptureTxEnd(remainingGas uint64, err error) {} diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 4b2fe265e307..66072d5bd969 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/params" ) func init() { @@ -79,17 +80,8 @@ func (t *fourByteTracer) store(id []byte, size int) { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (t *fourByteTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { t.env = env - - // Update list of precompiles based on current block - rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil) - t.activePrecompiles = vm.ActivePrecompiles(rules) - - // Save the outer calldata also - if len(input) >= 4 { - t.store(input[0:4], len(input)-4) - } } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. @@ -131,8 +123,17 @@ func (t *fourByteTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, func (t *fourByteTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { } -func (*fourByteTracer) CaptureTxStart(_ uint64) {} -func (*fourByteTracer) CaptureTxEnd(_ uint64, _ error) {} +func (t *fourByteTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { + // Update list of precompiles based on current block + t.activePrecompiles = vm.ActivePrecompiles(rules) + + // Save the outer calldata also + if len(input) >= 4 { + t.store(input[0:4], len(input)-4) + } +} + +func (*fourByteTracer) CaptureTxEnd(remainingGas uint64, err error) {} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 9a7cb80f0ece..c83c3bb63139 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/params" ) func init() { @@ -52,6 +53,11 @@ type callTracer struct { callstack []callFrame interrupt uint32 // Atomic flag to signal execution interruption reason error // Textual reason for the interruption + + from common.Address + create bool + input []byte + value *big.Int } // newCallTracer returns a native go tracer which tracks @@ -63,17 +69,17 @@ func newCallTracer() tracers.Tracer { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (t *callTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { t.env = env t.callstack[0] = callFrame{ Type: "CALL", - From: addrToHex(from), + From: addrToHex(t.from), To: addrToHex(to), - Input: bytesToHex(input), + Input: bytesToHex(t.input), Gas: uintToHex(gas), - Value: bigToHex(value), + Value: bigToHex(t.value), } - if create { + if t.create { t.callstack[0].Type = "CREATE" } } @@ -142,8 +148,14 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } -func (*callTracer) CaptureTxStart(_ uint64) {} -func (*callTracer) CaptureTxEnd(_ uint64, _ error) {} +func (t *callTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { + t.from = from + t.create = create + t.input = input + t.value = value +} + +func (t *callTracer) CaptureTxEnd(remainingGas uint64, err error) {} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index 9e541d622c5c..76d88b5c61e6 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/params" ) func init() { @@ -40,7 +41,7 @@ func newNoopTracer() tracers.Tracer { } // 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, to common.Address, gas uint64) { } // CaptureEnd is called after the call finishes to finalize the tracing. @@ -64,9 +65,10 @@ func (t *noopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (t *noopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (*noopTracer) CaptureTxStart(_ uint64) {} +func (*noopTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +} -func (*noopTracer) CaptureTxEnd(_ uint64, _ error) {} +func (*noopTracer) CaptureTxEnd(remainingGas uint64, err error) {} // GetResult returns an empty json object. func (t *noopTracer) GetResult() (json.RawMessage, error) { diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 27f23e082ee7..c3ee1b0cc0bd 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -24,10 +24,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/params" ) func init() { @@ -45,7 +45,11 @@ type account struct { type prestateTracer struct { env *vm.EVM prestate prestate + from common.Address create bool + input []byte + gasLimit uint64 + value *big.Int to common.Address interrupt uint32 // Atomic flag to signal execution interruption reason error // Textual reason for the interruption @@ -58,30 +62,22 @@ func newPrestateTracer() tracers.Tracer { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (t *prestateTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { t.env = env - t.create = create t.to = to - // Compute intrinsic gas - isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber) - isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber) - intrinsicGas, err := core.IntrinsicGas(input, nil, create, isHomestead, isIstanbul) - if err != nil { - return - } - - t.lookupAccount(from) + t.lookupAccount(t.from) t.lookupAccount(to) // The recipient balance includes the value transferred. toBal := hexutil.MustDecodeBig(t.prestate[to].Balance) - toBal = new(big.Int).Sub(toBal, value) + toBal = new(big.Int).Sub(toBal, t.value) t.prestate[to].Balance = hexutil.EncodeBig(toBal) // The sender balance is after reducing: value, gasLimit, intrinsicGas. // We need to re-add them to get the pre-tx balance. - fromBal := hexutil.MustDecodeBig(t.prestate[from].Balance) + intrinsicGas := t.gasLimit - gas + fromBal := hexutil.MustDecodeBig(t.prestate[t.from].Balance) gasPrice := env.TxContext.GasPrice consumedGas := new(big.Int).Mul( gasPrice, @@ -90,9 +86,9 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo new(big.Int).SetUint64(gas), ), ) - fromBal.Add(fromBal, new(big.Int).Add(value, consumedGas)) - t.prestate[from].Balance = hexutil.EncodeBig(fromBal) - t.prestate[from].Nonce-- + fromBal.Add(fromBal, new(big.Int).Add(t.value, consumedGas)) + t.prestate[t.from].Balance = hexutil.EncodeBig(fromBal) + t.prestate[t.from].Nonce-- } // CaptureEnd is called after the call finishes to finalize the tracing. @@ -145,8 +141,15 @@ func (t *prestateTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (t *prestateTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (*prestateTracer) CaptureTxStart(_ uint64) {} -func (*prestateTracer) CaptureTxEnd(_ uint64, _ error) {} +func (t *prestateTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { + t.from = from + t.create = create + t.input = input + t.gasLimit = gasLimit + t.value = value +} + +func (*prestateTracer) CaptureTxEnd(remainingGas uint64, err error) {} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). From 02b47418b3c6e5d60284be6c40c1417b05104ee4 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 9 Mar 2022 17:02:03 +0100 Subject: [PATCH 09/18] simplify sender lookup in prestate tracer --- eth/tracers/native/prestate.go | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index c3ee1b0cc0bd..8bce8d2573a8 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -66,29 +66,11 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64 t.env = env t.to = to - t.lookupAccount(t.from) - t.lookupAccount(to) - // The recipient balance includes the value transferred. + t.lookupAccount(to) toBal := hexutil.MustDecodeBig(t.prestate[to].Balance) toBal = new(big.Int).Sub(toBal, t.value) t.prestate[to].Balance = hexutil.EncodeBig(toBal) - - // The sender balance is after reducing: value, gasLimit, intrinsicGas. - // We need to re-add them to get the pre-tx balance. - intrinsicGas := t.gasLimit - gas - fromBal := hexutil.MustDecodeBig(t.prestate[t.from].Balance) - gasPrice := env.TxContext.GasPrice - consumedGas := new(big.Int).Mul( - gasPrice, - new(big.Int).Add( - new(big.Int).SetUint64(intrinsicGas), - new(big.Int).SetUint64(gas), - ), - ) - fromBal.Add(fromBal, new(big.Int).Add(t.value, consumedGas)) - t.prestate[t.from].Balance = hexutil.EncodeBig(fromBal) - t.prestate[t.from].Nonce-- } // CaptureEnd is called after the call finishes to finalize the tracing. @@ -147,6 +129,7 @@ func (t *prestateTracer) CaptureTxStart(from common.Address, create bool, input t.input = input t.gasLimit = gasLimit t.value = value + t.lookupAccount(t.from) } func (*prestateTracer) CaptureTxEnd(remainingGas uint64, err error) {} From d3ae492be64f0986b6fc4dc1d09c0934da29ddf9 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 10 Mar 2022 12:01:54 +0100 Subject: [PATCH 10/18] mv env to TxStart --- core/state_transition.go | 2 +- core/vm/evm.go | 6 +++--- core/vm/logger.go | 4 ++-- core/vm/runtime/runtime_test.go | 2 +- eth/tracers/js/tracer.go | 12 ++++++------ eth/tracers/logger/access_list_tracer.go | 4 ++-- eth/tracers/logger/logger.go | 13 +++++++------ eth/tracers/logger/logger_json.go | 7 ++++--- eth/tracers/native/4byte.go | 6 +++--- eth/tracers/native/call.go | 6 +++--- eth/tracers/native/noop.go | 4 ++-- eth/tracers/native/prestate.go | 6 +++--- 12 files changed, 37 insertions(+), 35 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index bbc34fb9ead0..1fc03c011af7 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -298,7 +298,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { ) if st.evm.Config.Debug { - st.evm.Config.Tracer.CaptureTxStart(sender.Address(), contractCreation, st.data, st.initialGas, st.value, rules) + st.evm.Config.Tracer.CaptureTxStart(st.evm, sender.Address(), contractCreation, st.data, st.initialGas, st.value, rules) defer func() { st.evm.Config.Tracer.CaptureTxEnd(st.gas, err) }() diff --git a/core/vm/evm.go b/core/vm/evm.go index a743b5c8a1f3..8f39cc9ab409 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -182,7 +182,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // Calling a non existing account, don't do anything, but ping the tracer if evm.Config.Debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, addr, gas) + evm.Config.Tracer.CaptureStart(addr, gas) evm.Config.Tracer.CaptureEnd(ret, 0, 0, nil) } else { evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) @@ -198,7 +198,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // Capture the tracer start/end events in debug mode if evm.Config.Debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, addr, gas) + evm.Config.Tracer.CaptureStart(addr, gas) defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters evm.Config.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err) }(gas, time.Now()) @@ -442,7 +442,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if evm.Config.Debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, address, gas) + evm.Config.Tracer.CaptureStart(address, gas) } else { evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value) } diff --git a/core/vm/logger.go b/core/vm/logger.go index 516e7dffe5d2..d535b08184fd 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -31,10 +31,10 @@ import ( // if you need to retain them beyond the current call. type EVMLogger interface { // Transaction-scoped - CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) + CaptureTxStart(env *EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) CaptureTxEnd(remainingGas uint64, err error) // Main call frame - CaptureStart(env *EVM, to common.Address, gas uint64) + CaptureStart(to common.Address, gas uint64) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) // Nested call frames CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 204e9a3a3a3a..95114f2595a8 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -331,7 +331,7 @@ type stepCounter struct { steps int } -func (s *stepCounter) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { +func (s *stepCounter) CaptureStart(to common.Address, gas uint64) { } func (s *stepCounter) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { diff --git a/eth/tracers/js/tracer.go b/eth/tracers/js/tracer.go index 441bc5eaf54c..c02e21503e32 100644 --- a/eth/tracers/js/tracer.go +++ b/eth/tracers/js/tracer.go @@ -680,7 +680,8 @@ func wrapError(context string, err error) error { return fmt.Errorf("%v in server-side tracer function '%v'", err, context) } -func (jst *jsTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +func (jst *jsTracer) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { + jst.env = env jst.gasLimit = gasLimit jst.ctx["type"] = "CALL" if create { @@ -697,15 +698,14 @@ func (jst *jsTracer) CaptureTxStart(from common.Address, create bool, input []by func (*jsTracer) CaptureTxEnd(remainingGas uint64, _ error) {} // CaptureStart implements the Tracer interface to initialize the tracing operation. -func (jst *jsTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { - jst.env = env +func (jst *jsTracer) CaptureStart(to common.Address, gas uint64) { jst.ctx["to"] = to jst.ctx["gas"] = gas - jst.ctx["gasPrice"] = env.TxContext.GasPrice + jst.ctx["gasPrice"] = jst.env.TxContext.GasPrice // Initialize the context - jst.ctx["block"] = env.Context.BlockNumber.Uint64() - jst.dbWrapper.db = env.StateDB + jst.ctx["block"] = jst.env.Context.BlockNumber.Uint64() + jst.dbWrapper.db = jst.env.StateDB // Intrinsic costs are the only things reduced from initial gas to this point jst.ctx["intrinsicGas"] = jst.gasLimit - gas diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index fe01c822d72c..3051ff6cc499 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -139,7 +139,7 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi } } -func (a *AccessListTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { +func (a *AccessListTracer) CaptureStart(to common.Address, gas uint64) { } // CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist. @@ -175,7 +175,7 @@ func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*AccessListTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +func (*AccessListTracer) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { } func (*AccessListTracer) CaptureTxEnd(remainingGas uint64, err error) {} diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 8fd1eeae78cb..244a30ddbf67 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -134,8 +134,7 @@ func (l *StructLogger) Reset() { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (l *StructLogger) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { - l.env = env +func (l *StructLogger) CaptureStart(to common.Address, gas uint64) { } // CaptureState logs a new structured log message and pushes it out to the environment @@ -223,8 +222,10 @@ func (l *StructLogger) CaptureEnter(typ vm.OpCode, from common.Address, to commo func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*StructLogger) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +func (l *StructLogger) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { + l.env = env } + func (*StructLogger) CaptureTxEnd(remainingGas uint64, err error) {} // StructLogs returns the captured log entries. @@ -304,8 +305,7 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { return l } -func (t *mdLogger) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { - t.env = env +func (t *mdLogger) CaptureStart(to common.Address, gas uint64) { if !t.create { fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `0x%x`\nGas: `%d`\nValue `%v` wei\n", t.from.String(), to.String(), @@ -357,7 +357,8 @@ func (t *mdLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (t *mdLogger) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +func (t *mdLogger) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { + t.env = env t.from = from t.create = create t.input = input diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index d107ef8be5fd..4427691cd7cc 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -44,8 +44,7 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger { return l } -func (l *JSONLogger) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { - l.env = env +func (l *JSONLogger) CaptureStart(to common.Address, gas uint64) { } func (l *JSONLogger) CaptureFault(pc uint64, op vm.OpCode, gas uint64, cost uint64, scope *vm.ScopeContext, depth int, err error) { @@ -100,6 +99,8 @@ func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*JSONLogger) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +func (l *JSONLogger) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { + l.env = env } + func (*JSONLogger) CaptureTxEnd(remainingGas uint64, err error) {} diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 66072d5bd969..090507bfc332 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -80,8 +80,7 @@ func (t *fourByteTracer) store(id []byte, size int) { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *fourByteTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { - t.env = env +func (t *fourByteTracer) CaptureStart(to common.Address, gas uint64) { } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. @@ -123,7 +122,8 @@ func (t *fourByteTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, func (t *fourByteTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { } -func (t *fourByteTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +func (t *fourByteTracer) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { + t.env = env // Update list of precompiles based on current block t.activePrecompiles = vm.ActivePrecompiles(rules) diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index c83c3bb63139..7cadddd7eb9f 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -69,8 +69,7 @@ func newCallTracer() tracers.Tracer { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *callTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { - t.env = env +func (t *callTracer) CaptureStart(to common.Address, gas uint64) { t.callstack[0] = callFrame{ Type: "CALL", From: addrToHex(t.from), @@ -148,7 +147,8 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } -func (t *callTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +func (t *callTracer) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { + t.env = env t.from = from t.create = create t.input = input diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index 76d88b5c61e6..bba7faafea0e 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -41,7 +41,7 @@ func newNoopTracer() tracers.Tracer { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *noopTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { +func (t *noopTracer) CaptureStart(to common.Address, gas uint64) { } // CaptureEnd is called after the call finishes to finalize the tracing. @@ -65,7 +65,7 @@ func (t *noopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (t *noopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (*noopTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +func (*noopTracer) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { } func (*noopTracer) CaptureTxEnd(remainingGas uint64, err error) {} diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 8bce8d2573a8..44821b08cd80 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -62,8 +62,7 @@ func newPrestateTracer() tracers.Tracer { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *prestateTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { - t.env = env +func (t *prestateTracer) CaptureStart(to common.Address, gas uint64) { t.to = to // The recipient balance includes the value transferred. @@ -123,7 +122,8 @@ func (t *prestateTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (t *prestateTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (t *prestateTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +func (t *prestateTracer) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { + t.env = env t.from = from t.create = create t.input = input From 34303bfa0f6634413c11672b55af8ced4174b0fb Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 16 Mar 2022 19:32:56 +0100 Subject: [PATCH 11/18] Revert "mv env to TxStart" This reverts commit 656939634b9aff19f55a1cd167345faf8b1ec310. --- core/state_transition.go | 2 +- core/vm/evm.go | 6 +++--- core/vm/logger.go | 4 ++-- core/vm/runtime/runtime_test.go | 2 +- eth/tracers/js/tracer.go | 12 ++++++------ eth/tracers/logger/access_list_tracer.go | 4 ++-- eth/tracers/logger/logger.go | 13 ++++++------- eth/tracers/logger/logger_json.go | 7 +++---- eth/tracers/native/4byte.go | 6 +++--- eth/tracers/native/call.go | 6 +++--- eth/tracers/native/noop.go | 4 ++-- eth/tracers/native/prestate.go | 6 +++--- 12 files changed, 35 insertions(+), 37 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index 1fc03c011af7..bbc34fb9ead0 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -298,7 +298,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { ) if st.evm.Config.Debug { - st.evm.Config.Tracer.CaptureTxStart(st.evm, sender.Address(), contractCreation, st.data, st.initialGas, st.value, rules) + st.evm.Config.Tracer.CaptureTxStart(sender.Address(), contractCreation, st.data, st.initialGas, st.value, rules) defer func() { st.evm.Config.Tracer.CaptureTxEnd(st.gas, err) }() diff --git a/core/vm/evm.go b/core/vm/evm.go index 8f39cc9ab409..a743b5c8a1f3 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -182,7 +182,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // Calling a non existing account, don't do anything, but ping the tracer if evm.Config.Debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(addr, gas) + evm.Config.Tracer.CaptureStart(evm, addr, gas) evm.Config.Tracer.CaptureEnd(ret, 0, 0, nil) } else { evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) @@ -198,7 +198,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // Capture the tracer start/end events in debug mode if evm.Config.Debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(addr, gas) + evm.Config.Tracer.CaptureStart(evm, addr, gas) defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters evm.Config.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err) }(gas, time.Now()) @@ -442,7 +442,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if evm.Config.Debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(address, gas) + evm.Config.Tracer.CaptureStart(evm, address, gas) } else { evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value) } diff --git a/core/vm/logger.go b/core/vm/logger.go index d535b08184fd..516e7dffe5d2 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -31,10 +31,10 @@ import ( // if you need to retain them beyond the current call. type EVMLogger interface { // Transaction-scoped - CaptureTxStart(env *EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) + CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) CaptureTxEnd(remainingGas uint64, err error) // Main call frame - CaptureStart(to common.Address, gas uint64) + CaptureStart(env *EVM, to common.Address, gas uint64) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) // Nested call frames CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 95114f2595a8..204e9a3a3a3a 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -331,7 +331,7 @@ type stepCounter struct { steps int } -func (s *stepCounter) CaptureStart(to common.Address, gas uint64) { +func (s *stepCounter) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { } func (s *stepCounter) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { diff --git a/eth/tracers/js/tracer.go b/eth/tracers/js/tracer.go index c02e21503e32..441bc5eaf54c 100644 --- a/eth/tracers/js/tracer.go +++ b/eth/tracers/js/tracer.go @@ -680,8 +680,7 @@ func wrapError(context string, err error) error { return fmt.Errorf("%v in server-side tracer function '%v'", err, context) } -func (jst *jsTracer) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { - jst.env = env +func (jst *jsTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { jst.gasLimit = gasLimit jst.ctx["type"] = "CALL" if create { @@ -698,14 +697,15 @@ func (jst *jsTracer) CaptureTxStart(env *vm.EVM, from common.Address, create boo func (*jsTracer) CaptureTxEnd(remainingGas uint64, _ error) {} // CaptureStart implements the Tracer interface to initialize the tracing operation. -func (jst *jsTracer) CaptureStart(to common.Address, gas uint64) { +func (jst *jsTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { + jst.env = env jst.ctx["to"] = to jst.ctx["gas"] = gas - jst.ctx["gasPrice"] = jst.env.TxContext.GasPrice + jst.ctx["gasPrice"] = env.TxContext.GasPrice // Initialize the context - jst.ctx["block"] = jst.env.Context.BlockNumber.Uint64() - jst.dbWrapper.db = jst.env.StateDB + jst.ctx["block"] = env.Context.BlockNumber.Uint64() + jst.dbWrapper.db = env.StateDB // Intrinsic costs are the only things reduced from initial gas to this point jst.ctx["intrinsicGas"] = jst.gasLimit - gas diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 3051ff6cc499..fe01c822d72c 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -139,7 +139,7 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi } } -func (a *AccessListTracer) CaptureStart(to common.Address, gas uint64) { +func (a *AccessListTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { } // CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist. @@ -175,7 +175,7 @@ func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*AccessListTracer) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +func (*AccessListTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { } func (*AccessListTracer) CaptureTxEnd(remainingGas uint64, err error) {} diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 244a30ddbf67..8fd1eeae78cb 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -134,7 +134,8 @@ func (l *StructLogger) Reset() { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (l *StructLogger) CaptureStart(to common.Address, gas uint64) { +func (l *StructLogger) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { + l.env = env } // CaptureState logs a new structured log message and pushes it out to the environment @@ -222,10 +223,8 @@ func (l *StructLogger) CaptureEnter(typ vm.OpCode, from common.Address, to commo func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (l *StructLogger) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { - l.env = env +func (*StructLogger) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { } - func (*StructLogger) CaptureTxEnd(remainingGas uint64, err error) {} // StructLogs returns the captured log entries. @@ -305,7 +304,8 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { return l } -func (t *mdLogger) CaptureStart(to common.Address, gas uint64) { +func (t *mdLogger) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { + t.env = env if !t.create { fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `0x%x`\nGas: `%d`\nValue `%v` wei\n", t.from.String(), to.String(), @@ -357,8 +357,7 @@ func (t *mdLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (t *mdLogger) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { - t.env = env +func (t *mdLogger) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { t.from = from t.create = create t.input = input diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 4427691cd7cc..d107ef8be5fd 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -44,7 +44,8 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger { return l } -func (l *JSONLogger) CaptureStart(to common.Address, gas uint64) { +func (l *JSONLogger) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { + l.env = env } func (l *JSONLogger) CaptureFault(pc uint64, op vm.OpCode, gas uint64, cost uint64, scope *vm.ScopeContext, depth int, err error) { @@ -99,8 +100,6 @@ func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (l *JSONLogger) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { - l.env = env +func (*JSONLogger) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { } - func (*JSONLogger) CaptureTxEnd(remainingGas uint64, err error) {} diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 090507bfc332..66072d5bd969 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -80,7 +80,8 @@ func (t *fourByteTracer) store(id []byte, size int) { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *fourByteTracer) CaptureStart(to common.Address, gas uint64) { +func (t *fourByteTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { + t.env = env } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. @@ -122,8 +123,7 @@ func (t *fourByteTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, func (t *fourByteTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { } -func (t *fourByteTracer) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { - t.env = env +func (t *fourByteTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { // Update list of precompiles based on current block t.activePrecompiles = vm.ActivePrecompiles(rules) diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 7cadddd7eb9f..c83c3bb63139 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -69,7 +69,8 @@ func newCallTracer() tracers.Tracer { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *callTracer) CaptureStart(to common.Address, gas uint64) { +func (t *callTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { + t.env = env t.callstack[0] = callFrame{ Type: "CALL", From: addrToHex(t.from), @@ -147,8 +148,7 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } -func (t *callTracer) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { - t.env = env +func (t *callTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { t.from = from t.create = create t.input = input diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index bba7faafea0e..76d88b5c61e6 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -41,7 +41,7 @@ func newNoopTracer() tracers.Tracer { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *noopTracer) CaptureStart(to common.Address, gas uint64) { +func (t *noopTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { } // CaptureEnd is called after the call finishes to finalize the tracing. @@ -65,7 +65,7 @@ func (t *noopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (t *noopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (*noopTracer) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +func (*noopTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { } func (*noopTracer) CaptureTxEnd(remainingGas uint64, err error) {} diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 44821b08cd80..8bce8d2573a8 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -62,7 +62,8 @@ func newPrestateTracer() tracers.Tracer { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *prestateTracer) CaptureStart(to common.Address, gas uint64) { +func (t *prestateTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { + t.env = env t.to = to // The recipient balance includes the value transferred. @@ -122,8 +123,7 @@ func (t *prestateTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (t *prestateTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (t *prestateTracer) CaptureTxStart(env *vm.EVM, from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { - t.env = env +func (t *prestateTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { t.from = from t.create = create t.input = input From 47913aa3f05898478b6cb77c4aa5b38b52702011 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 16 Mar 2022 19:33:05 +0100 Subject: [PATCH 12/18] Revert "simplify sender lookup in prestate tracer" This reverts commit ab65bce48007cab99e68232e7aac2fe008338d50. --- eth/tracers/native/prestate.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 8bce8d2573a8..c3ee1b0cc0bd 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -66,11 +66,29 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64 t.env = env t.to = to - // The recipient balance includes the value transferred. + t.lookupAccount(t.from) t.lookupAccount(to) + + // The recipient balance includes the value transferred. toBal := hexutil.MustDecodeBig(t.prestate[to].Balance) toBal = new(big.Int).Sub(toBal, t.value) t.prestate[to].Balance = hexutil.EncodeBig(toBal) + + // The sender balance is after reducing: value, gasLimit, intrinsicGas. + // We need to re-add them to get the pre-tx balance. + intrinsicGas := t.gasLimit - gas + fromBal := hexutil.MustDecodeBig(t.prestate[t.from].Balance) + gasPrice := env.TxContext.GasPrice + consumedGas := new(big.Int).Mul( + gasPrice, + new(big.Int).Add( + new(big.Int).SetUint64(intrinsicGas), + new(big.Int).SetUint64(gas), + ), + ) + fromBal.Add(fromBal, new(big.Int).Add(t.value, consumedGas)) + t.prestate[t.from].Balance = hexutil.EncodeBig(fromBal) + t.prestate[t.from].Nonce-- } // CaptureEnd is called after the call finishes to finalize the tracing. @@ -129,7 +147,6 @@ func (t *prestateTracer) CaptureTxStart(from common.Address, create bool, input t.input = input t.gasLimit = gasLimit t.value = value - t.lookupAccount(t.from) } func (*prestateTracer) CaptureTxEnd(remainingGas uint64, err error) {} From 507f6b41098f36d892cdb343a3475ff668b87632 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 16 Mar 2022 19:33:10 +0100 Subject: [PATCH 13/18] Revert "Mv some fields from Start to TxStart" This reverts commit aa50d3d9b2559addc80df966111ef5fb5d0c1b6b. --- core/state_transition.go | 16 ++++----- core/vm/evm.go | 6 ++-- core/vm/logger.go | 15 +++------ core/vm/runtime/runtime_test.go | 2 +- eth/tracers/js/tracer.go | 25 +++++++-------- eth/tracers/logger/access_list_tracer.go | 8 ++--- eth/tracers/logger/logger.go | 34 +++++++------------- eth/tracers/logger/logger_json.go | 8 ++--- eth/tracers/native/4byte.go | 25 +++++++-------- eth/tracers/native/call.go | 26 ++++----------- eth/tracers/native/noop.go | 8 ++--- eth/tracers/native/prestate.go | 41 +++++++++++------------- 12 files changed, 87 insertions(+), 127 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index bbc34fb9ead0..a41b62f0ec88 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -288,8 +288,15 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, err } + var err error + if st.evm.Config.Debug { + st.evm.Config.Tracer.CaptureTxStart(st.initialGas) + defer func() { + st.evm.Config.Tracer.CaptureTxEnd(st.gas, err) + }() + } + var ( - err error msg = st.msg sender = vm.AccountRef(msg.From()) rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil) @@ -297,13 +304,6 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { gas uint64 ) - if st.evm.Config.Debug { - st.evm.Config.Tracer.CaptureTxStart(sender.Address(), contractCreation, st.data, st.initialGas, st.value, rules) - defer func() { - st.evm.Config.Tracer.CaptureTxEnd(st.gas, err) - }() - } - // Check clauses 4-5, subtract intrinsic gas if everything is correct gas, err = IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul) if err != nil { diff --git a/core/vm/evm.go b/core/vm/evm.go index a743b5c8a1f3..dd55618bf812 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -182,7 +182,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // Calling a non existing account, don't do anything, but ping the tracer if evm.Config.Debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, addr, gas) + evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) evm.Config.Tracer.CaptureEnd(ret, 0, 0, nil) } else { evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) @@ -198,7 +198,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // Capture the tracer start/end events in debug mode if evm.Config.Debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, addr, gas) + evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters evm.Config.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err) }(gas, time.Now()) @@ -442,7 +442,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if evm.Config.Debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, address, gas) + evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value) } else { evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value) } diff --git a/core/vm/logger.go b/core/vm/logger.go index 516e7dffe5d2..4928b52f9f36 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -21,7 +21,6 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/params" ) // EVMLogger is used to collect execution traces from an EVM transaction @@ -30,16 +29,12 @@ import ( // Note that reference types are actual VM data structures; make copies // if you need to retain them beyond the current call. type EVMLogger interface { - // Transaction-scoped - CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) - CaptureTxEnd(remainingGas uint64, err error) - // Main call frame - CaptureStart(env *EVM, to common.Address, gas uint64) - CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) - // Nested call frames + CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) + CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) CaptureExit(output []byte, gasUsed uint64, err error) - // Opcode-scoped - 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) + CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) + CaptureTxStart(gasLimit uint64) + CaptureTxEnd(remainingGas uint64, err error) } diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 204e9a3a3a3a..97673b490636 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -331,7 +331,7 @@ type stepCounter struct { steps int } -func (s *stepCounter) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { +func (s *stepCounter) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { } func (s *stepCounter) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { diff --git a/eth/tracers/js/tracer.go b/eth/tracers/js/tracer.go index 441bc5eaf54c..37208c5ff5e1 100644 --- a/eth/tracers/js/tracer.go +++ b/eth/tracers/js/tracer.go @@ -35,7 +35,6 @@ import ( tracers2 "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/eth/tracers/js/internal/tracers" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" "gopkg.in/olebedev/go-duktape.v3" ) @@ -680,32 +679,32 @@ func wrapError(context string, err error) error { return fmt.Errorf("%v in server-side tracer function '%v'", err, context) } -func (jst *jsTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { +func (jst *jsTracer) CaptureTxStart(gasLimit uint64) { jst.gasLimit = gasLimit - jst.ctx["type"] = "CALL" - if create { - jst.ctx["type"] = "CREATE" - } - jst.ctx["from"] = from - jst.ctx["input"] = input - jst.ctx["value"] = value - - // Update list of precompiles based on current block - jst.activePrecompiles = vm.ActivePrecompiles(rules) } func (*jsTracer) CaptureTxEnd(remainingGas uint64, _ error) {} // CaptureStart implements the Tracer interface to initialize the tracing operation. -func (jst *jsTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { +func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { jst.env = env + jst.ctx["type"] = "CALL" + if create { + jst.ctx["type"] = "CREATE" + } + jst.ctx["from"] = from jst.ctx["to"] = to + jst.ctx["input"] = input jst.ctx["gas"] = gas jst.ctx["gasPrice"] = env.TxContext.GasPrice + jst.ctx["value"] = value // Initialize the context jst.ctx["block"] = env.Context.BlockNumber.Uint64() jst.dbWrapper.db = env.StateDB + // Update list of precompiles based on current block + rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil) + jst.activePrecompiles = vm.ActivePrecompiles(rules) // Intrinsic costs are the only things reduced from initial gas to this point jst.ctx["intrinsicGas"] = jst.gasLimit - gas diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index fe01c822d72c..74f9a5f4d9bc 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -23,7 +23,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/params" ) // accessList is an accumulator for the set of accounts and storage slots an EVM @@ -139,7 +138,7 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi } } -func (a *AccessListTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { +func (a *AccessListTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { } // CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist. @@ -175,9 +174,8 @@ func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*AccessListTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { -} -func (*AccessListTracer) CaptureTxEnd(remainingGas uint64, err error) {} +func (*AccessListTracer) CaptureTxStart(_ uint64) {} +func (*AccessListTracer) CaptureTxEnd(_ uint64, _ error) {} // AccessList returns the current accesslist maintained by the tracer. func (a *AccessListTracer) AccessList() types.AccessList { diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 8fd1eeae78cb..443b233c5552 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -134,7 +134,7 @@ func (l *StructLogger) Reset() { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (l *StructLogger) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { +func (l *StructLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { l.env = env } @@ -223,9 +223,8 @@ func (l *StructLogger) CaptureEnter(typ vm.OpCode, from common.Address, to commo func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*StructLogger) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { -} -func (*StructLogger) CaptureTxEnd(remainingGas uint64, err error) {} +func (*StructLogger) CaptureTxStart(_ uint64) {} +func (*StructLogger) CaptureTxEnd(_ uint64, _ error) {} // StructLogs returns the captured log entries. func (l *StructLogger) StructLogs() []StructLog { return l.logs } @@ -287,11 +286,6 @@ type mdLogger struct { out io.Writer cfg *Config env *vm.EVM - - from common.Address - create bool - input []byte - value *big.Int } // NewMarkdownLogger creates a logger which outputs information in a format adapted @@ -304,16 +298,16 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { return l } -func (t *mdLogger) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { +func (t *mdLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { t.env = env - if !t.create { + if !create { fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `0x%x`\nGas: `%d`\nValue `%v` wei\n", - t.from.String(), to.String(), - t.input, gas, t.value) + from.String(), to.String(), + input, gas, value) } else { fmt.Fprintf(t.out, "From: `%v`\nCreate at: `%v`\nData: `0x%x`\nGas: `%d`\nValue `%v` wei\n", - t.from.String(), to.String(), - t.input, gas, t.value) + from.String(), to.String(), + input, gas, value) } fmt.Fprintf(t.out, ` @@ -357,11 +351,5 @@ func (t *mdLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (t *mdLogger) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { - t.from = from - t.create = create - t.input = input - t.value = value -} - -func (*mdLogger) CaptureTxEnd(remainingGas uint64, err error) {} +func (*mdLogger) CaptureTxStart(_ uint64) {} +func (*mdLogger) CaptureTxEnd(_ uint64, _ error) {} diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index d107ef8be5fd..8ea0bea2b3d1 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -25,7 +25,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/params" ) type JSONLogger struct { @@ -44,7 +43,7 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger { return l } -func (l *JSONLogger) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { +func (l *JSONLogger) CaptureStart(env *vm.EVM, from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { l.env = env } @@ -100,6 +99,5 @@ func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*JSONLogger) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { -} -func (*JSONLogger) CaptureTxEnd(remainingGas uint64, err error) {} +func (*JSONLogger) CaptureTxStart(_ uint64) {} +func (*JSONLogger) CaptureTxEnd(_ uint64, _ error) {} diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 66072d5bd969..4b2fe265e307 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -26,7 +26,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" - "github.com/ethereum/go-ethereum/params" ) func init() { @@ -80,8 +79,17 @@ func (t *fourByteTracer) store(id []byte, size int) { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *fourByteTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { +func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { t.env = env + + // Update list of precompiles based on current block + rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil) + t.activePrecompiles = vm.ActivePrecompiles(rules) + + // Save the outer calldata also + if len(input) >= 4 { + t.store(input[0:4], len(input)-4) + } } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. @@ -123,17 +131,8 @@ func (t *fourByteTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, func (t *fourByteTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { } -func (t *fourByteTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { - // Update list of precompiles based on current block - t.activePrecompiles = vm.ActivePrecompiles(rules) - - // Save the outer calldata also - if len(input) >= 4 { - t.store(input[0:4], len(input)-4) - } -} - -func (*fourByteTracer) CaptureTxEnd(remainingGas uint64, err error) {} +func (*fourByteTracer) CaptureTxStart(_ uint64) {} +func (*fourByteTracer) CaptureTxEnd(_ uint64, _ error) {} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index c83c3bb63139..9a7cb80f0ece 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -28,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" - "github.com/ethereum/go-ethereum/params" ) func init() { @@ -53,11 +52,6 @@ type callTracer struct { callstack []callFrame interrupt uint32 // Atomic flag to signal execution interruption reason error // Textual reason for the interruption - - from common.Address - create bool - input []byte - value *big.Int } // newCallTracer returns a native go tracer which tracks @@ -69,17 +63,17 @@ func newCallTracer() tracers.Tracer { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *callTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { +func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { t.env = env t.callstack[0] = callFrame{ Type: "CALL", - From: addrToHex(t.from), + From: addrToHex(from), To: addrToHex(to), - Input: bytesToHex(t.input), + Input: bytesToHex(input), Gas: uintToHex(gas), - Value: bigToHex(t.value), + Value: bigToHex(value), } - if t.create { + if create { t.callstack[0].Type = "CREATE" } } @@ -148,14 +142,8 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } -func (t *callTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { - t.from = from - t.create = create - t.input = input - t.value = value -} - -func (t *callTracer) CaptureTxEnd(remainingGas uint64, err error) {} +func (*callTracer) CaptureTxStart(_ uint64) {} +func (*callTracer) CaptureTxEnd(_ uint64, _ error) {} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index 76d88b5c61e6..9e541d622c5c 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -24,7 +24,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" - "github.com/ethereum/go-ethereum/params" ) func init() { @@ -41,7 +40,7 @@ func newNoopTracer() tracers.Tracer { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *noopTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { +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. @@ -65,10 +64,9 @@ func (t *noopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (t *noopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (*noopTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { -} +func (*noopTracer) CaptureTxStart(_ uint64) {} -func (*noopTracer) CaptureTxEnd(remainingGas uint64, err error) {} +func (*noopTracer) CaptureTxEnd(_ uint64, _ error) {} // GetResult returns an empty json object. func (t *noopTracer) GetResult() (json.RawMessage, error) { diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index c3ee1b0cc0bd..27f23e082ee7 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -24,10 +24,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers" - "github.com/ethereum/go-ethereum/params" ) func init() { @@ -45,11 +45,7 @@ type account struct { type prestateTracer struct { env *vm.EVM prestate prestate - from common.Address create bool - input []byte - gasLimit uint64 - value *big.Int to common.Address interrupt uint32 // Atomic flag to signal execution interruption reason error // Textual reason for the interruption @@ -62,22 +58,30 @@ func newPrestateTracer() tracers.Tracer { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *prestateTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64) { +func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { t.env = env + t.create = create t.to = to - t.lookupAccount(t.from) + // Compute intrinsic gas + isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber) + isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber) + intrinsicGas, err := core.IntrinsicGas(input, nil, create, isHomestead, isIstanbul) + if err != nil { + return + } + + t.lookupAccount(from) t.lookupAccount(to) // The recipient balance includes the value transferred. toBal := hexutil.MustDecodeBig(t.prestate[to].Balance) - toBal = new(big.Int).Sub(toBal, t.value) + toBal = new(big.Int).Sub(toBal, value) t.prestate[to].Balance = hexutil.EncodeBig(toBal) // The sender balance is after reducing: value, gasLimit, intrinsicGas. // We need to re-add them to get the pre-tx balance. - intrinsicGas := t.gasLimit - gas - fromBal := hexutil.MustDecodeBig(t.prestate[t.from].Balance) + fromBal := hexutil.MustDecodeBig(t.prestate[from].Balance) gasPrice := env.TxContext.GasPrice consumedGas := new(big.Int).Mul( gasPrice, @@ -86,9 +90,9 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, to common.Address, gas uint64 new(big.Int).SetUint64(gas), ), ) - fromBal.Add(fromBal, new(big.Int).Add(t.value, consumedGas)) - t.prestate[t.from].Balance = hexutil.EncodeBig(fromBal) - t.prestate[t.from].Nonce-- + fromBal.Add(fromBal, new(big.Int).Add(value, consumedGas)) + t.prestate[from].Balance = hexutil.EncodeBig(fromBal) + t.prestate[from].Nonce-- } // CaptureEnd is called after the call finishes to finalize the tracing. @@ -141,15 +145,8 @@ func (t *prestateTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (t *prestateTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (t *prestateTracer) CaptureTxStart(from common.Address, create bool, input []byte, gasLimit uint64, value *big.Int, rules params.Rules) { - t.from = from - t.create = create - t.input = input - t.gasLimit = gasLimit - t.value = value -} - -func (*prestateTracer) CaptureTxEnd(remainingGas uint64, err error) {} +func (*prestateTracer) CaptureTxStart(_ uint64) {} +func (*prestateTracer) CaptureTxEnd(_ uint64, _ error) {} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). From a59d257fac98efe80e069de4b52a918ca5bd5ec0 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 30 Mar 2022 13:43:20 +0200 Subject: [PATCH 14/18] fix intrinsic gas for prestate tracer --- eth/tracers/native/prestate.go | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 27f23e082ee7..72222533ae18 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -24,7 +24,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers" @@ -47,6 +46,7 @@ type prestateTracer struct { prestate prestate create bool to common.Address + gasLimit uint64 // Amount of gas bought for the whole tx interrupt uint32 // Atomic flag to signal execution interruption reason error // Textual reason for the interruption } @@ -63,14 +63,6 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo t.create = create t.to = to - // Compute intrinsic gas - isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber) - isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber) - intrinsicGas, err := core.IntrinsicGas(input, nil, create, isHomestead, isIstanbul) - if err != nil { - return - } - t.lookupAccount(from) t.lookupAccount(to) @@ -82,6 +74,7 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo // The sender balance is after reducing: value, gasLimit, intrinsicGas. // We need to re-add them to get the pre-tx balance. fromBal := hexutil.MustDecodeBig(t.prestate[from].Balance) + intrinsicGas := t.gasLimit - gas gasPrice := env.TxContext.GasPrice consumedGas := new(big.Int).Mul( gasPrice, @@ -145,8 +138,11 @@ func (t *prestateTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (t *prestateTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (*prestateTracer) CaptureTxStart(_ uint64) {} -func (*prestateTracer) CaptureTxEnd(_ uint64, _ error) {} +func (t *prestateTracer) CaptureTxStart(gasLimit uint64) { + t.gasLimit = gasLimit +} + +func (t *prestateTracer) CaptureTxEnd(restGas uint64, err error) {} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). From 3f09581e65f216bed43241d06f682ea9193a6293 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 30 Mar 2022 13:43:32 +0200 Subject: [PATCH 15/18] add comments --- core/vm/logger.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/core/vm/logger.go b/core/vm/logger.go index 4928b52f9f36..6b5ba08c6049 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -29,12 +29,16 @@ import ( // Note that reference types are actual VM data structures; make copies // if you need to retain them beyond the current call. type EVMLogger interface { + // Transaction level + CaptureTxStart(gasLimit uint64) + CaptureTxEnd(remainingGas uint64, err error) + // Top call frame CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) - CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) + CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) + // Rest of call frames CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) CaptureExit(output []byte, gasUsed uint64, err error) + // Opcode level + 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) - CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) - CaptureTxStart(gasLimit uint64) - CaptureTxEnd(remainingGas uint64, err error) } From b7d6ba03482f25953d168682c4dc8f5abc594c14 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 30 Mar 2022 13:55:11 +0200 Subject: [PATCH 16/18] refactor --- core/state_transition.go | 6 ++---- core/vm/logger.go | 2 +- eth/tracers/js/tracer.go | 11 ++++++++--- eth/tracers/logger/access_list_tracer.go | 5 +++-- eth/tracers/logger/logger.go | 10 ++++++---- eth/tracers/logger/logger_json.go | 5 +++-- eth/tracers/native/4byte.go | 5 +++-- eth/tracers/native/call.go | 5 +++-- eth/tracers/native/noop.go | 4 ++-- eth/tracers/native/prestate.go | 2 +- 10 files changed, 32 insertions(+), 23 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index a41b62f0ec88..3b5f81b16632 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -288,11 +288,10 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, err } - var err error if st.evm.Config.Debug { st.evm.Config.Tracer.CaptureTxStart(st.initialGas) defer func() { - st.evm.Config.Tracer.CaptureTxEnd(st.gas, err) + st.evm.Config.Tracer.CaptureTxEnd(st.gas) }() } @@ -301,11 +300,10 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { sender = vm.AccountRef(msg.From()) rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil) contractCreation = msg.To() == nil - gas uint64 ) // Check clauses 4-5, subtract intrinsic gas if everything is correct - gas, err = IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul) + gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul) if err != nil { return nil, err } diff --git a/core/vm/logger.go b/core/vm/logger.go index 6b5ba08c6049..1067947d47cd 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -31,7 +31,7 @@ import ( type EVMLogger interface { // Transaction level CaptureTxStart(gasLimit uint64) - CaptureTxEnd(remainingGas uint64, err error) + CaptureTxEnd(restGas uint64) // Top call frame CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) diff --git a/eth/tracers/js/tracer.go b/eth/tracers/js/tracer.go index 37208c5ff5e1..a71d2920ffaa 100644 --- a/eth/tracers/js/tracer.go +++ b/eth/tracers/js/tracer.go @@ -679,13 +679,18 @@ func wrapError(context string, err error) error { return fmt.Errorf("%v in server-side tracer function '%v'", err, context) } +// CaptureTxStart implements the Tracer interface and is invoked at the beginning of +// transaction processing. func (jst *jsTracer) CaptureTxStart(gasLimit uint64) { jst.gasLimit = gasLimit } -func (*jsTracer) CaptureTxEnd(remainingGas uint64, _ error) {} +// CaptureTxStart implements the Tracer interface and is invoked at the end of +// transaction processing. +func (*jsTracer) CaptureTxEnd(restGas uint64) {} -// CaptureStart implements the Tracer interface to initialize the tracing operation. +// CaptureStart implements the Tracer interface and is invoked before executing the +// top-level call frame of a transaction. func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { jst.env = env jst.ctx["type"] = "CALL" @@ -760,7 +765,7 @@ func (jst *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, sco } } -// CaptureEnd is called after the call finishes to finalize the tracing. +// CaptureEnd is called after the top-level call finishes. func (jst *jsTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) { jst.ctx["output"] = output jst.ctx["time"] = t.String() diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 74f9a5f4d9bc..37f71a05abfb 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -174,8 +174,9 @@ func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*AccessListTracer) CaptureTxStart(_ uint64) {} -func (*AccessListTracer) CaptureTxEnd(_ uint64, _ error) {} +func (*AccessListTracer) CaptureTxStart(gasLimit uint64) {} + +func (*AccessListTracer) CaptureTxEnd(restGas uint64) {} // AccessList returns the current accesslist maintained by the tracer. func (a *AccessListTracer) AccessList() types.AccessList { diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 443b233c5552..fe15c97ef7cd 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -223,8 +223,9 @@ func (l *StructLogger) CaptureEnter(typ vm.OpCode, from common.Address, to commo func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*StructLogger) CaptureTxStart(_ uint64) {} -func (*StructLogger) CaptureTxEnd(_ uint64, _ error) {} +func (*StructLogger) CaptureTxStart(gasLimit uint64) {} + +func (*StructLogger) CaptureTxEnd(restGas uint64) {} // StructLogs returns the captured log entries. func (l *StructLogger) StructLogs() []StructLog { return l.logs } @@ -351,5 +352,6 @@ func (t *mdLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*mdLogger) CaptureTxStart(_ uint64) {} -func (*mdLogger) CaptureTxEnd(_ uint64, _ error) {} +func (*mdLogger) CaptureTxStart(gasLimit uint64) {} + +func (*mdLogger) CaptureTxEnd(restGas uint64) {} diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 8ea0bea2b3d1..72ad0199c946 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -99,5 +99,6 @@ func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*JSONLogger) CaptureTxStart(_ uint64) {} -func (*JSONLogger) CaptureTxEnd(_ uint64, _ error) {} +func (l *JSONLogger) CaptureTxStart(gasLimit uint64) {} + +func (l *JSONLogger) CaptureTxEnd(restGas uint64) {} diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 4b2fe265e307..5d4057689c91 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -131,8 +131,9 @@ func (t *fourByteTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, func (t *fourByteTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { } -func (*fourByteTracer) CaptureTxStart(_ uint64) {} -func (*fourByteTracer) CaptureTxEnd(_ uint64, _ error) {} +func (*fourByteTracer) CaptureTxStart(gasLimit uint64) {} + +func (*fourByteTracer) CaptureTxEnd(restGas uint64) {} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 9a7cb80f0ece..843c1a18f437 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -142,8 +142,9 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } -func (*callTracer) CaptureTxStart(_ uint64) {} -func (*callTracer) CaptureTxEnd(_ uint64, _ error) {} +func (*callTracer) CaptureTxStart(gasLimit uint64) {} + +func (*callTracer) CaptureTxEnd(restGas uint64) {} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index 9e541d622c5c..566a8a652f3a 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -64,9 +64,9 @@ func (t *noopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (t *noopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (*noopTracer) CaptureTxStart(_ uint64) {} +func (*noopTracer) CaptureTxStart(gasLimit uint64) {} -func (*noopTracer) CaptureTxEnd(_ uint64, _ error) {} +func (*noopTracer) CaptureTxEnd(restGas uint64) {} // GetResult returns an empty json object. func (t *noopTracer) GetResult() (json.RawMessage, error) { diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 72222533ae18..111d35996f9c 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -142,7 +142,7 @@ func (t *prestateTracer) CaptureTxStart(gasLimit uint64) { t.gasLimit = gasLimit } -func (t *prestateTracer) CaptureTxEnd(restGas uint64, err error) {} +func (t *prestateTracer) CaptureTxEnd(restGas uint64) {} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). From a167f7e61181321b169e46c577c05537f15d8b64 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 30 Mar 2022 16:01:21 +0200 Subject: [PATCH 17/18] fix test case --- eth/tracers/js/tracer_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index cf0a4aa8284f..9f4d6ddd4d51 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -62,15 +62,19 @@ func testCtx() *vmContext { func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig) (json.RawMessage, error) { var ( env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Debug: true, Tracer: tracer}) + gasLimit uint64 = 31000 startGas uint64 = 10000 value = big.NewInt(0) contract = vm.NewContract(account{}, account{}, value, startGas) ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} + tracer.CaptureTxStart(gasLimit) tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value) ret, err := env.Interpreter().Run(contract, []byte{}, false) tracer.CaptureEnd(ret, startGas-contract.Gas, 1, err) + // Rest gas assumes no refund + tracer.CaptureTxEnd(startGas - contract.Gas) if err != nil { return nil, err } From 5bffbc083f97821d75e91c96df991bba85c4e128 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 31 Mar 2022 10:18:23 +0200 Subject: [PATCH 18/18] simplify consumedGas calc in prestate tracer --- eth/tracers/native/prestate.go | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 111d35996f9c..c7b00e5da88b 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -71,18 +71,11 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo toBal = new(big.Int).Sub(toBal, value) t.prestate[to].Balance = hexutil.EncodeBig(toBal) - // The sender balance is after reducing: value, gasLimit, intrinsicGas. + // The sender balance is after reducing: value and gasLimit. // We need to re-add them to get the pre-tx balance. fromBal := hexutil.MustDecodeBig(t.prestate[from].Balance) - intrinsicGas := t.gasLimit - gas gasPrice := env.TxContext.GasPrice - consumedGas := new(big.Int).Mul( - gasPrice, - new(big.Int).Add( - new(big.Int).SetUint64(intrinsicGas), - new(big.Int).SetUint64(gas), - ), - ) + consumedGas := new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(t.gasLimit)) fromBal.Add(fromBal, new(big.Int).Add(value, consumedGas)) t.prestate[from].Balance = hexutil.EncodeBig(fromBal) t.prestate[from].Nonce--