Skip to content

Commit 76198a3

Browse files
committed
execution/commitment: route trie trace through an io.Writer
Replace HexPatriciaHashed's `trace bool` + `fmt.Printf` pattern with a single `traceW io.Writer`. `SetTrace(bool)` becomes `SetTraceWriter(io.Writer)` on the Trie interface; nil disables tracing. The `if traceW != nil` guard is kept, so disabled tracing stays free. Capture is unified onto the same writer: SetCapture/GetCapture ([]string) are removed; ComputeCommitment points traceW at a bytes.Buffer when capture is requested and DrainCapture() returns its contents. This makes trace output configurable (stdout, file, or a bytes.Buffer for assertions in tests). The concurrent trie wraps the writer in a mutex-guarded syncWriter and fans it out to the root and all mounts so cross-goroutine trace writes are safe. GenerateWitness resets traceW to nil to preserve the prior trace-off behavior. traceDomain remains a separate bool gating a stdout dump.
1 parent 04098aa commit 76198a3

9 files changed

Lines changed: 355 additions & 274 deletions

db/state/execctx/domain_shared.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,10 +618,9 @@ func (sd *SharedDomains) InlineTouchKeyDisabled() bool {
618618
return sd.disableInlineTouchKey
619619
}
620620

621-
func (sd *SharedDomains) SetTrace(b, capture bool) []string {
621+
func (sd *SharedDomains) SetTrace(b, capture bool) {
622622
sd.trace = b
623623
sd.commitmentCapture = capture
624-
return sd.sdCtx.GetCapture(true)
625624
}
626625

627626
func (sd *SharedDomains) HasPrefix(domain kv.Domain, prefix []byte, roTx kv.Tx) ([]byte, []byte, bool, error) {

execution/commitment/commitment.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"encoding/binary"
2323
"errors"
2424
"fmt"
25+
"io"
2526
"math/bits"
2627
"slices"
2728
"strconv"
@@ -93,12 +94,10 @@ type Trie interface {
9394
// RootHash produces root hash of the trie
9495
RootHash() (hash []byte, err error)
9596

96-
// Makes trie more verbose
97-
SetTrace(bool)
98-
// Trace domain writes only (no filding etc)
97+
// SetTraceWriter sets the trace writer; nil disables tracing
98+
SetTraceWriter(io.Writer)
99+
// Trace domain writes only (no folding etc)
99100
SetTraceDomain(bool)
100-
SetCapture(capture []string)
101-
GetCapture(truncate bool) []string
102101
EnableCsvMetrics(filePathPrefix string)
103102

104103
// Variant returns commitment trie variant

execution/commitment/commitment_bench_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func BenchmarkHexPatriciaHashedFold(b *testing.B) {
3131
ctx := context.Background()
3232
ms := NewMockState(b)
3333
hph := NewHexPatriciaHashed(1, ms, DefaultTrieConfig())
34-
hph.SetTrace(false)
34+
hph.SetTraceWriter(nil)
3535

3636
// Build a trie with accounts and storage to exercise all fold paths
3737
plainKeys, updates := NewUpdateBuilder().

execution/commitment/commitmentdb/commitment_context.go

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"encoding/hex"
88
"errors"
99
"fmt"
10+
"os"
1011
"runtime"
1112
"sync"
1213
"sync/atomic"
@@ -49,6 +50,7 @@ type SharedDomainsCommitmentContext struct {
4950
patriciaTrie commitment.Trie
5051
justRestored atomic.Bool // set to true when commitment trie was just restored from snapshot
5152
trace bool
53+
captureBuf *bytes.Buffer // buffer for CommitmentCapture trace output
5254
stateReader StateReader
5355
paraTrieDB kv.TemporalRoDB // DB used for para trie and/or parallel trie warmup
5456
// warmupBase holds the construction-time portion of the per-call WarmupConfig.
@@ -150,12 +152,16 @@ func (sdc *SharedDomainsCommitmentContext) SetCustomHistoryStateReader(stateRead
150152

151153
func (sdc *SharedDomainsCommitmentContext) SetTrace(trace bool) {
152154
sdc.trace = trace
153-
sdc.patriciaTrie.SetTrace(trace)
154155
}
155156

156-
// SetCapture enables/disables trie operation capture for diagnosis.
157-
func (sdc *SharedDomainsCommitmentContext) SetCapture(capture []string) {
158-
sdc.patriciaTrie.SetCapture(capture)
157+
// DrainCapture returns the accumulated capture buffer content and resets the buffer.
158+
func (sdc *SharedDomainsCommitmentContext) DrainCapture() string {
159+
if sdc.captureBuf == nil || sdc.captureBuf.Len() == 0 {
160+
return ""
161+
}
162+
s := sdc.captureBuf.String()
163+
sdc.captureBuf.Reset()
164+
return s
159165
}
160166

161167
// GetUpdates returns the current updates buffer. Used by the commitment
@@ -215,10 +221,6 @@ func (sdc *SharedDomainsCommitmentContext) Reset() {
215221
}
216222
}
217223

218-
func (sdc *SharedDomainsCommitmentContext) GetCapture(truncate bool) []string {
219-
return sdc.patriciaTrie.GetCapture(truncate)
220-
}
221-
222224
func (sdc *SharedDomainsCommitmentContext) ClearRam() {
223225
sdc.updates.Reset()
224226
sdc.Reset()
@@ -319,21 +321,28 @@ func (sdc *SharedDomainsCommitmentContext) ComputeCommitment(ctx context.Context
319321
}
320322
log.Debug("[commitment] processed", "block", blockNum, "txNum", txNum, "keys", common.PrettyCounter(updateCount), "keys/s", common.PrettyCounter(keysPerSec), "mode", sdc.updates.Mode(), "spent", took, "rootHash", hex.EncodeToString(rootHash))
321323
}()
324+
// Configure trace writer before any trie operations (including the early-return
325+
// RootHash below) so a stale traceW from a prior call doesn't leak into captureBuf.
326+
sdc.patriciaTrie.SetTraceDomain(sdc.sharedDomains.Trace())
327+
if sdc.sharedDomains.CommitmentCapture() {
328+
if sdc.captureBuf == nil {
329+
sdc.captureBuf = new(bytes.Buffer)
330+
}
331+
sdc.captureBuf.Reset() // ensure clean slate for this computation
332+
sdc.patriciaTrie.SetTraceWriter(sdc.captureBuf)
333+
} else if sdc.trace {
334+
sdc.patriciaTrie.SetTraceWriter(os.Stderr)
335+
} else {
336+
sdc.patriciaTrie.SetTraceWriter(nil)
337+
}
338+
322339
if updateCount == 0 {
323340
rootHash, err = sdc.patriciaTrie.RootHash()
324341
return rootHash, err
325342
}
326343

327344
// data accessing functions should be set when domain is opened/shared context updated
328345

329-
sdc.patriciaTrie.SetTrace(sdc.trace)
330-
sdc.patriciaTrie.SetTraceDomain(sdc.sharedDomains.Trace())
331-
if sdc.sharedDomains.CommitmentCapture() {
332-
if sdc.patriciaTrie.GetCapture(false) == nil {
333-
sdc.patriciaTrie.SetCapture([]string{})
334-
}
335-
}
336-
337346
trieContext := sdc.trieContext(tx, blockNum, txNum)
338347

339348
// If trie trace is configured, wrap the context with a recorder.

execution/commitment/hex_concurrent_patricia_hashed.go

Lines changed: 50 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"io"
78
"sync"
89
"time"
910

@@ -118,8 +119,8 @@ func (p *ConcurrentPatriciaHashed) foldNibble(ctx context.Context, nib int) erro
118119
}
119120

120121
func (p *ConcurrentPatriciaHashed) unfoldRoot(ctx context.Context, ctxFactory TrieContextFactory) error {
121-
if p.root.trace {
122-
fmt.Printf("=============ROOT unfold============\n")
122+
if p.root.traceW != nil {
123+
fmt.Fprintf(p.root.traceW, "=============ROOT unfold============\n")
123124
}
124125
// if p.root.rootPresent && p.root.root.hashedExtLen == 0 { // if root has no extension, we have to unfold
125126
zero := []byte{0}
@@ -133,8 +134,8 @@ func (p *ConcurrentPatriciaHashed) unfoldRoot(ctx context.Context, ctxFactory Tr
133134
}
134135
// }
135136

136-
if p.root.trace {
137-
fmt.Printf("=========END=ROOT unfold============\n")
137+
if p.root.traceW != nil {
138+
fmt.Fprintf(p.root.traceW, "=========END=ROOT unfold============\n")
138139
}
139140

140141
for i := range p.mounts {
@@ -159,36 +160,41 @@ func (p *ConcurrentPatriciaHashed) Close() {
159160
}
160161
}
161162

162-
func (p *ConcurrentPatriciaHashed) SetTrace(b bool) {
163-
p.root.SetTrace(b)
164-
for i := range p.mounts {
165-
p.mounts[i].SetTrace(b)
166-
}
163+
// syncWriter wraps an io.Writer with a mutex for goroutine-safe writes.
164+
// Used by ConcurrentPatriciaHashed to protect concurrent fmt.Fprintf calls
165+
// from root and mount goroutines writing to the same underlying writer.
166+
type syncWriter struct {
167+
mu sync.Mutex
168+
w io.Writer
167169
}
168-
func (p *ConcurrentPatriciaHashed) SetTraceDomain(b bool) {
169-
p.root.SetTraceDomain(b)
170-
for i := range p.mounts {
171-
p.mounts[i].SetTraceDomain(b)
172-
}
170+
171+
func (sw *syncWriter) Write(p []byte) (n int, err error) {
172+
sw.mu.Lock()
173+
n, err = sw.w.Write(p)
174+
sw.mu.Unlock()
175+
return
173176
}
174177

175-
func (p *ConcurrentPatriciaHashed) GetCapture(truncate bool) []string {
176-
capture := p.root.GetCapture(truncate)
177-
if truncate {
178+
func (p *ConcurrentPatriciaHashed) SetTraceWriter(w io.Writer) {
179+
if w != nil {
180+
sw := &syncWriter{w: w}
181+
p.root.SetTraceWriter(sw)
178182
for i := range p.mounts {
179-
p.mounts[i].SetCapture(nil)
183+
p.mounts[i].SetTraceWriter(sw)
184+
}
185+
} else {
186+
p.root.SetTraceWriter(nil)
187+
for i := range p.mounts {
188+
p.mounts[i].SetTraceWriter(nil)
180189
}
181190
}
182-
return capture
183191
}
184-
185-
func (p *ConcurrentPatriciaHashed) SetCapture(capture []string) {
186-
p.root.SetCapture(capture)
192+
func (p *ConcurrentPatriciaHashed) SetTraceDomain(b bool) {
193+
p.root.SetTraceDomain(b)
187194
for i := range p.mounts {
188-
p.mounts[i].SetCapture(capture)
195+
p.mounts[i].SetTraceDomain(b)
189196
}
190197
}
191-
192198
func (p *ConcurrentPatriciaHashed) EnableCsvMetrics(filePathPrefix string) {
193199
p.root.EnableCsvMetrics(filePathPrefix)
194200
for i := range p.mounts {
@@ -199,10 +205,18 @@ func (p *ConcurrentPatriciaHashed) EnableCsvMetrics(filePathPrefix string) {
199205
}
200206

201207
// pass -1 to enable trace just for root trie
202-
func (p *ConcurrentPatriciaHashed) SetParticularTrace(b bool, n int) {
203-
p.root.SetTrace(b)
204-
if n < len(p.mounts) && n >= 0 {
205-
p.mounts[n].SetTrace(b)
208+
func (p *ConcurrentPatriciaHashed) SetParticularTrace(w io.Writer, n int) {
209+
if w != nil {
210+
sw := &syncWriter{w: w}
211+
p.root.SetTraceWriter(sw)
212+
if n < len(p.mounts) && n >= 0 {
213+
p.mounts[n].SetTraceWriter(sw)
214+
}
215+
} else {
216+
p.root.SetTraceWriter(nil)
217+
if n < len(p.mounts) && n >= 0 {
218+
p.mounts[n].SetTraceWriter(nil)
219+
}
206220
}
207221
}
208222

@@ -245,8 +259,8 @@ func (t *Updates) ParallelHashSort(ctx context.Context, pph *ConcurrentPatriciaH
245259
cnt := 0
246260
err := nib.Load(nil, "", func(hashedKey, plainKey []byte, table etl.CurrentTableReader, next etl.LoadNextFunc) error {
247261
cnt++
248-
if phnib.trace {
249-
fmt.Printf("\n%x) %d plainKey [%x] hashedKey [%x] currentKey [%x]\n", ni, cnt, plainKey, hashedKey, phnib.currentKey[:phnib.currentKeyLen])
262+
if phnib.traceW != nil {
263+
fmt.Fprintf(phnib.traceW, "\n%x) %d plainKey [%x] hashedKey [%x] currentKey [%x]\n", ni, cnt, plainKey, hashedKey, phnib.currentKey[:phnib.currentKeyLen])
250264
}
251265
if err := phnib.followAndUpdate(hashedKey, plainKey, nil); err != nil {
252266
return fmt.Errorf("followAndUpdate[%x]: %w", ni, err)
@@ -259,8 +273,8 @@ func (t *Updates) ParallelHashSort(ctx context.Context, pph *ConcurrentPatriciaH
259273
if cnt == 0 {
260274
return nil
261275
}
262-
if pph.mounts[ni].trace {
263-
fmt.Printf("ConcurrentTrie: folding [%2x] keys %d maxDepth %d\n", ni, cnt, phnib.depths[0])
276+
if pph.mounts[ni].traceW != nil {
277+
fmt.Fprintf(pph.mounts[ni].traceW, "ConcurrentTrie: folding [%2x] keys %d maxDepth %d\n", ni, cnt, phnib.depths[0])
264278
}
265279
return pph.foldNibble(gctx, ni)
266280
})
@@ -269,8 +283,8 @@ func (t *Updates) ParallelHashSort(ctx context.Context, pph *ConcurrentPatriciaH
269283
return nil, err
270284
}
271285

272-
if pph.root.trace {
273-
fmt.Printf("======= folding ROOT trie =========\n")
286+
if pph.root.traceW != nil {
287+
fmt.Fprintf(pph.root.traceW, "======= folding ROOT trie =========\n")
274288
}
275289
// TODO zero active rows could be a clue to some invalid cases
276290
if pph.root.activeRows == 0 {
@@ -289,8 +303,8 @@ func (t *Updates) ParallelHashSort(ctx context.Context, pph *ConcurrentPatriciaH
289303
if err != nil {
290304
return nil, err
291305
}
292-
if pph.root.trace {
293-
fmt.Printf("======= folding root done =========\n")
306+
if pph.root.traceW != nil {
307+
fmt.Fprintf(pph.root.traceW, "======= folding root done =========\n")
294308
}
295309
// have to reset trie since we do not do any unfolding
296310
return rootHash, nil

0 commit comments

Comments
 (0)