Skip to content

fix(core/txpool/legacypool): prevent balance overflow panic and preserve tx replacement accounting, fix #2134#2168

Open
gzliudan wants to merge 1 commit intoXinFinOrg:dev-upgradefrom
gzliudan:fix-balance-overflow
Open

fix(core/txpool/legacypool): prevent balance overflow panic and preserve tx replacement accounting, fix #2134#2168
gzliudan wants to merge 1 commit intoXinFinOrg:dev-upgradefrom
gzliudan:fix-balance-overflow

Conversation

@gzliudan
Copy link
Collaborator

@gzliudan gzliudan commented Mar 10, 2026

Proposed changes

The #2134 txpool changes converted account-balance checks to uint256.MustFromBig, which can panic when state balances exceed uint256 range during promote/demote filtering. A runtime panic was triggered in promoteExecutables/demoteUnexecutables when account balance was converted with uint256.MustFromBig(...):

Root cause:

  • pool.currentState.GetBalance(addr) can exceed uint256 range in this code path.
  • uint256.MustFromBig(balance) panics on overflow, crashing the reorg loop.

What this commit changes:

  • remove uint256.MustFromBig(balance) from executable/non-executable filtering paths
  • change list.Filter costLimit from *uint256.Int to *big.Int, and compare costs using big.Int directly
  • keep overflow-safe totalcost accounting for replacements (subtract old cost first, then add new)
  • return txpool.ErrSpecialTxCostOverflow for special-tx cost/totalcost overflow instead of returning (false, nil)
  • avoid partial pending-state mutation by attaching a new pending list only after overflow-safe totalcost calculation succeeds

Tests:

  • add regression coverage for special-tx overflow rejection returning non-nil error
  • verify no pending/lookup/nonce mutation on overflow rejection
  • cover replacement paths to ensure no intermediate-overflow regressions in list.Add/promoteSpecialTx

panic message:

panic: overflow

goroutine 2405 [running]:
github.com/holiman/uint256.MustFromBig(...)
        github.com/holiman/uint256@v1.3.2/conversion.go:129
github.com/XinFinOrg/XDPoSChain/core/txpool/legacypool.(*LegacyPool).promoteExecutables(0xc0161943c0, {0xc04fd01df0, 0x1, 0x63d528?})
        github.com/XinFinOrg/XDPoSChain/core/txpool/legacypool/legacypool.go:1637 +0xb4e
github.com/XinFinOrg/XDPoSChain/core/txpool/legacypool.(*LegacyPool).runReorg(0xc0161943c0, 0xc04e8f1f10, 0xc03ebc3c60, 0x0, 0xc043f7b110)
        github.com/XinFinOrg/XDPoSChain/core/txpool/legacypool/legacypool.go:1459 +0x55a
created by github.com/XinFinOrg/XDPoSChain/core/txpool/legacypool.(*LegacyPool).scheduleReorgLoop in goroutine 69
        github.com/XinFinOrg/XDPoSChain/core/txpool/legacypool/legacypool.go:1372 +0x14a

Types of changes

What types of changes does your code introduce to XDC network?
Put an in the boxes that apply

  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Changes that don't change source code or tests
  • docs: Documentation only changes
  • feat: A new feature
  • fix: A bug fix
  • perf: A code change that improves performance
  • refactor: A code change that neither fixes a bug nor adds a feature
  • revert: Revert something
  • style: Changes that do not affect the meaning of the code
  • test: Adding missing tests or correcting existing tests

Impacted Components

Which parts of the codebase does this PR touch?
Put an in the boxes that apply

  • Consensus
  • Account
  • Network
  • Geth
  • Smart Contract
  • External components
  • Not sure (Please specify below)

Checklist

