Skip to content

[Testing] Fix races and bugs found by flaky tests - #8633

Open
janezpodhostnik wants to merge 5 commits into
masterfrom
janez/fix-flaky-tests-production-races
Open

[Testing] Fix races and bugs found by flaky tests#8633
janezpodhostnik wants to merge 5 commits into
masterfrom
janez/fix-flaky-tests-production-races

Conversation

@janezpodhostnik

@janezpodhostnik janezpodhostnik commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Fixes bugs discovered while stress-running the full unit test suite (500+ full-suite runs plus per-test -race stress runs, continuing the work from #8626).

Changes

  • herocache: Cache.get stopped scanning a bucket when it hit a slot whose value was ejected but whose stale 32-bit id prefix collided with the queried key, reporting a present entity as missing. Now continues scanning. Includes a deterministic regression test (verified to fail before the fix).
  • optimistic sync pipeline: Run unconditionally stored the initial parent state and could overwrite a concurrently delivered OnParentStateUpdated, losing the update and deadlocking the pipeline (it would never observe StateComplete and never persist). Run now initializes with CompareAndSwap from StatePending, and OnParentStateUpdated uses an unconditional store so updates cannot be silently dropped. Includes the pipeline test harness fixes this change interlocks with.
  • grpcserver: when shutdown wins the window between ready() and Serve, Serve returns ErrServerStopped, which was thrown as an irrecoverable error during a normal shutdown. Now excluded explicitly (gRPC returns nil when stopped while serving, so the exclusion is precise).
  • ALSP SpamRecordCache: Get copied record fields and AdjustWithInit read the adjusted penalty after the backend lock was released, racing in-place record mutations. Both now read under the lock.
  • slashing consumer: logOffense mutated the caller's Violation (defaulting MsgType), racing concurrent use of the same violation. Uses a local variable now.
  • gossipsub scoring: silencePeriodStartTime (multi-word time.Time) was written by the startup worker while the score function read it concurrently, now an atomic pointer. AppSpecificScoreCache and SubscriptionRecordCache mutated records in place while Get reads fields outside the lock, both use copy-on-write now.
  • RPC inspector: inspectRpcPublishMessages shuffled the live RPC's publish message slice on worker goroutines while libp2p pubsub still reads the same RPC. Now samples a shallow clone.

All fixes verified with 20-100x -race stress runs per affected package. network/alsp/..., network/p2p/scoring/..., and consensus/hotstuff/integration are now fully race-clean.

Related: #8626, #8629

Follow-up PRs will add dedicated regression tests for paths that still lack deterministic coverage (grpcserver shutdown race, slashing consumer, pipeline initialization race).


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Summary by CodeRabbit

  • Bug Fixes
    • Improved synchronization so concurrent state updates are preserved reliably.
    • Fixed cache lookups that could incorrectly report misses after entries were evicted.
    • Improved safety and consistency when updating network scoring and subscription data.
    • Prevented shared message data from being modified during validation.
    • Corrected shutdown handling so normal server stops are not reported as fatal errors.
    • Improved registry startup handling and prevented unintended changes to recorded offense details.
  • Tests
    • Expanded regression coverage for cache collisions, pipeline state transitions, and shutdown behavior.

@janezpodhostnik
janezpodhostnik requested a review from a team as a code owner August 3, 2026 13:54
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The changes address concurrent state updates, cache lookup and record ownership, gRPC shutdown handling, atomic registry startup state, asynchronous test behavior, and slashing message-type handling.

Changes

Optimistic sync pipeline

Layer / File(s) Summary
Pipeline state handling and test synchronization
module/executiondatasync/optimistic_sync/pipeline/*
Parent-state updates now preserve concurrent values and always notify. Tests register asynchronous mock expectations earlier, allow expected cancellation errors, and use longer state and error wait timeouts.

Shared cache and record safety

Layer / File(s) Summary
Hero cache collision lookup
module/mempool/herocache/backdata/*
Lookup continues past stale prefix matches. A regression test covers colliding identifiers in ejected slots.
ALSP backend access
network/alsp/internal/cache.go
Penalty values are captured while locked. Record lookup and copying run inside Backend.Run.
Scoring cache copy-on-write
network/p2p/scoring/internal/*Cache.go
Score and subscription updates replace records instead of mutating shared records or topic slices.
Inspector message sampling
network/p2p/inspector/validation/control_message_validation_inspector.go
Sampling uses a cloned publish-message slice.

Server and registry lifecycle handling

Layer / File(s) Summary
gRPC shutdown error handling
module/grpcserver/server.go
grpc.ErrServerStopped is excluded from fatal serve errors.
Registry startup state
network/p2p/scoring/registry.go
Startup time uses an atomic pointer. Repeated startup is rejected, and silence checks handle an unstarted registry.

Slashing offense logging

Layer / File(s) Summary
Local offense message type
network/slashing/consumer.go
Empty message types default to a local unknown value for logging and metrics without modifying the violation.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • onflow/flow-go#8626: Both PRs update optimistic sync functional tests and test utilities for asynchronous state and error handling.

Suggested reviewers: zhangchiqing, kay-zee

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the pull request's primary focus on fixing race conditions and bugs identified by flaky tests.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch janez/fix-flaky-tests-production-races

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@janezpodhostnik janezpodhostnik changed the title Fix production races and bugs found by flaky test campaigns [Testing] Fix races and bugs found by flaky tests Aug 4, 2026
@janezpodhostnik janezpodhostnik self-assigned this Aug 4, 2026
Base automatically changed from janez/flaky-test-followup-evm-registers to master August 4, 2026 15:25
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@codecov-commenter

codecov-commenter commented Aug 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.70175% with 11 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
network/slashing/consumer.go 0.00% 5 Missing ⚠️
network/p2p/scoring/registry.go 62.50% 1 Missing and 2 partials ⚠️
network/alsp/internal/cache.go 89.47% 1 Missing and 1 partial ⚠️
module/grpcserver/server.go 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@network/alsp/internal/cache.go`:
- Around line 126-129: Replace the panic call in the error handler that logs
"unexpected error while getting spam record from cache" with
irrecoverable.NewExceptionf(...) instead, using the same descriptive error
message. This ensures backend faults in the cache are handled consistently
through Flow's exception mechanism rather than bypassing it with a raw panic.

In `@network/p2p/scoring/registry.go`:
- Around line 192-196: Update the startup guard around silencePeriodStartTime to
use CompareAndSwap(nil, &now) as an atomic one-shot initialization; if the swap
fails, return immediately from the current worker instead of calling
parent.Throw or continuing toward ready(). Preserve the timestamp initialization
and startup behavior for the winning worker.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5bbe8b0d-3d8c-4daa-a2a0-b6dd5de7c161

📥 Commits

Reviewing files that changed from the base of the PR and between 1d9475f and 14ad9df.

📒 Files selected for processing (13)
  • module/executiondatasync/optimistic_sync/pipeline/pipeline.go
  • module/executiondatasync/optimistic_sync/pipeline/pipeline_functional_test.go
  • module/executiondatasync/optimistic_sync/pipeline/pipeline_test.go
  • module/executiondatasync/optimistic_sync/pipeline/pipeline_test_utils.go
  • module/grpcserver/server.go
  • module/mempool/herocache/backdata/cache.go
  • module/mempool/herocache/backdata/cache_test.go
  • network/alsp/internal/cache.go
  • network/p2p/inspector/validation/control_message_validation_inspector.go
  • network/p2p/scoring/internal/appSpecificScoreCache.go
  • network/p2p/scoring/internal/subscriptionCache.go
  • network/p2p/scoring/registry.go
  • network/slashing/consumer.go

Comment on lines +126 to +129
if err != nil {
// the Run closure above never returns an error; an error here indicates a bug in the
// backend implementation.
panic(fmt.Errorf("unexpected error while getting spam record from cache: %w", err))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)cache\.go$|module/component/component\.go|irrecoverable|docs/agents/(CodingConventions|GoDocs)\.md' || true

echo "== target snippet =="
if [ -f network/alsp/internal/cache.go ]; then
  sed -n '1,220p' network/alsp/internal/cache.go | nl -ba | sed -n '1,220p'
fi

echo "== irrecoverable usage examples =="
rg -n "irrecoverable|panic\(fmt\.Errorf|panic\(" -S --glob '*.go' . | head -200

Repository: onflow/flow-go

Length of output: 1148


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== read docs guidelines =="
for f in docs/agents/CodingConventions.md docs/agents/GoDocs.md; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    cat -n "$f"
  else
    echo "missing $f"
  fi
done

Repository: onflow/flow-go

Length of output: 28678


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== target file =="
awk '{printf "%6d\t%s\n", NR, $0}' network/alsp/internal/cache.go | sed -n '1,240p'

echo "== irrecoverable package =="
awk '{printf "%6d\t%s\n", NR, $0}' module/irrecoverable/exception.go | sed -n '1,240p'
awk '{printf "%6d\t%s\n", NR, $0}' module/irrecoverable/irrecoverable.go | sed -n '1,240p'

echo "== irrecoverable import/usages in network/alsp/internal/cache.go and neighboring alsp cache files =="
rg -n 'irrecoverable|panic\(fmt\.Errorf|fmt\.Errorf|No error returns are expected|Unexpected error' network/alsp -S network/alsp -S || true

echo "== component interface =="
awk '{printf "%6d\t%s\n", NR, $0}' module/component/component.go | sed -n '1,240p'

Repository: onflow/flow-go

Length of output: 34983


Use irrecoverable exceptions for backend faults.

This cache documents returned errors as irrecoverable bugs, but panic(fmt.Errorf(...)) bypasses Flow’s exception mechanism. Use irrecoverable.NewExceptionf(...) here or refactor the cache methods to return exceptions consistently.

🤖 Prompt for 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.

In `@network/alsp/internal/cache.go` around lines 126 - 129, Replace the panic
call in the error handler that logs "unexpected error while getting spam record
from cache" with irrecoverable.NewExceptionf(...) instead, using the same
descriptive error message. This ensures backend faults in the cache are handled
consistently through Flow's exception mechanism rather than bypassing it with a
raw panic.

Source: Coding guidelines

Comment thread network/p2p/scoring/registry.go
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.

2 participants