diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 8e445818ef..963282ca66 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -51,6 +51,19 @@ type Config struct { Overrides *params.ChainConfig `json:"overrides,omitempty"` } +// countingWriter wraps an io.Writer and records how many bytes have been +// written through it. +type countingWriter struct { + w io.Writer + n int +} + +func (c *countingWriter) Write(p []byte) (int, error) { + n, err := c.w.Write(p) + c.n += n + return n, err +} + //go:generate go run github.com/fjl/gencodec -type StructLog -field-override structLogMarshaling -out gen_structlog.go // StructLog is emitted to the EVM each cycle and lists information about the @@ -227,7 +240,7 @@ type StructLogger struct { writer io.Writer // If set, the logger will stream instead of store logs logs []json.RawMessage // buffer of json-encoded logs - resultSize int + resultSize int // total bytes of trace output interrupt atomic.Bool // Atomic flag to signal execution interruption reason atomic.Pointer[error] // Reason for the interruption, populated by Stop @@ -237,7 +250,7 @@ type StructLogger struct { // NewStreamingStructLogger returns a new streaming logger. func NewStreamingStructLogger(cfg *Config, writer io.Writer) *StructLogger { l := NewStructLogger(cfg) - l.writer = writer + l.writer = &countingWriter{w: writer} return l } @@ -334,6 +347,7 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope return } log.Write(l.writer) + l.resultSize = l.writer.(*countingWriter).n } // OnExit is called a call frame finishes processing. diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 52ac3945d4..530f21b534 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -59,12 +59,14 @@ type jsonLogger struct { cfg *Config env *tracing.VMContext hooks *tracing.Hooks + written *countingWriter } // NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects // into the provided stream. func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks { - l := &jsonLogger{encoder: json.NewEncoder(writer), cfg: cfg} + cw := &countingWriter{w: writer} + l := &jsonLogger{encoder: json.NewEncoder(cw), cfg: cfg, written: cw} if l.cfg == nil { l.cfg = &Config{} } @@ -81,7 +83,8 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks { // NewJSONLoggerWithCallFrames creates a new EVM tracer that prints execution steps as JSON objects // into the provided stream. It also includes call frames in the output. func NewJSONLoggerWithCallFrames(cfg *Config, writer io.Writer) *tracing.Hooks { - l := &jsonLogger{encoder: json.NewEncoder(writer), cfg: cfg} + cw := &countingWriter{w: writer} + l := &jsonLogger{encoder: json.NewEncoder(cw), cfg: cfg, written: cw} if l.cfg == nil { l.cfg = &Config{} } @@ -102,6 +105,9 @@ func (l *jsonLogger) OnFault(pc uint64, op byte, gas uint64, cost uint64, scope } func (l *jsonLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + if l.cfg.Limit != 0 && l.written.n > l.cfg.Limit { + return + } memory := scope.MemoryData() stack := scope.StackData()