Put an in the boxes once you have confirmed below actions (or provide reasons on not doing so) that

  • This PR has sufficient test coverage (unit/integration test) OR I have provided reason in the PR description for not having test coverage
  • Tested on a private network from the genesis block and monitored the chain operating correctly for multiple epochs.
  • Provide an end-to-end test plan in the PR description on how to manually test it on the devnet/testnet.
  • Tested the backwards compatibility.
  • Tested with XDC nodes running this version co-exist with those running the previous version.
  • Relevant documentation has been updated as part of this PR
  • N/A

Copilot AI review requested due to automatic review settings March 10, 2026 17:51
@coderabbitai
Copy link

coderabbitai bot commented Mar 10, 2026

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

Run ID: e9ca3e46-5016-4145-9661-09a328b9adce

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

Copy link

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 addresses txpool stability and accounting correctness in core/txpool/legacypool by avoiding uint256.MustFromBig conversions on state balances (which can panic for >256-bit balances) and by fixing total-cost accounting during transaction replacement (including special tx promotion paths).

Changes:

  • Switch list cost caps and filter thresholds to *big.Int and pass account balances directly into list.Filter to prevent overflow panics.
  • Fix total-cost replacement accounting by computing totals from a post-replacement base (subtract old cost first, then add new cost with overflow checks).
  • Add regression tests covering special-tx totalcost consistency and replacement scenarios involving intermediate overflows.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
core/txpool/legacypool/list.go Changes list costcap to *big.Int, updates Filter signature/logic, and adjusts Add totalcost replacement computation.
core/txpool/legacypool/legacypool.go Stops converting balances to uint256 for filtering; updates special-tx promotion accounting to mirror replacement-safe totalcost computation.
core/txpool/legacypool/legacypool_test.go Adds regression tests for special-tx promotion totalcost correctness and replacement overflow scenarios.
core/txpool/legacypool/list_test.go Updates benchmark to use *big.Int for the new Filter signature and drops the uint256 import.

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

Comment on lines +1083 to +1090
cost, overflow := uint256.FromBig(tx.Cost())
if overflow {
return false, nil
}
total, overflow := new(uint256.Int).AddOverflow(base, cost)
if overflow {
return false, nil
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

In promoteSpecialTx, cost/totalcost overflow paths return (false, nil). Since add() returns immediately with this result for special txs, a nil error will make the caller treat the tx as accepted even though it wasn’t inserted (and it can also leak the reserver.Hold() reservation because the deferred Release only runs on err != nil). Return a non-nil error for these overflow cases (and ensure the tx is not partially accounted/inserted).

Copilot uses AI. Check for mistakes.
@gzliudan gzliudan force-pushed the fix-balance-overflow branch 2 times, most recently from fd24767 to 07d25ce Compare March 11, 2026 03:10
…able tx filtering, fix XinFinOrg#2134

A runtime panic was triggered in promoteExecutables/demoteUnexecutables when
account balance was converted with uint256.MustFromBig(...):

panic: overflow
... legacypool.go:1637

Root cause:
- pool.currentState.GetBalance(addr) can exceed uint256 range in this code path.
- uint256.MustFromBig(balance) panics on overflow, crashing the reorg loop.

What this commit changes:
- remove uint256.MustFromBig(balance) from executable/non-executable filtering paths
- change list.Filter costLimit from *uint256.Int to *big.Int, and compare costs using big.Int directly
- keep overflow-safe totalcost accounting for replacements (subtract old cost first, then add new)
- return txpool.ErrSpecialTxCostOverflow for special-tx cost/totalcost overflow instead of returning (false, nil)
- avoid partial pending-state mutation by attaching a new pending list only after overflow-safe totalcost calculation succeeds

Tests:
- add regression coverage for special-tx overflow rejection returning non-nil error
- verify no pending/lookup/nonce mutation on overflow rejection
- cover replacement paths to ensure no intermediate-overflow regressions in list.Add/promoteSpecialTx
@gzliudan gzliudan force-pushed the fix-balance-overflow branch from 07d25ce to 20acb19 Compare March 11, 2026 03:37
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