Skip to content

[KLC-2400] fix flaky configITO ShouldError test: slot-relative ITO windows#58

Merged
fbsobreira merged 2 commits into
developfrom
worktree-klc-2400
May 21, 2026
Merged

[KLC-2400] fix flaky configITO ShouldError test: slot-relative ITO windows#58
fbsobreira merged 2 commits into
developfrom
worktree-klc-2400

Conversation

@fbsobreira
Copy link
Copy Markdown
Member

@fbsobreira fbsobreira commented May 21, 2026

Summary

TestTransaction_CreateConfigITO_ShouldError was flaky (~40% failure rate on develop) because it pinned ITO StartTime to time.Now().Add(4s). The KAPP, however, validates ITO windows against ctx.Block().GetTimestamp() (core/kapp/ito/ito.go:660-666), and the test harness computes that as genesis + slot * slotDuration (integrationTest/processorNode/block.go:72) — fully deterministic. When the runner was slow enough that wall-clock drifted past the 4-second cushion, the block-time check StartTime <= block.Timestamp fired and rejected the only configITOTxHash the test expected to succeed.

Fix

Replace wall-clock offsets with slot-relative anchors derived from the proposer's SlotManager:

slotDuration := int64(nodes[xidProposerBlock].SlotManager.TimeDuration().Seconds())
genesisTs   := nodes[xidProposerBlock].SlotManager.Timestamp().Unix()
itoStart    := genesisTs + int64(slot+1)*slotDuration
itoEnd      := itoStart + 1

This guarantees blockTs(slot) < itoStart <= blockTs(slot+1) <= itoEnd < blockTs(slot+2), which is exactly the window the rest of the test (config submission at slot, in-window buys at slot+1, out-of-window buy at slot+2) needs — independent of wall-clock load. Two malformed-time test cases still use deliberately inverted values for start > end validation.

Sibling triggerITO_test.go was audited: it uses day-scale AddDate offsets and isn't affected.

Test plan

  • go test ./integrationTest/transaction/configITO/ -run TestTransaction_CreateConfigITO_ShouldError -count=1 — 20/20 pass in a loop (~270s total); previously ~40% failure rate.
  • Full go test ./integrationTest/transaction/configITO/ -count=1 package — pass.
  • CI green on develop.

Test-Only Reliability Fix (configITO_test.go)

Scope

  • Changes confined to integrationTest/transaction/configITO/configITO_test.go (test code only). No production code modified.

Problem

  • TestTransaction_CreateConfigITO_ShouldError was flaky (~40% failures) because the test used wall-clock offsets (time.Now().Add...) for ITO Start/End timestamps while KAPP validates ITO windows against block timestamps computed from the proposer's SlotManager (slot0 reference + slot*slotDuration). On slow runners a wall-clock StartTime could be ≤ block timestamp and the config ITO got rejected unexpectedly.

Fix

  • All ITO/whitelist times in the problematic test are now derived from the proposer node’s SlotManager:
    • slotDuration := nodes[xidProposerBlock].SlotManager.TimeDuration().Seconds()
    • slot0Ts := nodes[xidProposerBlock].SlotManager.Timestamp().Unix() (renamed from genesisTs)
    • itoStart := slot0Ts + int64(slot+1)*slotDuration
    • itoEnd := slot0Ts + int64(slot+2)*slotDuration - 1 (hardened to ensure itoEnd < blockTs(slot+2))
  • Two negative test cases still use intentionally inverted start/end timestamps to validate error paths.
  • All uses of time.Now().Add(...) for WhitelistStartTime, WhitelistEndTime, StartTime, EndTime in this test were replaced with the deterministic slot-relative values.

Rationale / Invariants

  • Guarantees blockTs(slot) < itoStart ≤ blockTs(slot+1) ≤ itoEnd < blockTs(slot+2), aligning test submission/buy windows with how block timestamps are produced during tests and removing flakiness.

Other edits

  • Renamed variable genesisTs → slot0Ts for clarity.
  • Tightened itoEnd calculation (-1) to avoid equality at block boundary when slotDuration == 1s.

Blockchain-critical impact

  • None to production behavior: consensus, transaction processing, state management, KVM, and networking code remain unchanged.
  • The ITO validation logic in KAPP is not modified — only test inputs were made deterministic.
  • No impact on node stability, data integrity, concurrency, or error handling in runtime code. The change reduces nondeterminism in tests, improving reliability of integration test outcomes.

Test results

  • Targeted test loop: 20/20 passes locally (~270s). Full package tests passed locally. CI run pending.

