From 85363fb6b86b4fe507db96c6cc54f5f780b2f8ad Mon Sep 17 00:00:00 2001 From: Daniel Liu <139250065@qq.com> Date: Wed, 8 Apr 2026 18:28:39 +0800 Subject: [PATCH] eth/tracers/logger: enforce pre-append size limit Reject struct log entries that would push the buffered trace output past the configured limit. Add regression tests for oversized entries and exact boundary handling. --- eth/tracers/logger/logger.go | 7 +++--- eth/tracers/logger/logger_test.go | 42 +++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 7f2b2aecf2..0757f66ce6 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -276,10 +276,6 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope if l.skip { return } - // check if already accumulated the size of the response. - if l.cfg.Limit != 0 && l.resultSize > l.cfg.Limit { - return - } var ( op = vm.OpCode(opcode) memory = scope.MemoryData() @@ -329,6 +325,9 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope // create a log if l.writer == nil { entry := log.toLegacyJSON() + if l.cfg.Limit != 0 && l.resultSize+len(entry) > l.cfg.Limit { + return + } l.resultSize += len(entry) l.logs = append(l.logs, entry) return diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index 554a37aff1..694ade895d 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -43,6 +44,16 @@ func (*dummyStatedb) GetStateAndCommittedState(common.Address, common.Hash) (com return common.Hash{}, common.Hash{} } +type dummyOpContext struct{} + +func (dummyOpContext) MemoryData() []byte { return nil } +func (dummyOpContext) StackData() []uint256.Int { return nil } +func (dummyOpContext) Caller() common.Address { return common.Address{} } +func (dummyOpContext) Address() common.Address { return common.Address{} } +func (dummyOpContext) CallValue() *uint256.Int { return new(uint256.Int) } +func (dummyOpContext) CallInput() []byte { return nil } +func (dummyOpContext) ContractCode() []byte { return nil } + func TestStoreCapture(t *testing.T) { var ( logger = NewStructLogger(nil) @@ -139,3 +150,34 @@ func TestStructLogLegacyJSONSpecFormatting(t *testing.T) { }) } } + +func TestStructLoggerLimitRejectsOversizedEntry(t *testing.T) { + entry := (&StructLog{Op: vm.STOP, RefundCounter: 1337}).toLegacyJSON() + logger := NewStructLogger(&Config{Limit: len(entry) - 1}) + logger.env = &tracing.VMContext{StateDB: &dummyStatedb{}} + + logger.OnOpcode(0, byte(vm.STOP), 0, 0, dummyOpContext{}, nil, 0, nil) + + if len(logger.logs) != 0 { + t.Fatalf("expected oversized entry to be skipped, got %d logs", len(logger.logs)) + } + if logger.resultSize != 0 { + t.Fatalf("expected result size to remain zero, got %d", logger.resultSize) + } +} + +func TestStructLoggerLimitAllowsEntryUpToBoundary(t *testing.T) { + entry := (&StructLog{Op: vm.STOP, RefundCounter: 1337}).toLegacyJSON() + logger := NewStructLogger(&Config{Limit: len(entry)}) + logger.env = &tracing.VMContext{StateDB: &dummyStatedb{}} + + logger.OnOpcode(0, byte(vm.STOP), 0, 0, dummyOpContext{}, nil, 0, nil) + logger.OnOpcode(0, byte(vm.STOP), 0, 0, dummyOpContext{}, nil, 0, nil) + + if len(logger.logs) != 1 { + t.Fatalf("expected exactly one log at the size boundary, got %d", len(logger.logs)) + } + if logger.resultSize != len(entry) { + t.Fatalf("expected result size %d, got %d", len(entry), logger.resultSize) + } +}