77 "encoding/hex"
88 "errors"
99 "fmt"
10+ "io"
1011 "runtime"
1112 "sync"
1213 "sync/atomic"
@@ -43,9 +44,6 @@ type sd interface {
4344 // read), tagged with source.
4445 MergeMetrics (source kvmetrics.Source , wm * kvmetrics.DomainMetrics )
4546 StepSize () uint64
46- Trace () bool
47- CommitmentCapture () bool
48-
4947 // ProbeReadLayers samples sd.mem, parent.mem and tx-direct (MDBX) for one
5048 // key — BranchCache divergence-detection probe. Read-only.
5149 ProbeReadLayers (domain kv.Domain , tx kv.TemporalTx , key []byte ) (mem , parentMem , mdbx []byte , memOk , parentOk bool )
@@ -64,7 +62,7 @@ type SharedDomainsCommitmentContext struct {
6462 patriciaTrie commitment.Trie
6563 variant commitment.TrieVariant // selected trie engine, for the [commitment] log (updates.Mode() is ModeParallel for both parallel and streaming)
6664 justRestored atomic.Bool // set to true when commitment trie was just restored from snapshot
67- trace bool
65+ traceW io. Writer
6866 stateReader StateReader
6967 paraTrieDB kv.TemporalRoDB // DB used for para trie and/or parallel trie warmup
7068 // warmupBase holds the construction-time portion of the per-call WarmupConfig.
@@ -170,14 +168,11 @@ func (sdc *SharedDomainsCommitmentContext) SetCustomHistoryStateReader(stateRead
170168 sdc .SetStateReader (stateReader )
171169}
172170
173- func (sdc * SharedDomainsCommitmentContext ) SetTrace (trace bool ) {
174- sdc .trace = trace
175- sdc .patriciaTrie .SetTrace (trace )
176- }
177-
178- // SetCapture enables/disables trie operation capture for diagnosis.
179- func (sdc * SharedDomainsCommitmentContext ) SetCapture (capture []string ) {
180- sdc .patriciaTrie .SetCapture (capture )
171+ func (sdc * SharedDomainsCommitmentContext ) SetTraceWriter (w io.Writer ) {
172+ // Wrap once so the main and per-worker TrieContexts share one mutex-guarded
173+ // writer: concurrent workers trace branch reads/writes without racing.
174+ sdc .traceW = commitment .NewSyncWriter (w )
175+ sdc .patriciaTrie .SetTraceWriter (sdc .traceW )
181176}
182177
183178// GetUpdates returns the current updates buffer. Used by the commitment
@@ -225,6 +220,7 @@ func (sdc *SharedDomainsCommitmentContext) trieContext(tx kv.TemporalTx, blockNu
225220 stepSize : sdc .sharedDomains .StepSize (),
226221 txNum : txNum ,
227222 blockNum : blockNum ,
223+ traceW : sdc .traceW ,
228224 }
229225 if sdc .stateReader != nil {
230226 mainTtx .stateReader = sdc .stateReader .CloneForWorker (readCtx , tx )
@@ -246,10 +242,6 @@ func (sdc *SharedDomainsCommitmentContext) Reset() {
246242 }
247243}
248244
249- func (sdc * SharedDomainsCommitmentContext ) GetCapture (truncate bool ) []string {
250- return sdc .patriciaTrie .GetCapture (truncate )
251- }
252-
253245func (sdc * SharedDomainsCommitmentContext ) ClearRam () {
254246 sdc .updates .Reset ()
255247 sdc .Reset ()
@@ -421,21 +413,17 @@ func (sdc *SharedDomainsCommitmentContext) ComputeCommitment(ctx context.Context
421413 }
422414 log .Debug ("[commitment] processed" , "block" , blockNum , "txNum" , txNum , "keys" , common .PrettyCounter (updateCount ), "keys/s" , common .PrettyCounter (keysPerSec ), "mode" , sdc .variant , "bufmode" , sdc .updates .Mode (), "spent" , took , "rootHash" , hex .EncodeToString (rootHash ))
423415 }()
416+ // Re-apply the trace writer before any trie operations (including the early-return
417+ // RootHash below); GenerateWitness clears it, so it must be restored on each call.
418+ sdc .patriciaTrie .SetTraceWriter (sdc .traceW )
419+
424420 if updateCount == 0 {
425421 rootHash , err = sdc .patriciaTrie .RootHash ()
426422 return rootHash , err
427423 }
428424
429425 // data accessing functions should be set when domain is opened/shared context updated
430426
431- sdc .patriciaTrie .SetTrace (sdc .trace )
432- sdc .patriciaTrie .SetTraceDomain (sdc .sharedDomains .Trace ())
433- if sdc .sharedDomains .CommitmentCapture () {
434- if sdc .patriciaTrie .GetCapture (false ) == nil {
435- sdc .patriciaTrie .SetCapture ([]string {})
436- }
437- }
438-
439427 // Per-ComputeCommitment metrics accumulator for the main (root-fold) reads.
440428 // The fold is single-goroutine, so this lock-free accumulator is owned
441429 // exclusively here; merged into the shared metrics when commitment finishes.
@@ -626,6 +614,7 @@ func (sdc *SharedDomainsCommitmentContext) trieContextFactory(ctx context.Contex
626614 putter : sdc .sharedDomains .AsPutDel (roTx ),
627615 stepSize : stepSize ,
628616 txNum : txNum ,
617+ traceW : sdc .traceW ,
629618 }
630619 if sdc .stateReader != nil {
631620 warmupCtx .stateReader = sdc .stateReader .CloneForWorker (workerCtx , roTx )
@@ -672,6 +661,7 @@ func (sdc *SharedDomainsCommitmentContext) concurrentTrieContextFactory(ctx cont
672661 stepSize : stepSize ,
673662 txNum : txNum ,
674663 localCollector : collector ,
664+ traceW : sdc .traceW ,
675665 }
676666 if sdc .stateReader != nil {
677667 warmupCtx .stateReader = sdc .stateReader .CloneForWorker (workerCtx , roTx )
@@ -887,7 +877,7 @@ func (sdc *SharedDomainsCommitmentContext) restorePatriciaState(value []byte) (u
887877 return 0 , 0 , fmt .Errorf ("failed restore state : %w" , err )
888878 }
889879 sdc .justRestored .Store (true ) // to prevent double reset
890- if sdc .trace {
880+ if sdc .traceW != nil {
891881 rootHash , err := hext .RootHash ()
892882 if err != nil {
893883 return 0 , 0 , fmt .Errorf ("failed to get root hash after state restore: %w" , err )
@@ -904,7 +894,7 @@ type TrieContext struct {
904894 blockNum uint64
905895
906896 stepSize uint64
907- trace bool
897+ traceW io. Writer // nil = disabled; traces branch reads/writes (see [SDC] lines)
908898 stateReader StateReader
909899 localCollector * etl.Collector // per-goroutine collector for concurrent PutBranch
910900}
@@ -925,15 +915,18 @@ func (sdc *TrieContext) Branch(pref []byte) ([]byte, kv.Step, error) {
925915 // underlying state cache / getter aliases shared storage that another goroutine
926916 // (concurrent commitment workers) can recycle. Own the bytes at the trie-context
927917 // boundary so all downstream consumers are safe.
918+ if sdc .traceW != nil {
919+ fmt .Fprintf (sdc .traceW , "[SDC] Branch read %x => %x\n " , pref , enc )
920+ }
928921 return common .Copy (enc ), step , nil
929922}
930923
931924func (sdc * TrieContext ) PutBranch (prefix []byte , data []byte , prevData []byte ) error {
932925 if sdc .stateReader .WithHistory () { // do not store branches if explicitly operate on history
933926 return nil
934927 }
935- if sdc .trace {
936- fmt .Printf ( "[SDC] PutBranch: %x: %x\n " , prefix , data )
928+ if sdc .traceW != nil {
929+ fmt .Fprintf ( sdc . traceW , "[SDC] PutBranch %x: %x\n " , prefix , data )
937930 }
938931 if sdc .localCollector != nil {
939932 return sdc .localCollector .Collect (prefix , data )
0 commit comments