Review Change Stack

…ndows

The KAPP validates ITO windows against ctx.Block().GetTimestamp(), which
in tests is genesis + slot*slotDuration — fully deterministic. The test
was using time.Now().Add(4s) for StartTime, so on slow runners the
configITO tx landed at a block whose timestamp had already passed
StartTime and was rejected as invalid.

Replace wall-clock offsets with slot-relative anchors so the window
invariant blockTs(slot) < itoStart <= blockTs(slot+1) <= itoEnd <
blockTs(slot+2) holds by construction.

Verified: 20/20 passes in a -count=1 loop (previously ~40% failure on
develop).
Copilot AI review requested due to automatic review settings May 21, 2026 17:43
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 79d6a42d-d7b9-4886-8a30-314ca13bb288

📥 Commits

Reviewing files that changed from the base of the PR and between 2085ca7 and 0e743b5.

📒 Files selected for processing (1)
  • integrationTest/transaction/configITO/configITO_test.go
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: setup-and-lint / setup-and-lint
  • GitHub Check: Analyze (go)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (Custom checks)

**/*.go: Verify that any new or modified concurrent code (goroutines, channels, mutexes, sync primitives) is free of race conditions. Check for: proper lock/unlock pairing, no goroutine leaks, correct channel lifecycle management, and proper context cancellation propagation.
Verify that errors are not silently discarded. Check for: unchecked error returns, error wrapping with context, proper error propagation up the call chain, and no bare panic() calls outside of init() functions.

Files:

  • integrationTest/transaction/configITO/configITO_test.go
**/*_test.go

⚙️ CodeRabbit configuration file

**/*_test.go: Test files. Review for: - Adequate coverage of edge cases and error paths - Proper use of test helpers and assertions - Race condition coverage (tests should use -race flag patterns) - No hardcoded sleep for synchronization (use channels or sync primitives) - Test isolation (no shared mutable state between tests)

Files:

  • integrationTest/transaction/configITO/configITO_test.go
🧠 Learnings (1)
📚 Learning: 2026-04-21T20:12:22.959Z
Learnt from: phcarneirobc
Repo: klever-io/klever-go PR: 38
File: indexer/eventsProcessor.go:188-211
Timestamp: 2026-04-21T20:12:22.959Z
Learning: In Go structs that are JSON-marshaled, if a field is a `bool` and has the `json:"...,omitempty"` tag, then leaving that field at its zero value (`false`) is functionally equivalent (in the resulting JSON) to explicitly setting `Foundation: false`. Reviewers should not flag struct literals that omit such `bool` fields as an inconsistency; they will serialize identically because `omitempty` suppresses `false` values.

Applied to files:

  • integrationTest/transaction/configITO/configITO_test.go
🔇 Additional comments (1)
integrationTest/transaction/configITO/configITO_test.go (1)

198-201: LGTM!

Also applies to: 204-206, 209-214, 216-216


Walkthrough

This PR updates TestTransaction_CreateConfigITO_ShouldError to compute all ITO and whitelist window timestamps from the proposer node's SlotManager (genesis timestamp + slot duration) and uses those deterministic values across all error and success test cases.

Changes

ITO time-window determinism

Layer / File(s) Summary
Deterministic timestamp calculation
integrationTest/transaction/configITO/configITO_test.go
Compute slot-relative itoStart/itoEnd and inverted timestamp pairs from the proposer SlotManager (genesis timestamp + slot duration) for deterministic test windows.
Config ITO test cases with slot-relative timestamps
integrationTest/transaction/configITO/configITO_test.go
Replace all time.Now().Add(...) usages across Config ITO error-case and success-case requests with the precomputed itoStart/itoEnd values; use inverted pairs for the malformed-window negative tests.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 7 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (7 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title follows the required format [KLC-XXXX] type: description with type 'fix', directly summarizes the main change (fixing flaky test via slot-relative ITO windows), and aligns with the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Concurrency Safety ✅ Passed No concurrent code introduced. Reads SlotManager fields once and computes local ITO timestamps. SlotManagerMock uses atomic.Int64 for thread safety. No goroutines, channels, or mutexes added.
Error Handling ✅ Passed All 44 error assignments in the modified test file have corresponding checks. No unchecked errors, error-ignoring patterns, or bare panic() calls detected.
State Consistency ✅ Passed PR modifies only test infrastructure (configITO_test.go), replacing wall-clock timestamps with slot-relative values. No production state-mutation code is touched; check is not applicable.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-klc-2400

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes flakiness in the TestTransaction_CreateConfigITO_ShouldError integration test by eliminating wall-clock-based ITO window timestamps and instead anchoring ITO start/end times to deterministic, slot-relative timestamps derived from the test node’s SlotManager.

Changes:

  • Replace time.Now().Add(...) ITO/whitelist window timestamps with slot-relative timestamps (itoStart, itoEnd) based on SlotManager.Timestamp() and SlotManager.TimeDuration().
  • Keep the two malformed-time cases by using deliberately inverted start/end timestamps computed from the same slot-relative anchors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread integrationTest/transaction/configITO/configITO_test.go Outdated
Comment thread integrationTest/transaction/configITO/configITO_test.go Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@integrationTest/transaction/configITO/configITO_test.go`:
- Line 208: itoEnd is set to itoStart+1 which assumes slotDuration>1s and can
make the "out-of-window at block(slot+2)" case hit the boundary when
slotDuration==1s; change the computation of itoEnd to derive it from the test's
slot boundaries (e.g., use slotDuration or the existing slotStart/slotEnd
variables) so itoEnd = itoStart + slotDuration (or itoEnd = slotEnd) instead of
a fixed +1, and update any assertions that rely on itoEnd to use the new
computed value (look for itoStart, itoEnd, slotDuration and any references to
slotStart/slotEnd in the test).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9dc3a59b-7acc-43e5-990a-fb6301a426eb

📥 Commits

Reviewing files that changed from the base of the PR and between bfd4001 and 2085ca7.

📒 Files selected for processing (1)
  • integrationTest/transaction/configITO/configITO_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Agent
  • GitHub Check: setup-and-lint / setup-and-lint
  • GitHub Check: Analyze (go)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (Custom checks)

**/*.go: Verify that any new or modified concurrent code (goroutines, channels, mutexes, sync primitives) is free of race conditions. Check for: proper lock/unlock pairing, no goroutine leaks, correct channel lifecycle management, and proper context cancellation propagation.
Verify that errors are not silently discarded. Check for: unchecked error returns, error wrapping with context, proper error propagation up the call chain, and no bare panic() calls outside of init() functions.

