From d2690d65615f3e18bf1d3b30db972c6c60c16d0c Mon Sep 17 00:00:00 2001 From: Michael de Hoog Date: Wed, 23 Oct 2024 12:08:43 -1000 Subject: [PATCH] Add live tracer for per-tx logging --- eth/tracers/live/logger.go | 92 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 eth/tracers/live/logger.go diff --git a/eth/tracers/live/logger.go b/eth/tracers/live/logger.go new file mode 100644 index 0000000000..4b6b2a5a09 --- /dev/null +++ b/eth/tracers/live/logger.go @@ -0,0 +1,92 @@ +package live + +import ( + "encoding/json" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/log" +) + +func init() { + tracers.LiveDirectory.Register("logger", newLoggerTracer) +} + +type logger struct { + tx *types.Transaction + from common.Address + start time.Time + reads uint64 + writes uint64 + calls uint64 + logs uint64 + creates uint64 + faults uint64 +} + +func newLoggerTracer(_ json.RawMessage) (*tracing.Hooks, error) { + t := &logger{} + return &tracing.Hooks{ + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, + }, nil +} + +func (t *logger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + switch vm.OpCode(op) { + case vm.SLOAD, vm.BALANCE, vm.EXTCODEHASH, vm.EXTCODESIZE, vm.EXTCODECOPY: + t.reads++ + case vm.SSTORE: + t.writes++ + case vm.LOG0, vm.LOG1, vm.LOG2, vm.LOG3, vm.LOG4: + t.logs++ + case vm.CALL, vm.CALLCODE, vm.DELEGATECALL, vm.STATICCALL: + t.calls++ + case vm.CREATE, vm.CREATE2: + t.creates++ + } +} + +func (t *logger) OnFault(pc uint64, op byte, gas, cost uint64, _ tracing.OpContext, depth int, err error) { + t.faults++ +} + +func (t *logger) OnTxStart(vm *tracing.VMContext, tx *types.Transaction, from common.Address) { + t.tx = tx + t.from = from + t.start = time.Now() + t.reads, t.writes, t.calls, t.logs, t.creates, t.faults = 0, 0, 0, 0, 0, 0 +} + +func (t *logger) OnTxEnd(receipt *types.Receipt, err error) { + duration := time.Since(t.start) + to := "" + if t.tx.To() != nil { + to = t.tx.To().Hex() + } + log.Info( + "OnTxEnd", + "hash", t.tx.Hash().Hex(), + "from", t.from.Hex(), + "to", to, + "value", t.tx.Value().String(), + "size", len(t.tx.Data()), + "nonce", t.tx.Nonce(), + "gas", receipt.GasUsed, + "price", t.tx.GasPrice().String(), + "duration", duration.Nanoseconds(), + "reads", t.reads, + "writes", t.writes, + "calls", t.calls, + "logs", t.logs, + "creates", t.creates, + "faults", t.faults, + "error", err, + ) +}