Skip to content

feat: stop transaction rebroadcast while syncing - #2397

Draft
vbhattaccmu wants to merge 5 commits into
developfrom
vbhattac/disable-unsynced-rebroadcast
Draft

feat: stop transaction rebroadcast while syncing#2397
vbhattaccmu wants to merge 5 commits into
developfrom
vbhattac/disable-unsynced-rebroadcast

Conversation

@vbhattaccmu

Copy link
Copy Markdown
Contributor

Summary

Stops stuck-transaction rebroadcasting as soon as chain sync detects a higher-TD peer, and re-enables it only after a successful sync. This keeps the existing initial-sync transaction-acceptance behavior separate while preventing halted or lagging nodes from clearing every peer’s known-transaction cache and re-announcing stale transactions. Adds a repeatable local Kurtosis hard-fork-stall and netem-delay scenario.

Executed tests

  • make test
  • make test-integration
  • go test -race ./eth -count=1 -timeout=20m
  • make lint-deps && make lint (0 issues)
  • Diffguard with mutation testing: 100% (2/2 killed)
  • docker build -t bor:local --file Dockerfile .
  • Local Kurtosis scenario: current nodes advanced past block 150 while Bor v2.9.0 halted at block 127 on the Austin boundary; with 1.5s netem delay and a seeded pending transaction, the halted node identified 5 stuck batches and emitted 2 rebroadcast batches in 45 seconds.

Repository-wide go vet ./eth/..., gosec ./..., and make vulncheck also ran. They report pre-existing baseline findings: the tracer WriteTo signature warning, existing gosec findings, and Go 1.26.5 standard-library advisories fixed in Go 1.26.6. None point to changed files.

Rollout notes

Backward-compatible and not consensus-affecting. No configuration or database migration is required. Out-of-sync nodes stop stuck-transaction rebroadcasts once a catch-up requirement is detected; normal rebroadcast eligibility resumes after a successful sync.

@codecov

codecov Bot commented Sep 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.66667% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 55.60%. Comparing base (aae7e66) to head (304c66f).

Files with missing lines Patch % Lines
eth/sync.go 86.36% 2 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #2397      +/-   ##
===========================================
+ Coverage    55.59%   55.60%   +0.01%     
===========================================
  Files          918      918              
  Lines       167145   167168      +23     
===========================================
+ Hits         92926    92959      +33     
+ Misses       68740    68739       -1     
+ Partials      5479     5470       -9     
Files with missing lines Coverage Δ
eth/handler.go 69.61% <100.00%> (+0.07%) ⬆️
eth/sync.go 66.94% <86.36%> (+1.78%) ⬆️

... and 20 files with indirect coverage changes

Files with missing lines Coverage Δ
eth/handler.go 69.61% <100.00%> (+0.07%) ⬆️
eth/sync.go 66.94% <86.36%> (+1.78%) ⬆️

... and 20 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@vbhattaccmu
vbhattaccmu requested a lite review from Copilot September 9, 2026 16:50
@vbhattaccmu vbhattaccmu changed the title eth: stop transaction rebroadcast while syncing feat: stop transaction rebroadcast while syncing Sep 9, 2026

Copilot AI 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.

🟡 Changes recommended

The new Kurtosis observation script can exit prematurely under set -euo pipefail when the target service container is not found, preventing the intended error handling and making the scenario less reliable.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR disables stuck-transaction rebroadcast as soon as the syncer detects a higher-TD peer (i.e., a catch-up sync is required), and only re-enables rebroadcast after a successful sync cycle, preventing out-of-date nodes from repeatedly clearing peers’ known-tx caches and re-announcing stale transactions. It also adds a Kurtosis-based local scenario to reproduce and observe the “hard-fork-stall + network delay” rebroadcast behavior.

Changes:

  • Disable stuck-tx rebroadcast when chainSyncer.nextSyncOp schedules a sync, and re-enable it via enableSyncedFeatures() after successful sync.
  • Refactor stuck-tx rebroadcast into handler.rebroadcastStuckTransactions and update tests to validate the new gating behavior.
  • Add a repeatable Kurtosis scenario (README/params/observe script) to observe rebroadcast behavior under fork-stall and netem delay.
File summaries
File Description
tests/kurtosis/rebroadcast/README.md Documents a local Kurtosis scenario for observing rebroadcast behavior on an out-of-sync node.
tests/kurtosis/rebroadcast/params.yml Kurtosis params defining the devnet topology with a v2.9.0 baseline node and a candidate node.
tests/kurtosis/rebroadcast/observe.sh Observation script that applies netem delay, optionally seeds a tx, and reports identified vs emitted rebroadcast batches.
eth/sync.go Disables rebroadcast immediately when a higher-TD peer requires a sync.
eth/sync_test.go Adds assertions that required sync disables rebroadcast and that a completed sync re-enables it.
eth/handler.go Introduces rebroadcastOK and gates stuck-tx rebroadcast through rebroadcastStuckTransactions; enables rebroadcast after successful sync.
eth/handler_test.go Updates tests to directly validate rebroadcast gating and that a tx message is emitted when rebroadcast is enabled.
Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/kurtosis/rebroadcast/observe.sh Outdated
Comment thread eth/handler.go
@vbhattaccmu
vbhattaccmu requested a lite review from Copilot September 9, 2026 17:13
@vbhattaccmu

