drop proofs and headers received too late in the next round#7804
drop proofs and headers received too late in the next round#7804sstanculeanu wants to merge 14 commits intofeat/testnet-fixesfrom
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## feat/supernova-async-exec #7804 +/- ##
==========================================================
Coverage 77.56% 77.56%
==========================================================
Files 882 882
Lines 123719 123752 +33
==========================================================
+ Hits 95958 95987 +29
- Misses 21402 21407 +5
+ Partials 6359 6358 -1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
|
||
| currentRoundStart := bbt.roundHandler.TimeStamp() | ||
| roundDuration := float64(bbt.roundHandler.TimeDuration()) | ||
| maxTimeToAcceptProof := time.Duration(roundDuration + roundDuration*receivedProofDelay) |
There was a problem hiding this comment.
| maxTimeToAcceptProof := time.Duration(roundDuration + roundDuration*receivedProofDelay) | |
| maxTimeToAcceptProof := time.Duration(currentRoundStart + roundDuration*receivedProofDelay) |
it should be based on start round time, right?
There was a problem hiding this comment.
no, max time parameter is the total amount of time (900 ms in this case), as RemainingTime is called with currentRoundStart
| RemainingTimeCalled: func(startTime time.Time, maxTime time.Duration) time.Duration { | ||
| currentTime := time.Now() | ||
| elapsedTime := currentTime.Sub(startTime) | ||
| remainingTime := maxTime - elapsedTime | ||
|
|
||
| return remainingTime | ||
| }, |
There was a problem hiding this comment.
can we use real RemainingTime method from round handler?
There was a problem hiding this comment.
maybe use real round handler, and call UpdateRound several times to set the desired index (with lower test values)
There was a problem hiding this comment.
that should work too, tried to keep it simple
There was a problem hiding this comment.
Pull request overview
This PR attempts to enforce a time window for accepting “next round” headers/proofs, so that items received too late are dropped, and wires round timing data through the process.RoundHandler interface to support that logic.
Changes:
- Extend
process.RoundHandlerwithTimeStamp()andRemainingTime(...)to support time-window validation. - Add a time-window check in
baseBlockTrack.checkAgainstRoundHandler. - Update mocks and add a unit test intended to cover the “too-late” rejection behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| process/track/baseBlockTrack.go | Adds time-window rejection logic for headers/proofs based on round timing. |
| process/track/baseBlockTrack_test.go | Updates round handler setup in tests and adds a new “invalid window” test. |
| process/mock/rounderMock.go | Extends the process mock to support RemainingTime injection via callback. |
| process/interface.go | Extends process.RoundHandler with timestamp and remaining-time methods. |
| integrationTests/testProcessorNode.go | Updates integration-test round handler mock initialization for new interface expectations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // wait until after half of the next round passed | ||
| timeToSleep := roundDuration + time.Duration(float64(roundDuration)*0.6) | ||
| time.Sleep(timeToSleep) |
There was a problem hiding this comment.
The test relies on real time (time.Sleep) to cross the acceptance window, which makes the suite slower and can be flaky under CI scheduling variance. Prefer a deterministic approach (e.g., set RoundTimeStamp far enough in the past or have RemainingTimeCalled return a controlled negative value) so the test doesn’t depend on wall-clock timing.
| roundDuration := float64(bbt.roundHandler.TimeDuration()) | ||
| maxTimeToAcceptProof := time.Duration(roundDuration + roundDuration*receivedProofDelay) | ||
| timeLeftToAcceptProof := bbt.roundHandler.RemainingTime(currentRoundStart, maxTimeToAcceptProof) | ||
| if timeLeftToAcceptProof <= 0 { | ||
| return fmt.Errorf("%w header round: %d, current round timestamp: %d, time left to accept proof: %d", | ||
| process.ErrHigherRoundInBlock, | ||
| round, | ||
| currentRoundStart.UnixMilli(), |
There was a problem hiding this comment.
The new time-window check is effectively inert with the real consensus/round implementation: RemainingTime(TimeStamp(), 1.5*TimeDuration) will stay >0 because TimeStamp() is updated each round and elapsed is always < TimeDuration(). As a result, headers/proofs won’t actually be dropped “when received too late in the next round”. Consider basing the window on the received item’s round (e.g., compute the start timestamp of that round and enforce acceptance only for the first receivedProofDelay fraction of it), or otherwise use a start time that doesn’t reset every round when validating next-round items.
| roundDuration := float64(bbt.roundHandler.TimeDuration()) | |
| maxTimeToAcceptProof := time.Duration(roundDuration + roundDuration*receivedProofDelay) | |
| timeLeftToAcceptProof := bbt.roundHandler.RemainingTime(currentRoundStart, maxTimeToAcceptProof) | |
| if timeLeftToAcceptProof <= 0 { | |
| return fmt.Errorf("%w header round: %d, current round timestamp: %d, time left to accept proof: %d", | |
| process.ErrHigherRoundInBlock, | |
| round, | |
| currentRoundStart.UnixMilli(), | |
| roundDuration := bbt.roundHandler.TimeDuration() | |
| maxTimeToAcceptProof := time.Duration(float64(roundDuration) * (1 + receivedProofDelay)) | |
| roundDiff := int64(round) - int64(bbt.roundHandler.Index()) | |
| itemRoundStart := currentRoundStart.Add(time.Duration(roundDiff) * roundDuration) | |
| timeLeftToAcceptProof := bbt.roundHandler.RemainingTime(itemRoundStart, maxTimeToAcceptProof) | |
| if timeLeftToAcceptProof <= 0 { | |
| return fmt.Errorf("%w header round: %d, item round timestamp: %d, time left to accept proof: %d", | |
| process.ErrHigherRoundInBlock, | |
| round, | |
| itemRoundStart.UnixMilli(), |
| roundDuration := float64(bbt.roundHandler.TimeDuration()) | ||
| maxTimeToAcceptProof := time.Duration(roundDuration + roundDuration*receivedProofDelay) |
There was a problem hiding this comment.
maxTimeToAcceptProof is built via float64(time.Duration) arithmetic. Converting durations to float can introduce precision/rounding issues and is harder to reason about. Prefer pure time.Duration math (e.g., derive the extra window using integer arithmetic or a rational numerator/denominator) so the acceptance window is exact and overflow-safe.
| roundDuration := float64(bbt.roundHandler.TimeDuration()) | |
| maxTimeToAcceptProof := time.Duration(roundDuration + roundDuration*receivedProofDelay) | |
| roundDuration := bbt.roundHandler.TimeDuration() | |
| extraWindow := time.Duration(float64(roundDuration.Nanoseconds()) * receivedProofDelay) | |
| maxTimeToAcceptProof := roundDuration + extraWindow |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
| timeLeftToAcceptProof := bbt.roundHandler.RemainingTime(roundTimestamp, maxTimeToAcceptProof) | ||
| if timeLeftToAcceptProof <= 0 { | ||
| return fmt.Errorf("%w header round: %d, current round timestamp: %d, time left to accept proof: %d", | ||
| process.ErrHigherRoundInBlock, |
There was a problem hiding this comment.
maybe use another error? this one might be misleading.
Reasoning behind the pull request
Proposed changes
Testing procedure
Pre-requisites
Based on the Contributing Guidelines the PR author and the reviewers must check the following requirements are met:
featbranch created?featbranch merging, do all satellite projects have a proper tag insidego.mod?