fix(e2e): remove epoch gap flakiness - #3445
Conversation
4847826 to
4f65f57
Compare
4f65f57 to
8ad0e8c
Compare
The exponential poll backoff exceeded short devnet epochs, so target epochs could be detected up to a full epoch after their boundary.
A restart crossing an epoch boundary before the current epoch is certified creates an unrecoverable epoch gap that blocks the aggregator.
A single epoch left no slack for certificate sealing latency, causing spurious 'Timeout exhausted waiting for...' failures.
Reduce the number of lotteries played to get closer to the initial parameter set, as the test only needs to exercise the parameters update.
* mithril-end-to-end from `0.5.9` to `0.5.10`
8ad0e8c to
520f12b
Compare
There was a problem hiding this comment.
Pull request overview
This PR reduces intermittent e2e CI failures caused by epoch-boundary timing and aggregator restarts by tightening epoch transition polling, ensuring certificate continuity across restarts, and increasing artifact wait timeouts.
Changes:
- Switch epoch-transition waiting to a constant “tenth of epoch” polling cadence.
- Ensure the current epoch is certified before restarting the aggregator for protocol-parameter updates.
- Increase artifact production timeout to cover up to three epochs and reduce concatenation protocol parameters used during the update.
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| mithril-test-lab/mithril-end-to-end/src/toolkit/wait.rs | Uses the new constant tenth-of-epoch backoff when waiting for target epoch transitions. |
| mithril-test-lab/mithril-end-to-end/src/toolkit/exec.rs | Lightens concatenation protocol parameters used during the update/restart step. |
| mithril-test-lab/mithril-end-to-end/src/toolkit/context.rs | Adds tenth_of_epoch_poll_backoff() and increases artifact production timeout to 3 epochs (plus tests). |
| mithril-test-lab/mithril-end-to-end/src/scenario/full.rs | Adds a pre-restart certification check to prevent unrecoverable epoch gaps. |
| mithril-test-lab/mithril-end-to-end/Cargo.toml | Bumps mithril-end-to-end crate version to 0.5.10. |
| Cargo.lock | Updates lockfile for the mithril-end-to-end version bump. |
| // A certificate chain lagging one epoch behind the chain tip is normal, but a restart | ||
| // crossing an epoch boundary before the current epoch is certified would create an | ||
| // unrecoverable epoch gap and block the aggregator | ||
| let current_epoch = chain_observer.get_current_epoch().await?.unwrap_or_default(); |
| let delay = self.timeout_for_epochs(1) / 10; | ||
| Backoff::new(delay, delay, 1) |
There was a problem hiding this comment.
This is true: https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=c1895e5a63c9bf02f672eb5b6cea6dd1
Maybe we should add a timeout_for_epoch_fraction(&self, fraction: u32) -> Duration to centralize the behavior?
| /// Timeout to wait for the aggregator to produce a signed artifact once it is running. | ||
| pub fn artifact_production_timeout(&self) -> Duration { | ||
| self.timeout_for_epochs(1) | ||
| self.timeout_for_epochs(3) |
There was a problem hiding this comment.
This timeout is also used for is_creating_certificate_with_enough_signers which does not make sense with a timeout of three epochs has the certificate hash is provided so it already exist (the timeout here only make sense to handle http request issues).
So I would change is_creating_certificate_with_enough_signers timeout to use timeout_for_epochs(1) or better a new named timeout method.
| // A certificate chain lagging one epoch behind the chain tip is normal, but a restart | ||
| // crossing an epoch boundary before the current epoch is certified would create an | ||
| // unrecoverable epoch gap and block the aggregator |
There was a problem hiding this comment.
It took me some time to understand the problem solved here, I think that sightly changing the text would make it more clear (with a first line saying the goal achieve, and the rest why we need it)
| // A certificate chain lagging one epoch behind the chain tip is normal, but a restart | |
| // crossing an epoch boundary before the current epoch is certified would create an | |
| // unrecoverable epoch gap and block the aggregator | |
| // Ensure the current epoch is certified | |
| // Given the time needed to restart the aggregator, a restart crossing an epoch | |
| // boundary before the current epoch is certified would create an | |
| // unrecoverable epoch gap and block the aggregator |
| let delay = self.timeout_for_epochs(1) / 10; | ||
| Backoff::new(delay, delay, 1) |
There was a problem hiding this comment.
This is true: https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=c1895e5a63c9bf02f672eb5b6cea6dd1
Maybe we should add a timeout_for_epoch_fraction(&self, fraction: u32) -> Duration to centralize the behavior?
Content
This PR includes the removal of several sources of flakiness in the e2e tests which caused intermittent
Timeout exhausted waiting for Certificate for epoch XXfailures in the CI:The fixed e2e test has been run 381 times with 1 failure, a 99.74% success ratio.
Pre-submit checklist
Issue(s)
Closes #3452