Skip to content

Commit

Permalink
Fix system tx gasused (#373)
Browse files Browse the repository at this point in the history
* eth/tracers: trace system tx should add intrinsicGas
  • Loading branch information
blxdyx authored Apr 23, 2024
1 parent b35ebaf commit 9523692
Show file tree
Hide file tree
Showing 20 changed files with 76 additions and 55 deletions.
2 changes: 2 additions & 0 deletions cmd/state/commands/opcode_tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ func (ot *opcodeTracer) CaptureTxStart(gasLimit uint64) {}

func (ot *opcodeTracer) CaptureTxEnd(restGas uint64) {}

func (ot *opcodeTracer) CaptureSystemTxEnd(restGas uint64) {}

func (ot *opcodeTracer) captureStartOrEnter(from, to libcommon.Address, create bool, input []byte) {
//fmt.Fprint(ot.summary, ot.lastLine)

Expand Down
5 changes: 3 additions & 2 deletions cmd/state/exec3/calltracer_v3.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ func (ct *CallTracer) Reset() {
func (ct *CallTracer) Froms() map[libcommon.Address]struct{} { return ct.froms }
func (ct *CallTracer) Tos() map[libcommon.Address]struct{} { return ct.tos }

func (ct *CallTracer) CaptureTxStart(gasLimit uint64) {}
func (ct *CallTracer) CaptureTxEnd(restGas uint64) {}
func (ct *CallTracer) CaptureTxStart(gasLimit uint64) {}
func (ct *CallTracer) CaptureTxEnd(restGas uint64) {}
func (ct *CallTracer) CaptureSystemTxEnd(intrinsicGas uint64) {}
func (ct *CallTracer) CaptureStart(env *vm.EVM, from libcommon.Address, to libcommon.Address, precompile bool, create bool, input []byte, gas uint64, value *uint256.Int, code []byte) {
if ct.froms == nil {
ct.froms = map[libcommon.Address]struct{}{}
Expand Down
12 changes: 12 additions & 0 deletions core/system_contract_lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@ func init() {
addCodeRecords(systemcontracts.KeplerUpgrade[chainName], 0, blockTime, byChain)
}
}
if chainConfig.FeynmanTime != nil {
blockTime := chainConfig.FeynmanTime.Uint64()
if blockTime != 0 {
addCodeRecords(systemcontracts.FeynmanUpgrade[chainName], 0, blockTime, byChain)
}
}
if chainConfig.FeynmanFixTime != nil {
blockTime := chainConfig.FeynmanFixTime.Uint64()
if blockTime != 0 {
addCodeRecords(systemcontracts.FeynmanFixUpgrade[chainName], 0, blockTime, byChain)
}
}
}

addGnosisSpecialCase()
Expand Down
1 change: 1 addition & 0 deletions core/vm/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type EVMLogger interface {
// Transaction level
CaptureTxStart(gasLimit uint64)
CaptureTxEnd(restGas uint64)
CaptureSystemTxEnd(intrinsicGas uint64)
// Top call frame
CaptureStart(env *EVM, from libcommon.Address, to libcommon.Address, precompile bool, create bool, input []byte, gas uint64, value *uint256.Int, code []byte)
CaptureEnd(output []byte, usedGas uint64, err error)
Expand Down
41 changes: 0 additions & 41 deletions erigon-lib/chain/chain_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -615,47 +615,6 @@ func (c *Config) checkCompatible(newcfg *Config, head uint64) *ConfigCompatError
if incompatible(c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock, head) {
return newCompatError("Merge netsplit block", c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock)
}

// Parlia forks
if incompatible(c.RamanujanBlock, newcfg.RamanujanBlock, head) {
return newCompatError("Ramanujan fork block", c.RamanujanBlock, newcfg.RamanujanBlock)
}
if incompatible(c.NielsBlock, newcfg.NielsBlock, head) {
return newCompatError("Niels fork block", c.NielsBlock, newcfg.NielsBlock)
}
if incompatible(c.MirrorSyncBlock, newcfg.MirrorSyncBlock, head) {
return newCompatError("MirrorSync fork block", c.MirrorSyncBlock, newcfg.MirrorSyncBlock)
}
if incompatible(c.BrunoBlock, newcfg.BrunoBlock, head) {
return newCompatError("Bruno fork block", c.BrunoBlock, newcfg.BrunoBlock)
}
if incompatible(c.EulerBlock, newcfg.EulerBlock, head) {
return newCompatError("Euler fork block", c.EulerBlock, newcfg.EulerBlock)
}
if incompatible(c.GibbsBlock, newcfg.GibbsBlock, head) {
return newCompatError("Gibbs fork block", c.GibbsBlock, newcfg.GibbsBlock)
}
if incompatible(c.NanoBlock, newcfg.NanoBlock, head) {
return newCompatError("Nano fork block", c.NanoBlock, newcfg.NanoBlock)
}
if incompatible(c.MoranBlock, newcfg.MoranBlock, head) {
return newCompatError("moran fork block", c.MoranBlock, newcfg.MoranBlock)
}
if incompatible(c.PlanckBlock, newcfg.PlanckBlock, head) {
return newCompatError("planck fork block", c.PlanckBlock, newcfg.PlanckBlock)
}
if incompatible(c.LubanBlock, newcfg.LubanBlock, head) {
return newCompatError("luban fork block", c.LubanBlock, newcfg.LubanBlock)
}
if incompatible(c.PlatoBlock, newcfg.PlatoBlock, head) {
return newCompatError("plato fork block", c.PlatoBlock, newcfg.PlatoBlock)
}
if incompatible(c.HertzBlock, newcfg.HertzBlock, head) {
return newCompatError("hertz fork block", c.HertzBlock, newcfg.HertzBlock)
}
if incompatible(c.HertzfixBlock, newcfg.HertzfixBlock, head) {
return newCompatError("hertzfix fork block", c.HertzfixBlock, newcfg.HertzfixBlock)
}
return nil
}

Expand Down
5 changes: 3 additions & 2 deletions eth/calltracer/calltracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ func NewCallTracer() *CallTracer {
}
}

func (ct *CallTracer) CaptureTxStart(gasLimit uint64) {}
func (ct *CallTracer) CaptureTxEnd(restGas uint64) {}
func (ct *CallTracer) CaptureTxStart(gasLimit uint64) {}
func (ct *CallTracer) CaptureTxEnd(restGas uint64) {}
func (ct *CallTracer) CaptureSystemTxEnd(intrinsicGas uint64) {}

// CaptureStart and CaptureEnter also capture SELFDESTRUCT opcode invocations
func (ct *CallTracer) captureStartOrEnter(from, to libcommon.Address, create bool, code []byte) {
Expand Down
2 changes: 2 additions & 0 deletions eth/tracers/js/goja.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ func (t *jsTracer) CaptureTxEnd(restGas uint64) {
t.ctx["gasUsed"] = t.vm.ToValue(t.gasLimit - restGas)
}

func (t *jsTracer) CaptureSystemTxEnd(intrinsicGas uint64) {}

// CaptureStart implements the Tracer interface to initialize the tracing operation.
func (t *jsTracer) CaptureStart(env *vm.EVM, from libcommon.Address, to libcommon.Address, precompile bool, create bool, input []byte, gas uint64, value *uint256.Int, code []byte) {
t.env = env
Expand Down
2 changes: 2 additions & 0 deletions eth/tracers/logger/access_list_tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ func (a *AccessListTracer) CaptureTxStart(gasLimit uint64) {}

func (a *AccessListTracer) CaptureTxEnd(restGas uint64) {}

func (*AccessListTracer) CaptureSystemTxEnd(intrinsicGas uint64) {}

func (a *AccessListTracer) CaptureStart(env *vm.EVM, from libcommon.Address, to libcommon.Address, precompile bool, create bool, input []byte, gas uint64, value *uint256.Int, code []byte) {
}

Expand Down
2 changes: 2 additions & 0 deletions eth/tracers/logger/json_stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ func (l *JsonStreamLogger) CaptureTxStart(gasLimit uint64) {}

func (l *JsonStreamLogger) CaptureTxEnd(restGas uint64) {}

func (l *JsonStreamLogger) CaptureSystemTxEnd(restGas uint64) {}

// CaptureStart implements the Tracer interface to initialize the tracing operation.
func (l *JsonStreamLogger) CaptureStart(env *vm.EVM, from libcommon.Address, to libcommon.Address, precompile bool, create bool, input []byte, gas uint64, value *uint256.Int, code []byte) {
l.env = env
Expand Down
5 changes: 5 additions & 0 deletions eth/tracers/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ func (l *StructLogger) CaptureTxStart(gasLimit uint64) {}

func (l *StructLogger) CaptureTxEnd(restGas uint64) {}

func (l *StructLogger) CaptureSystemTxEnd(intrinsicGas uint64) {
}

// CaptureStart implements the Tracer interface to initialize the tracing operation.
func (l *StructLogger) CaptureStart(env *vm.EVM, from libcommon.Address, to libcommon.Address, precompile bool, create bool, input []byte, gas uint64, value *uint256.Int, code []byte) {
l.env = env
Expand Down Expand Up @@ -356,6 +359,8 @@ func (t *mdLogger) CaptureTxStart(gasLimit uint64) {}

func (t *mdLogger) CaptureTxEnd(restGas uint64) {}

func (*mdLogger) CaptureSystemTxEnd(intrinsicGas uint64) {}

func (t *mdLogger) captureStartOrEnter(from, to libcommon.Address, create bool, input []byte, gas uint64, value *uint256.Int) {
if !create {
fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `0x%x`\nGas: `%d`\nValue `%v` wei\n",
Expand Down
2 changes: 2 additions & 0 deletions eth/tracers/logger/logger_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func (l *JSONLogger) CaptureTxStart(gasLimit uint64) {}

func (l *JSONLogger) CaptureTxEnd(restGas uint64) {}

func (l *JSONLogger) CaptureSystemTxEnd(intrinsicGas uint64) {}

func (l *JSONLogger) CaptureStart(env *vm.EVM, from libcommon.Address, to libcommon.Address, precompile bool, create bool, input []byte, gas uint64, value *uint256.Int, code []byte) {
l.env = env
}
Expand Down
4 changes: 4 additions & 0 deletions eth/tracers/native/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,10 @@ func (t *callTracer) CaptureTxEnd(restGas uint64) {
t.logGaps = nil
}

func (t *callTracer) CaptureSystemTxEnd(intrinsicGas uint64) {
t.callstack[0].GasUsed -= intrinsicGas
}

// 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) {
Expand Down
6 changes: 6 additions & 0 deletions eth/tracers/native/mux.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ func (t *muxTracer) CaptureTxEnd(restGas uint64) {
}
}

func (t *muxTracer) CaptureSystemTxEnd(intrinsicGas uint64) {
for _, t := range t.tracers {
t.CaptureSystemTxEnd(intrinsicGas)
}
}

// GetResult returns an empty json object.
func (t *muxTracer) GetResult() (json.RawMessage, error) {
resObject := make(map[string]json.RawMessage)
Expand Down
2 changes: 2 additions & 0 deletions eth/tracers/native/noop.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ func (*noopTracer) CaptureTxStart(gasLimit uint64) {}

func (*noopTracer) CaptureTxEnd(restGas uint64) {}

func (t *noopTracer) CaptureSystemTxEnd(intrinsicGas uint64) {}

// GetResult returns an empty json object.
func (t *noopTracer) GetResult() (json.RawMessage, error) {
return json.RawMessage(`{}`), nil
Expand Down
2 changes: 2 additions & 0 deletions eth/tracers/native/prestate.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ func (t *prestateTracer) CaptureTxEnd(restGas uint64) {
}
}

func (t *prestateTracer) CaptureSystemTxEnd(intrinsicGas uint64) {}

// 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) {
Expand Down
2 changes: 1 addition & 1 deletion polygon/tracer/trace_bor_state_sync_txn.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func TraceBorStateSyncTxnDebugAPI(
return traceBorStateSyncTxn(ctx, ibs, stateWriter, stateReceiverContract, stateSyncEvents, evm, rules, txCtx, refunds)
}

return transactions.ExecuteTraceTx(blockCtx, txCtx, ibs, traceConfig, chainConfig, stream, tracer, streaming, execCb)
return transactions.ExecuteTraceTx(blockCtx, txCtx, ibs, traceConfig, chainConfig, stream, tracer, streaming, execCb, 0)
}

func TraceBorStateSyncTxnTraceAPI(
Expand Down
2 changes: 2 additions & 0 deletions turbo/jsonrpc/otterscan_default_tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ func (t *DefaultTracer) CaptureTxStart(gasLimit uint64) {}

func (t *DefaultTracer) CaptureTxEnd(restGas uint64) {}

func (t *DefaultTracer) CaptureSystemTxEnd(intrinsicGas uint64) {}

func (t *DefaultTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, precompile bool, create bool, input []byte, gas uint64, value *uint256.Int, code []byte) {
}

Expand Down
2 changes: 2 additions & 0 deletions turbo/jsonrpc/trace_adhoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,8 @@ func (ot *OeTracer) CaptureTxStart(gasLimit uint64) {}

func (ot *OeTracer) CaptureTxEnd(restGas uint64) {}

func (ot *OeTracer) CaptureSystemTxEnd(intrinsicGas uint64) {}

func (ot *OeTracer) captureStartOrEnter(deep bool, typ vm.OpCode, from libcommon.Address, to libcommon.Address, precompile bool, create bool, input []byte, gas uint64, value *uint256.Int, code []byte) {
//fmt.Printf("captureStartOrEnter deep %t, typ %s, from %x, to %x, create %t, input %x, gas %d, value %d, precompile %t\n", deep, typ.String(), from, to, create, input, gas, value, precompile)
if ot.r.VmTrace != nil {
Expand Down
22 changes: 17 additions & 5 deletions turbo/jsonrpc/tracing.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package jsonrpc
import (
"context"
"fmt"
"github.com/ledgerwatch/erigon/consensus"
"time"

"github.com/holiman/uint256"
Expand Down Expand Up @@ -116,7 +117,6 @@ func (api *PrivateDebugAPIImpl) traceBlock(ctx context.Context, blockNrOrHash rp
} else {
txnHash = txn.Hash()
}

stream.WriteObjectStart()
stream.WriteObjectField("txHash")
stream.WriteString(txnHash.Hex())
Expand Down Expand Up @@ -163,7 +163,13 @@ func (api *PrivateDebugAPIImpl) traceBlock(ctx context.Context, blockNrOrHash rp
api.evmCallTimeout,
)
} else {
err = transactions.TraceTx(ctx, msg, blockCtx, txCtx, ibs, config, chainConfig, stream, api.evmCallTimeout)
var intrinsicGas uint64
if posa, ok := api.engine().(consensus.PoSA); ok {
if isSystem, _ := posa.IsSystemTransaction(txn, block.Header()); isSystem {
intrinsicGas, _ = core.IntrinsicGas(msg.Data(), msg.AccessList(), false, true, true, false)
}
}
err = transactions.TraceTx(ctx, msg, blockCtx, txCtx, ibs, config, chainConfig, stream, api.evmCallTimeout, intrinsicGas)
}
if err == nil {
err = ibs.FinalizeTx(rules, state.NewNoopWriter())
Expand Down Expand Up @@ -295,8 +301,14 @@ func (api *PrivateDebugAPIImpl) TraceTransaction(ctx context.Context, hash commo
api.evmCallTimeout,
)
}
var intrinsicGas uint64
if posa, ok := api.engine().(consensus.PoSA); ok {
if isSystem, _ := posa.IsSystemTransaction(txn, block.Header()); isSystem {
intrinsicGas, _ = core.IntrinsicGas(msg.Data(), msg.AccessList(), false, true, true, false)
}
}
// Trace the transaction and return
return transactions.TraceTx(ctx, msg, blockCtx, txCtx, ibs, config, chainConfig, stream, api.evmCallTimeout)
return transactions.TraceTx(ctx, msg, blockCtx, txCtx, ibs, config, chainConfig, stream, api.evmCallTimeout, intrinsicGas)
}

func (api *PrivateDebugAPIImpl) TraceCall(ctx context.Context, args ethapi.CallArgs, blockNrOrHash rpc.BlockNumberOrHash, config *tracers.TraceConfig, stream *jsoniter.Stream) error {
Expand Down Expand Up @@ -364,7 +376,7 @@ func (api *PrivateDebugAPIImpl) TraceCall(ctx context.Context, args ethapi.CallA
blockCtx := transactions.NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, dbtx, api._blockReader)
txCtx := core.NewEVMTxContext(msg)
// Trace the transaction and return
return transactions.TraceTx(ctx, msg, blockCtx, txCtx, ibs, config, chainConfig, stream, api.evmCallTimeout)
return transactions.TraceTx(ctx, msg, blockCtx, txCtx, ibs, config, chainConfig, stream, api.evmCallTimeout, 0)
}

func (api *PrivateDebugAPIImpl) TraceCallMany(ctx context.Context, bundles []Bundle, simulateContext StateContext, config *tracers.TraceConfig, stream *jsoniter.Stream) error {
Expand Down Expand Up @@ -528,7 +540,7 @@ func (api *PrivateDebugAPIImpl) TraceCallMany(ctx context.Context, bundles []Bun
txCtx = core.NewEVMTxContext(msg)
ibs := evm.IntraBlockState().(*state.IntraBlockState)
ibs.SetTxContext(common.Hash{}, header.Hash(), txnIndex)
err = transactions.TraceTx(ctx, msg, blockCtx, txCtx, evm.IntraBlockState(), config, chainConfig, stream, api.evmCallTimeout)
err = transactions.TraceTx(ctx, msg, blockCtx, txCtx, evm.IntraBlockState(), config, chainConfig, stream, api.evmCallTimeout, 0)
if err != nil {
stream.WriteArrayEnd()
stream.WriteArrayEnd()
Expand Down
10 changes: 6 additions & 4 deletions turbo/transactions/tracing.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ func ComputeTxEnv(ctx context.Context, engine consensus.EngineReader, block *typ
return nil, evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, nil, err
}

//var beforeSystemTx = true
for idx, txn := range block.Transactions() {
select {
default:
Expand Down Expand Up @@ -136,6 +137,7 @@ func TraceTx(
chainConfig *chain.Config,
stream *jsoniter.Stream,
callTimeout time.Duration,
intrinsicGas uint64,
) error {
tracer, streaming, cancel, err := AssembleTracer(ctx, config, txCtx.TxHash, stream, callTimeout)
if err != nil {
Expand All @@ -150,7 +152,7 @@ func TraceTx(
return core.ApplyMessage(evm, message, gp, refunds, false /* gasBailout */)
}

return ExecuteTraceTx(blockCtx, txCtx, ibs, config, chainConfig, stream, tracer, streaming, execCb)
return ExecuteTraceTx(blockCtx, txCtx, ibs, config, chainConfig, stream, tracer, streaming, execCb, intrinsicGas)
}

func AssembleTracer(
Expand Down Expand Up @@ -208,6 +210,7 @@ func ExecuteTraceTx(
tracer vm.EVMLogger,
streaming bool,
execCb func(evm *vm.EVM, refunds bool) (*core.ExecutionResult, error),
intrinsicGas uint64,
) error {
// Run the transaction with tracing enabled.
evm := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vm.Config{Debug: true, Tracer: tracer})
Expand All @@ -222,8 +225,8 @@ func ExecuteTraceTx(
stream.WriteObjectField("structLogs")
stream.WriteArrayStart()
}

result, err := execCb(evm, refunds)
tracer.CaptureSystemTxEnd(intrinsicGas)
if err != nil {
if streaming {
stream.WriteArrayEnd()
Expand All @@ -233,13 +236,12 @@ func ExecuteTraceTx(
}
return fmt.Errorf("tracing failed: %w", err)
}

// Depending on the tracer type, format and return the output
if streaming {
stream.WriteArrayEnd()
stream.WriteMore()
stream.WriteObjectField("gas")
stream.WriteUint64(result.UsedGas)
stream.WriteUint64(result.UsedGas - intrinsicGas)
stream.WriteMore()
stream.WriteObjectField("failed")
stream.WriteBool(result.Failed())
Expand Down

0 comments on commit 9523692

Please sign in to comment.