Copy link
Copy Markdown
Contributor Author

@claude review

Copilot AI 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.

🟡 Changes recommended

There are confirmed compilation/type-mismatch issues in the new rebroadcast helper/tests plus a logic gap where benched higher-TD peers can still allow rebroadcast before a sync op is scheduled.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

eth/handler_test.go:486

  • After changing rebroadcastStuckTransactions to accept []*types.Transaction (matching core.StuckTxsEvent.Txs), this test should pass a []*types.Transaction slice instead of types.Transactions.
	if handler.handler.rebroadcastStuckTransactions(types.Transactions{signedTx}) {
  • Files reviewed: 7/7 changed files
  • Comments generated: 4
  • Review effort level: Lite

Comment thread eth/handler.go
Comment thread eth/handler_test.go
Comment thread eth/sync.go
Comment thread tests/kurtosis/rebroadcast/observe.sh Outdated
Comment thread eth/sync.go
@vbhattaccmu

Copy link
Copy Markdown
Contributor Author

@claude review

Copilot AI 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.

🟢 Approval recommended

The functional changes are small, well-scoped, and come with targeted unit tests and a reproducible Kurtosis scenario; only a minor test-strengthening nit was found.

Review details
  • Files reviewed: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread eth/sync_test.go Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I reviewed this updated version and the bug hunt found no new bugs. The critical gap I flagged earlier — rebroadcastOK staying stuck disabled forever after a failed catch-up sync — is now fixed: onSyncDone re-evaluates the gate via updateRebroadcastStatus() on sync error, and nextSyncOp re-evaluates it on every loop iteration (peer events, force timer, retry timer), with a dedicated regression test (TestChainSyncerRebroadcastAfterSyncFailure) covering peer-drop, timeout, and cancellation cases. Because this touches sync-critical, CODEOWNER-owned code (eth/) with shared atomic state read from two goroutines, a human maintainer look is still worthwhile before merge.

Extended reasoning...

This is a follow-up review of a PR I previously reviewed. In my prior pass I flagged a critical correctness issue: rebroadcastOK was cleared before every sync attempt but only restored in enableSyncedFeatures, which is only reached on a successful LegacySync. A sync failure (peer drop, timeout, cancellation — all routine) would leave rebroadcastOK permanently false even once the node was caught up, silently disabling stuck-tx rebroadcast forever.

Since that review, commit 53a2dcc ("eth, tests/kurtosis: fix rebroadcast gating during peer backoff") directly addresses this: onSyncDone now calls cs.updateRebroadcastStatus() whenever err != nil, and nextSyncOp unconditionally calls updateRebroadcastStatus() at the top of every invocation — which happens on every iteration of chainSyncer.loop() (peer events, sync completion, the 10s force timer, and the retry timer), not just when a new sync is scheduled. This means the gate is periodically re-evaluated even without a fresh peer event, which also mitigates the earlier ruled-out concern about peerWithHighestTD(nil) not accounting for downloader backoff/jail state — a benched peer's stale TD claim will eventually be re-checked against current peer state on the next loop tick. A new test file (eth/sync_rebroadcast_test.go) adds TestChainSyncerRebroadcastAfterSyncFailure, which exercises exactly the scenario I flagged (initial-sync failure, catch-up peer drop, catch-up timeout, catch-up cancellation) and asserts the gate is correctly restored once no peer remains ahead, then re-disabled if a new higher-TD peer appears.

No new bugs were reported by this run's bug hunt, and the two ruled-out candidates from earlier runs (both about peerWithHighestTD(nil) ignoring backoff/jail) are effectively mitigated by the periodic re-evaluation added in this fix, since a stale claim from a backed-off peer is checked again on the next tick rather than being a one-shot decision.

Despite the fix being solid and test-backed, I am not approving. eth/ is listed in .github/CODEOWNERS under a named owner, and per this review's guidelines, CODEOWNER-owned paths should not be approved by this automated pass regardless of code quality. The change also touches concurrency-sensitive shared state (atomic.Bool read/written from the sync goroutine and the stuck-tx broadcast loop) in a consensus-adjacent path (transaction propagation during sync), which warrants a maintainer's sign-off even though the logic itself now looks correct and is well tested.

This review covers commit 53a2dcc, which is no longer the latest commit on this pull request; later commits are not covered by it.

Copilot AI 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.

🔵 Needs a closer look

It changes sync-driven transaction propagation behavior in the eth P2P path, which is operationally sensitive and should get final human review despite the added tests.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

eth/handler_test.go:487

  • Grammar in this failure message is off; as written it reads like a present-tense verb phrase. Adjusting it makes the test output clearer when it fails.
  • Files reviewed: 8/8 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

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