Skip to content

fix(eth/bft): read handler test counters with atomic loads, close #2793 - #2802

Merged
gzliudan merged 1 commit into
XinFinOrg:dev-upgradefrom
gzliudan:fix-issue-2793
Oct 20, 2026
Merged

gzliudan merged 1 commit into
XinFinOrg:dev-upgradefrom
gzliudan:fix-issue-2793

Conversation

@gzliudan

@gzliudan gzliudan commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

The eth/bft handler tests keep their expectations in counters that the broadcast handlers increment with atomic.AddUint32 from the Bfter.loop goroutines, while the assertions read them with plain loads. The test goroutine therefore races with the handlers it just triggered, and go test -race reports four data races and fails TestSequentialVotes, TestTimeoutHandler, TestSyncInfoHandler and TestTooFarTimeout. Which of them fail depends on when the race reports land, so the failing set varies between runs.

Read every counter with atomic.LoadUint32 in the assertions -- both in the if conditions (keeping the int(...) conversion the int targets need) and in the t.Fatalf arguments. The increment sites stay as they are. Only eth/bft/bft_handler_test.go is touched, +20/-20.

eth/bft has no counterpart in go-ethereum: git ls-tree HEAD eth/ in geth master lists no bft entry, and a case-insensitive grep over the master tree finds nothing. The code entered this fork with a1b77f3ca8 (XDPoSChain PR #13, 2021-11-06), whose eth/bfter/bft_test.go ships the identical plain-read pattern. There is no upstream fix to port.

With this merged, eth/bft no longer needs the exclusion the race job of #2797 currently carries.

Evidence

  • Before: go test -race -short -count=1 ./eth/bft/ reports four data races at bft_handler_test.go:92 (TestSequentialVotes), :236 (TestTimeoutHandler), :288 (TestSyncInfoHandler) and :363 (TestTooFarTimeout), each reading a location last written by sync/atomic.AddUint32 in Bfter.loop; all four tests fail. The failing set is timing-dependent: at -count=3 only three of them fail.
  • After: go test -race -short -count=3 ./eth/bft/ exits 0 with no race reports.

Validation

  • make all exits 0.
  • make quick-test exits 0: 127 packages ok, 0 failures.
  • go test -race -short -count=3 ./eth/bft/ exits 0, no WARNING: DATA RACE (4G memory-capped scope).
  • gofmt / goimports: clean.

Merge Danger

Door: two-way -- test-only change; git revert restores the previous assertions byte for byte.

Blast Radius: none -- no production code is touched, and the assertions now read exactly the values the handlers wrote.

Closes #2793.

@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7bafc12e-bc1f-495e-9523-c35ebf85ea96

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@gzliudan gzliudan changed the title fix(eth/bft): read handler test counters with atomic loads fix(eth/bft): read handler test counters with atomic loads, close #2793 Oct 14, 2026
@gzliudan
gzliudan force-pushed the fix-issue-2793 branch 2 times, most recently from 81e396b to 6256e14 Compare October 18, 2026 12:35
…FinOrg#2793

The handler tests increment their counters with atomic.AddUint32 from
the Bfter.loop goroutines, but the assertions read them with plain
loads, so the test goroutine races with the broadcast handlers it just
triggered: go test -race reports four data races (bft_handler_test.go:92,
:236, :288 and :363) and fails TestSequentialVotes, TestTimeoutHandler,
TestSyncInfoHandler and TestTooFarTimeout. Which of them fail depends on
when the race reports land, so the failing set varies between runs.

Read every counter with atomic.LoadUint32 in the assertions, both in
the conditions and in the t.Fatalf arguments; the increment sites are
left untouched.

go-ethereum never had a bft package (git ls-tree HEAD eth/ lists no bft
entry, and a case-insensitive grep over the master tree finds nothing),
so there is nothing upstream to port. The code entered this fork with
a1b77f3 (XDPoSChain PR XinFinOrg#13, 2021-11-06), whose eth/bfter/bft_test.go
carries the same plain-read pattern.

Closes XinFinOrg#2793
@gzliudan
gzliudan merged commit ffbeb5d into XinFinOrg:dev-upgrade Oct 20, 2026
14 checks passed
@gzliudan
gzliudan deleted the fix-issue-2793 branch October 20, 2026 07:03
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 20, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a step of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched.
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 20, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a step of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched.
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 20, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a step of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched.
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 20, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a step of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

make race-test runs the same two passes, rpc last and on its own, so a local
sweep predicts the job. It does not pass -failfast: the sweep exists to report
every race in one go, and the first failing package would stop the rest.

The bulk pass also collects its package list before testing it: a command
substitution sitting in an argument list drops its exit status, so a package
that failed to load would be dropped from the run in silence.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched.
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 20, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a step of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

make race-test runs the same two passes, rpc last and on its own, so a local
sweep predicts the job. It does not pass -failfast: the sweep exists to report
every race in one go, and the first failing package would stop the rest.

-short leaves out the long consensus cases (skipLongInShortMode under
consensus/tests/engine_v2_tests), the discover UDP/lookup cases and the tests/
performance cases. The plain shards run those without the detector, so
make race-test-full exists for the local sweep a change to those paths needs.

Both the job and make race-test collect the package list before testing it:
an argument list drops the substitution's exit status, and an empty list sends
build/ci.go back to ./... with rpc in it. make runs the recipe with /bin/sh,
which has no pipefail, so its guard covers go list failing outright; a partial
failure still leaves every package path in the list, where go test reports it.

tag_build now waits for the race job as well, so a release artifact cannot
ship with a known race. devnet_build_push keeps waiting for tests only: it
fires on every merge, and a flaky detector would hold up the devnet image each
time.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched. make race-test
against baf6d16 reports rc=0 with zero DATA RACE (rpc 23.0s, trie 48.8s),
and pointing the recipe at a go that cannot list makes it exit instead of
testing the whole tree.
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 22, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a step of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

make race-test runs the same two passes, rpc last and on its own, so a local
sweep predicts the job. It does not pass -failfast: the sweep exists to report
every race in one go, and the first failing package would stop the rest.

-short leaves out the long consensus cases (skipLongInShortMode under
consensus/tests/engine_v2_tests), the discover UDP/lookup cases and the tests/
performance cases. The plain shards run those without the detector, so
make race-test-full exists for the local sweep a change to those paths needs.

Both the job and make race-test collect the package list before testing it:
an argument list drops the substitution's exit status, and an empty list sends
build/ci.go back to ./... with rpc in it. make runs the recipe with /bin/sh,
which has no pipefail, so its guard covers go list failing outright; a partial
failure still leaves every package path in the list, where go test reports it.

tag_build now waits for the race job as well, so a release artifact cannot
ship with a known race. devnet_build_push keeps waiting for tests only: it
fires on every merge, and a flaky detector would hold up the devnet image each
time.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched. make race-test
against baf6d16 reports rc=0 with zero DATA RACE (rpc 23.0s, trie 48.8s),
and pointing the recipe at a go that cannot list makes it exit instead of
testing the whole tree.
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 23, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a step of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

make race-test runs the same two passes, rpc last and on its own, so a local
sweep predicts the job. It does not pass -failfast: the sweep exists to report
every race in one go, and the first failing package would stop the rest.

-short leaves out the long consensus cases (skipLongInShortMode under
consensus/tests/engine_v2_tests), the discover UDP/lookup cases and the tests/
performance cases. The plain shards run those without the detector, so
make race-test-full exists for the local sweep a change to those paths needs.

Both the job and make race-test collect the package list before testing it:
an argument list drops the substitution's exit status, and an empty list sends
build/ci.go back to ./... with rpc in it. make runs the recipe with /bin/sh,
which has no pipefail, so its guard covers go list failing outright; a partial
failure still leaves every package path in the list, where go test reports it.

tag_build now waits for the race job as well, so a release artifact cannot
ship with a known race. devnet_build_push keeps waiting for tests only: it
fires on every merge, and a flaky detector would hold up the devnet image each
time.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched. make race-test
against baf6d16 reports rc=0 with zero DATA RACE (rpc 23.0s, trie 48.8s),
and pointing the recipe at a go that cannot list makes it exit instead of
testing the whole tree.
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 26, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a step of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

make race-test runs the same two passes, rpc last and on its own, so a local
sweep predicts the job. It does not pass -failfast: the sweep exists to report
every race in one go, and the first failing package would stop the rest.

-short leaves out the long consensus cases (skipLongInShortMode under
consensus/tests/engine_v2_tests), the discover UDP/lookup cases and the tests/
performance cases. The plain shards run those without the detector, so
make race-test-full exists for the local sweep a change to those paths needs.

Both the job and make race-test collect the package list before testing it:
an argument list drops the substitution's exit status, and an empty list sends
build/ci.go back to ./... with rpc in it. make runs the recipe with /bin/sh,
which has no pipefail, so its guard covers go list failing outright; a partial
failure still leaves every package path in the list, where go test reports it.

tag_build now waits for the race job as well, so a release artifact cannot
ship with a known race. devnet_build_push keeps waiting for tests only: it
fires on every merge, and a flaky detector would hold up the devnet image each
time.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched. make race-test
against baf6d16 reports rc=0 with zero DATA RACE (rpc 23.0s, trie 48.8s),
and pointing the recipe at a go that cannot list makes it exit instead of
testing the whole tree.
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 26, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a step of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

make race-test runs the same two passes, rpc last and on its own, so a local
sweep predicts the job. It does not pass -failfast: the sweep exists to report
every race in one go, and the first failing package would stop the rest.

-short leaves out the long consensus cases (skipLongInShortMode under
consensus/tests/engine_v2_tests), the discover UDP/lookup cases and the tests/
performance cases. The plain shards run those without the detector, so
make race-test-full exists for the local sweep a change to those paths needs.

Both the job and make race-test collect the package list before testing it:
an argument list drops the substitution's exit status, and an empty list sends
build/ci.go back to ./... with rpc in it. make runs the recipe with /bin/sh,
which has no pipefail, so its guard covers go list failing outright; a partial
failure still leaves every package path in the list, where go test reports it.

tag_build now waits for the race job as well, so a release artifact cannot
ship with a known race. devnet_build_push keeps waiting for tests only: it
fires on every merge, and a flaky detector would hold up the devnet image each
time.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched. make race-test
against baf6d16 reports rc=0 with zero DATA RACE (rpc 23.0s, trie 48.8s),
and pointing the recipe at a go that cannot list makes it exit instead of
testing the whole tree.
@benjamin202410 benjamin202410 mentioned this pull request Oct 26, 2026
13 of 25 tasks
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 27, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a step of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

make race-test runs the same two passes, rpc last and on its own, so a local
sweep predicts the job. It does not pass -failfast: the sweep exists to report
every race in one go, and the first failing package would stop the rest.

-short leaves out the long consensus cases (skipLongInShortMode under
consensus/tests/engine_v2_tests), the discover UDP/lookup cases and the tests/
performance cases. The plain shards run those without the detector, so
make race-test-full exists for the local sweep a change to those paths needs.

Both the job and make race-test collect the package list before testing it:
an argument list drops the substitution's exit status, and an empty list sends
build/ci.go back to ./... with rpc in it. make runs the recipe with /bin/sh,
which has no pipefail, so its guard covers go list failing outright; a partial
failure still leaves every package path in the list, where go test reports it.

tag_build now waits for the race job as well, so a release artifact cannot
ship with a known race. devnet_build_push keeps waiting for tests only: it
fires on every merge, and a flaky detector would hold up the devnet image each
time.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched. make race-test
against baf6d16 reports rc=0 with zero DATA RACE (rpc 23.0s, trie 48.8s),
and pointing the recipe at a go that cannot list makes it exit instead of
testing the whole tree.
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 27, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a step of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

The job calls make race-test-bulk and then race-test-rpc, so the two passes,
the rpc carve-out and the package list are defined in one place, and
make race-test runs exactly what CI runs: a local sweep predicts the job. It
does not pass -failfast: the sweep exists to report every race in one go, and
the first failing package would stop the rest. AGENTS.md mentions the target
in its test checklist.

-short leaves out the long consensus cases (skipLongInShortMode under
consensus/tests/engine_v2_tests), the discover UDP/lookup cases and the tests/
performance cases. The plain shards run those without the detector, so
make race-test-full exists for the local sweep a change to those paths needs.

The target collects the package list before testing it: an argument list
drops the substitution's exit status, and an empty list sends build/ci.go
back to ./... with rpc in it. make runs the recipe with /bin/sh, which has no
pipefail, so the guard covers go list failing outright; a partial failure
still leaves every package path in the list, where go test reports it.

tag_build now waits for the race job as well, so a release artifact cannot
ship with a known race. devnet_build_push keeps waiting for tests only: it
fires on every merge, and a flaky detector would hold up the devnet image each
time.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched. make race-test
against baf6d16 reports rc=0 with zero DATA RACE (rpc 23.0s, trie 48.8s),
and pointing the recipe at a go that cannot list makes it exit instead of
testing the whole tree.
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 27, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a slice of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

The job runs four slices of the bulk pass in parallel and then race-test-rpc,
and the shard split, the rpc carve-out and the package list live in the
Makefile, so make race-test (a single shard) runs exactly what CI runs and a
local sweep predicts the job. It does not pass -failfast: the sweep exists to
report every race in one go, and the first failing package would stop the
rest. AGENTS.md mentions the target in its test checklist.

Four slices because the detector makes the pass compile-bound: one job spent
8m28s on the 752s of test time that a twelve-core laptop covers in 5m38s. A
slice is the name-sorted package list taken modulo four, 32 packages each,
with -p 4 overlapping whatever shares one; side by side here they took 46s,
76s, 97s and 122s. actions/cache restores ~/.cache/go-build per slice, since
each slice would otherwise recompile the dependency graph with the
instrumentation. That cache also holds go's test results, so a slice reports
a previous verdict for packages whose inputs did not move. Only packages with
test files are listed: the other 70 would add build time and no coverage.

-short leaves out the long consensus cases (skipLongInShortMode under
consensus/tests/engine_v2_tests), the discover UDP/lookup cases and the tests/
performance cases. The plain shards run those without the detector, so
make race-test-full exists for the local sweep a change to those paths needs.

The target collects the package list before testing it: an argument list
drops the substitution's exit status, and an empty slice would send
build/ci.go back to ./... with rpc in it, so the slice is checked before it
is used. make runs the recipe with /bin/sh, which has no pipefail, so that
check is what covers go list failing outright.

tag_build now waits for the race job as well, so a release artifact cannot
ship with a known race. devnet_build_push keeps waiting for tests only: it
fires on every merge, and a flaky detector would hold up the devnet image each
time.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched. make race-test
against baf6d16 reports rc=0 with zero DATA RACE (rpc 23.0s, trie 48.8s),
and pointing the recipe at a go that cannot list makes it exit instead of
testing the whole tree. With the shards and the cache in place, the four
slices run side by side report rc=0 and zero DATA RACE (46s/76s/97s/122s),
their union equals the unsharded list, and an out-of-range slice exits before
testing anything.
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 27, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a slice of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

The job runs four slices of the bulk pass in parallel and then race-test-rpc,
and the shard split, the rpc carve-out and the package list live in the
Makefile, so make race-test (a single shard) runs exactly what CI runs and a
local sweep predicts the job. It does not pass -failfast: the sweep exists to
report every race in one go, and the first failing package would stop the
rest. AGENTS.md mentions the target in its test checklist.

Four slices because the detector makes the pass compile-bound: one job spent
8m28s on the 752s of test time that a twelve-core laptop covers in 5m38s. A
slice is the name-sorted package list taken modulo four, 32 packages each,
with -p 4 overlapping whatever shares one; side by side here they took 46s,
76s, 97s and 122s. actions/cache restores ~/.cache/go-build per slice,
keyed by the dependency hash rather than the commit, so a slice refills when
go.sum moves instead of once per push: an entry is 660 MB unpacked and 156 MB
stored, and five of them fit inside the 10 GB a repository may cache. That
cache also holds go's test results, so a slice reports a previous verdict for
packages whose inputs did not move. Only packages with
test files are listed: the other 70 would add build time and no coverage.

-short leaves out the long consensus cases (skipLongInShortMode under
consensus/tests/engine_v2_tests), the discover UDP/lookup cases and the tests/
performance cases. The plain shards run those without the detector, so
make race-test-full exists for the local sweep a change to those paths needs.

The target collects the package list before testing it: an argument list
drops the substitution's exit status, and an empty slice would send
build/ci.go back to ./... with rpc in it, so the slice is checked before it
is used. make runs the recipe with /bin/sh, which has no pipefail, so that
check is what covers go list failing outright.

tag_build now waits for the race job as well, so a release artifact cannot
ship with a known race. devnet_build_push keeps waiting for tests only: it
fires on every merge, and a flaky detector would hold up the devnet image each
time.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched. make race-test
against baf6d16 reports rc=0 with zero DATA RACE (rpc 23.0s, trie 48.8s),
and pointing the recipe at a go that cannot list makes it exit instead of
testing the whole tree. With the shards and the cache in place, the four
slices run side by side report rc=0 and zero DATA RACE (46s/76s/97s/122s),
their union equals the unsharded list, and an out-of-range slice exits before
testing anything.
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 27, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a slice of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

The job runs four slices of the bulk pass in parallel and then race-test-rpc,
and the shard split, the rpc carve-out and the package list live in the
Makefile, so make race-test (a single shard) runs exactly what CI runs and a
local sweep predicts the job. It does not pass -failfast: the sweep exists to
report every race in one go, and the first failing package would stop the
rest. AGENTS.md mentions the target in its test checklist.

Four slices because the detector makes the pass compile-bound: one job spent
8m28s on the 752s of test time that a twelve-core laptop covers in 5m38s. A
slice is the name-sorted package list taken modulo four, 32 packages each,
with -p 4 overlapping whatever shares one; side by side here they took 46s,
76s, 97s and 122s. actions/cache restores ~/.cache/go-build per slice,
keyed by the dependency hash rather than the commit, so a slice refills when
go.sum moves instead of once per push: an entry is 660 MB unpacked and 156 MB
stored, and five of them fit inside the 10 GB a repository may cache. That
cache also holds go's test results, so a slice reports a previous verdict for
packages whose inputs did not move. Only packages with
test files are listed: the other 70 would add build time and no coverage.

-short leaves out the long consensus cases (skipLongInShortMode under
consensus/tests/engine_v2_tests), the discover UDP/lookup cases and the tests/
performance cases. The plain shards run those without the detector, so
make race-test-full exists for the local sweep a change to those paths needs.

The target collects the package list before testing it: an argument list
drops the substitution's exit status, and an empty slice would send
build/ci.go back to ./... with rpc in it, so the slice is checked before it
is used. make runs the recipe with /bin/sh, which has no pipefail, so that
check is what covers go list failing outright.

tag_build now waits for the race job as well, so a release artifact cannot
ship with a known race. devnet_build_push keeps waiting for tests only: it
fires on every merge, and a flaky detector would hold up the devnet image each
time.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched. make race-test
against baf6d16 reports rc=0 with zero DATA RACE (rpc 23.0s, trie 48.8s),
and pointing the recipe at a go that cannot list makes it exit instead of
testing the whole tree. With the shards and the cache in place, the four
slices run side by side report rc=0 and zero DATA RACE (46s/76s/97s/122s),
their union equals the unsharded list, and an out-of-range slice exits before
testing anything.
gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Oct 27, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(XinFinOrg#2700).

Every package the job started out excluding is fixed (XinFinOrg#2791, XinFinOrg#2793 by
XinFinOrg#2802, XinFinOrg#2794) or gone with the package (XinFinOrg#2792, whose disposition was
deletion via XinFinOrg#2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: XinFinOrg#2795 (fixed by XinFinOrg#2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a slice of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

The job runs four slices of the bulk pass in parallel and then race-test-rpc,
and the shard split, the rpc carve-out and the package list live in the
Makefile, so make race-test (a single shard) runs exactly what CI runs and a
local sweep predicts the job. It does not pass -failfast: the sweep exists to
report every race in one go, and the first failing package would stop the
rest. AGENTS.md mentions the target in its test checklist.

Four slices because the detector makes the pass compile-bound: one job spent
8m28s on the 752s of test time that a twelve-core laptop covers in 5m38s. A
slice is the name-sorted package list taken modulo four, 32 packages each,
with -p 4 overlapping whatever shares one; side by side here they took 46s,
76s, 97s and 122s. actions/cache restores ~/.cache/go-build per slice,
keyed by the dependency hash rather than the commit, so a slice refills when
go.sum moves instead of once per push: an entry is 660 MB unpacked and 156 MB
stored, and five of them fit inside the 10 GB a repository may cache. That
cache also holds go's test results, so a slice reports a previous verdict for
packages whose inputs did not move. Only packages with
test files are listed: the other 70 would add build time and no coverage.

-short leaves out the long consensus cases (skipLongInShortMode under
consensus/tests/engine_v2_tests), the discover UDP/lookup cases and the tests/
performance cases. The plain shards run those without the detector, so
make race-test-full exists for the local sweep a change to those paths needs.

The target collects the package list before testing it: an argument list
drops the substitution's exit status, and an empty slice would send
build/ci.go back to ./... with rpc in it, so the slice is checked before it
is used. make runs the recipe with /bin/sh, which has no pipefail, so that
check is what covers go list failing outright.

tag_build now waits for the race job as well, so a release artifact cannot
ship with a known race. devnet_build_push keeps waiting for tests only: it
fires on every merge, and a flaky detector would hold up the devnet image each
time.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched. make race-test
against baf6d16 reports rc=0 with zero DATA RACE (rpc 23.0s, trie 48.8s),
and pointing the recipe at a go that cannot list makes it exit instead of
testing the whole tree. With the shards and the cache in place, the four
slices run side by side report rc=0 and zero DATA RACE (46s/76s/97s/122s),
their union equals the unsharded list, and an out-of-range slice exits before
testing anything.
gzliudan added a commit that referenced this pull request Oct 27, 2026
make test, make quick-test and all eight shards of ci.yml call
`go run build/ci.go test`, and none of them passes -race, so an access that
is unsynchronised at run time stays invisible to CI. build/ci.go has carried
the flag since it was ported from geth ethereum#23480 - nothing ever switched it on
(#2700).

Every package the job started out excluding is fixed (#2791, #2793 by
#2802, #2794) or gone with the package (#2792, whose disposition was
deletion via #2796), so the bulk pass now covers the whole tree. metrics no
longer needs a second, non-short run either: #2795 (fixed by #2801) removed
the `testing.Short()` guard from TestUniformSampleConcurrentUpdateCount, so
the short pass reaches it.

rpc gets a slice of its own: the bulk pass runs four packages at a time, and
TestClientWebsocketLargeMessage does not survive that on a GitHub-hosted
runner - twice in a row the job failed after 30.00s with
`websocket: close 1006 (abnormal closure): unexpected EOF`, the websocket
codec's 30s ping/pong watchdog, with no data race reported in either
attempt. The package is green when it does not compete with three other
packages - 26s here, and 24.9s in the plain CI shards, which run one package
at a time - so it leaves the bulk pass, which keeps the detector on the
package instead of dropping it from the job.

The job runs four slices of the bulk pass in parallel and then race-test-rpc,
and the shard split, the rpc carve-out and the package list live in the
Makefile, so make race-test (a single shard) runs exactly what CI runs and a
local sweep predicts the job. It does not pass -failfast: the sweep exists to
report every race in one go, and the first failing package would stop the
rest. AGENTS.md mentions the target in its test checklist.

Four slices because the detector makes the pass compile-bound: one job spent
8m28s on the 752s of test time that a twelve-core laptop covers in 5m38s. A
slice is the name-sorted package list taken modulo four, 32 packages each,
with -p 4 overlapping whatever shares one; side by side here they took 46s,
76s, 97s and 122s. actions/cache restores ~/.cache/go-build per slice,
keyed by the dependency hash rather than the commit, so a slice refills when
go.sum moves instead of once per push: an entry is 660 MB unpacked and 156 MB
stored, and five of them fit inside the 10 GB a repository may cache. That
cache also holds go's test results, so a slice reports a previous verdict for
packages whose inputs did not move. Only packages with
test files are listed: the other 70 would add build time and no coverage.

-short leaves out the long consensus cases (skipLongInShortMode under
consensus/tests/engine_v2_tests), the discover UDP/lookup cases and the tests/
performance cases. The plain shards run those without the detector, so
make race-test-full exists for the local sweep a change to those paths needs.

The target collects the package list before testing it: an argument list
drops the substitution's exit status, and an empty slice would send
build/ci.go back to ./... with rpc in it, so the slice is checked before it
is used. make runs the recipe with /bin/sh, which has no pipefail, so that
check is what covers go list failing outright.

tag_build now waits for the race job as well, so a release artifact cannot
ship with a known race. devnet_build_push keeps waiting for tests only: it
fires on every merge, and a flaky detector would hold up the devnet image each
time.

Verified with the job's command against dev-upgrade 72ed9d6: rc=0, zero
WARNING: DATA RACE, 126 packages ok in 3m49s. rpc on its own is ok in 26.0s,
eth/bft in 1.7s, metrics in 6.6s (the concurrent sample test runs instead of
skipping, 5.3s), make all exits 0, and no .go file is touched. make race-test
against baf6d16 reports rc=0 with zero DATA RACE (rpc 23.0s, trie 48.8s),
and pointing the recipe at a go that cannot list makes it exit instead of
testing the whole tree. With the shards and the cache in place, the four
slices run side by side report rc=0 and zero DATA RACE (46s/76s/97s/122s),
their union equals the unsharded list, and an out-of-range slice exits before
testing anything.
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