Files:

  • integrationTest/transaction/configITO/configITO_test.go
**/*_test.go

⚙️ CodeRabbit configuration file

**/*_test.go: Test files. Review for: - Adequate coverage of edge cases and error paths - Proper use of test helpers and assertions - Race condition coverage (tests should use -race flag patterns) - No hardcoded sleep for synchronization (use channels or sync primitives) - Test isolation (no shared mutable state between tests)

Files:

  • integrationTest/transaction/configITO/configITO_test.go
🧠 Learnings (1)
📚 Learning: 2026-04-21T20:12:22.959Z
Learnt from: phcarneirobc
Repo: klever-io/klever-go PR: 38
File: indexer/eventsProcessor.go:188-211
Timestamp: 2026-04-21T20:12:22.959Z
Learning: In Go structs that are JSON-marshaled, if a field is a `bool` and has the `json:"...,omitempty"` tag, then leaving that field at its zero value (`false`) is functionally equivalent (in the resulting JSON) to explicitly setting `Foundation: false`. Reviewers should not flag struct literals that omit such `bool` fields as an inconsistency; they will serialize identically because `omitempty` suppresses `false` values.

Applied to files:

  • integrationTest/transaction/configITO/configITO_test.go
🔇 Additional comments (1)
integrationTest/transaction/configITO/configITO_test.go (1)

198-207: LGTM!

Also applies to: 209-212, 229-232, 251-254, 273-276, 295-298, 317-320, 339-342, 361-364, 383-386, 405-408, 427-430, 449-452, 471-474, 493-496, 515-518, 537-540

Comment thread integrationTest/transaction/configITO/configITO_test.go Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 21, 2026
- Rename genesisTs → slot0Ts; the value is the proposer's slot-0 reference
  (SlotManagerMock captures time.Now() at node construction in block.go),
  not actual chain genesis. Tighten the explanatory comment to match.
- Change itoEnd to slot0Ts + (slot+2)*slotDuration - 1 so the invariant
  itoEnd < blockTs(slot+2) holds regardless of slotDuration. With the
  previous +1, a 1s slotDuration would land itoEnd exactly at blockTs(slot+2)
  and the final "out of window" buy would silently pass the strict-less-than
  check at ito.go:336-337.
@fbsobreira fbsobreira merged commit ea94830 into develop May 21, 2026
7 checks passed
@fbsobreira fbsobreira deleted the worktree-klc-2400 branch May 21, 2026 19:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants