fix(blockassembly/subtreeprocessor): zero-guard validFromMillis in dequeueDuringBlockMovement#846
Conversation
…queueDuringBlockMovement
The Start-loop dequeue at SubtreeProcessor.go:810-813 zero-guards the
validFromMillis calculation so a DoubleSpendWindow of 0 disables the
queue filter entirely. dequeueDuringBlockMovement was missing the
guard and unconditionally computed clock.Now().Add(-1 * window), which
at window=0 yields clock.Now().UnixMilli(). The queue filter at
queue.go:96 ("validFromMillis > 0 && time >= validFromMillis") then
activated, holding back any batch enqueued in the same millisecond as
the drain.
DoubleSpendWindow defaults to 0 (settings/blockassembly_settings.go:29),
so under the default config a block-movement drain could miss
fresh batches that the Start loop would have admitted, leaving them
queued for the next iteration. Mirroring the Start-loop guard restores
parity between the two call sites.
Test changes:
* Test_zeroWindowAsymmetry → Test_zeroWindowFormulasAgree. Renamed and
flipped the drain subtest to assert admission. Now pins post-fix
parity instead of the pre-fix divergence.
* TestDequeueDuringBlockMovement_ZeroWindowAsymmetry → ...AdmitsSameMillisecond.
Renamed and flipped same_millisecond_batch_is_held_back to assert
the batch drains into the subtree. control_one_ms_advance subtest
kept as a separate (now - window) cutoff smoke.
* TestDequeueDuringBlockMovement_RejectsChildOfConflictingParent:
replaced the time.Sleep(5ms) workaround with the clock seam. Both
stp.clock and stp.queue.clock pin to the same instant; the fix
admits the batch at window=0 so the conflicting-parent rejection
path is exercised deterministically.
|
🤖 Claude Code Review Status: Complete Summary: No issues found. This is a well-executed bug fix with excellent test coverage. Review: The PR correctly resolves a control-flow asymmetry between two dequeue call sites. The implementation is solid:
The PR description thoroughly documents the bug, test changes, and verification steps. Test plan shows clean go vet, go test -race, and benchmark sanity checks. |
|
Benchmark Comparison ReportBaseline: Current: Summary
All benchmark results (sec/op)
Threshold: >10% with p < 0.05 | Generated: 2026-05-12 08:47 UTC |



Summary
Mirrors the Start-loop's zero-guard at
dequeueDuringBlockMovementsoDoubleSpendWindow == 0disables the queue filter consistently across both call sites. Closes a same-millisecond admission gap that only manifests under the default config.The bug
The Start-loop dequeue at
SubtreeProcessor.go:810-813zero-guards the calculation:dequeueDuringBlockMovement(pre-fix:3789) skipped that guard and ran the calculation unconditionally:At
DoubleSpendWindow == 0that yieldsclock.Now().UnixMilli()(> 0), which trips the queue filter atqueue.go:96(validFromMillis > 0 && time >= validFromMillis) and rejects any batch enqueued in the same millisecond as the drain.DoubleSpendWindowdefaults to0(settings/blockassembly_settings.go:29). Under the default config, a block-movement drain could miss fresh batches that the Start loop would have admitted, leaving them queued for the next iteration. The fix is one zero-guard, mirroring the Start loop verbatim.This was characterized in #841 and is the asymmetry called out in that PR's "Latent finding" section.
Test changes
Test_zeroWindowAsymmetry→Test_zeroWindowFormulasAgree- renamed and flipped the drain subtest to assert admission. The test now pins post-fix parity between the two formulas.TestDequeueDuringBlockMovement_ZeroWindowAsymmetry→...AdmitsSameMillisecond- flippedsame_millisecond_batch_is_held_backto assert the batch drains. Kept the+1mscontrol subtest as a separate(now - window)cutoff smoke.TestDequeueDuringBlockMovement_RejectsChildOfConflictingParent- replaced thetime.Sleep(5 * time.Millisecond)workaround with the clock seam (bothstp.clockandstp.queue.clockpin to the same instant). With the fix, the batch admits at window=0 and the conflicting-parent rejection path is exercised deterministically. No more wall-time wait.Test plan
go vet ./services/blockassembly/...- cleango test -race -count=1 ./services/blockassembly/subtreeprocessor/- pass (164s)go test -race -count=1 ./services/blockassembly/- pass (101s)Notes
SubtreeProcessor.go, no API change, no new imports.fixedClockto drive timestamps withouttime.Sleep.