Skip to content

feat(cosmos): return errors from NewDecCoinsFromCoins (CON-370) - #3997

Open
wen-coding wants to merge 2 commits into
mainfrom
fix/con-370-dec-coins-from-coins-error
Open

feat(cosmos): return errors from NewDecCoinsFromCoins (CON-370)#3997
wen-coding wants to merge 2 commits into
mainfrom
fix/con-370-dec-coins-from-coins-error

Conversation

@wen-coding

Copy link
Copy Markdown
Contributor

Summary

  • NewDecCoinsFromCoins now returns an error when a Coin amount cannot convert to Dec (out-of-range Int→Dec).
  • Distribution keeper and legacy fee callers handle the new error return.
  • Community-pool ValidateBasic paths reject amounts that cannot convert to Dec.

Test plan

  • go test ./sei-cosmos/types/... covering NewDecCoinsFromCoins and Int→Dec conversion
  • go test ./sei-cosmos/x/distribution/... for keeper, msg, and proposal ValidateBasic updates
  • Confirm legacy stdtx fee path compiles and exercises the error return

Made with Cursor

NewDecCoinsFromCoins returns an error when a Coin amount cannot convert
to Dec. Update distribution and legacy fee callers, and reject
out-of-range amounts in community-pool ValidateBasic paths.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown

The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedAug 24, 2026, 8:55 PM

@seidroid seidroid 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.

Well-scoped change: NewDecCoinsFromCoins now returns an error instead of panicking on out-of-range Int→Dec conversion, every caller in the tree is updated, and the community-pool ValidateBasic paths gain a matching guard with new tests. No blockers; two robustness/consistency suggestions and one test-coverage note.

Findings: 0 blocking | 4 non-blocking | 2 posted inline

Blockers

  • None at the file/PR level.

Non-blocking

  • [suggestion] Int.CanConvertToDec is exercised only at values far from the actual boundary (2^200 passes, 2^256-1 fails). The real cutoff is bitLen(i × 10^18) <= 315, so an off-by-one in the comparison would go undetected. Consider adding a pair of cases at exactly the largest convertible Int and one above it.
  • 2 suggestion(s)/nit(s) flagged inline on specific lines.
  • 1 non-blocking pre-existing issue(s) listed below under pre-existing issues.

Pre-existing issues

  • [suggestion] sei-cosmos/x/distribution/keeper/allocation.go (AllocateTokens, BeginBlock) and sei-cosmos/x/distribution/keeper/hooks.go (AfterValidatorRemoved, EndBlock) still halt the chain on an out-of-range coin amount — the PR preserves the pre-existing panic semantics rather than introducing them. The hooks.go site is notable because the surrounding comment explains that branch exists specifically to avoid an EndBlock halt from a failed send; the conversion panic sitting inside it reintroduces that same class of hazard (practically unreachable, but the asymmetry is worth a note).

// update outstanding
outstanding := k.GetValidatorOutstandingRewards(ctx, valAddr).Rewards
k.SetValidatorOutstandingRewards(ctx, valAddr, types.ValidatorOutstandingRewards{Rewards: outstanding.Sub(sdk.NewDecCoinsFromCoins(commission...))})
commissionDec, err := sdk.NewDecCoinsFromCoins(commission...)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[suggestion] The conversion check runs after SetValidatorAccumulatedCommission has already written at line 130, so an error here returns with the accumulated commission truncated to remainder while outstanding rewards are untouched and no coins were sent. Every production caller (msg server, precompiles) runs in a revertible context so this can't corrupt committed state today, but it's the opposite ordering from what this same PR does in FundCommunityPool and DistributeFromFeePool, where the conversion is deliberately hoisted above the first mutation. Moving the NewDecCoinsFromCoins(commission...) call up between TruncateDecimal() and SetValidatorAccumulatedCommission makes the validate-then-mutate order uniform and removes the dependence on the caller's revert behavior.

Comment thread sei-cosmos/types/int.go

// CanConvertToDec reports whether i fits in a whole-number Dec (i × 10^Precision).
func (i Int) CanConvertToDec() bool {
if i.i == nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[suggestion] Returning true for a nil Int makes the predicate disagree with the operation it guards: Int{}.ToDec() panics (big.Int.Mul on the nil returned by BigInt()), so a caller that trusts CanConvertToDec() gets a panic anyway. This is unreachable from NewDecCoinsFromCoins (the NewCoins call rejects such coins first), but CanConvertToDec is new exported API on sdk.Int and other callers won't have that guarantee. Returning false for nil — or documenting that the predicate assumes a non-nil Int — would make the contract match ToDec.

Minor, same lines: i.BigInt() already returns a fresh copy, so the wrapping new(big.Int).Set(...) is a redundant allocation.

@codecov

codecov Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 74.35897% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 57.99%. Comparing base (447f79a) to head (f314de3).

Files with missing lines Patch % Lines
sei-cosmos/x/auth/legacy/legacytx/stdtx.go 0.00% 4 Missing ⚠️
sei-cosmos/x/distribution/keeper/allocation.go 50.00% 1 Missing and 1 partial ⚠️
sei-cosmos/x/distribution/keeper/hooks.go 50.00% 1 Missing and 1 partial ⚠️
sei-cosmos/x/distribution/keeper/keeper.go 75.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3997      +/-   ##
==========================================
- Coverage   59.08%   57.99%   -1.10%     
==========================================
  Files        2305     2206      -99     
  Lines      197017   185475   -11542     
==========================================
- Hits       116414   107572    -8842     
+ Misses      69842    68078    -1764     
+ Partials    10761     9825     -936     
Flag Coverage Δ
sei-chain-pr 79.59% <74.35%> (?)
sei-db 69.80% <ø> (-0.22%) ⬇️
sei-db-state-db ?

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
sei-cosmos/types/dec_coin.go 87.89% <100.00%> (+0.07%) ⬆️
sei-cosmos/types/int.go 86.05% <100.00%> (+0.34%) ⬆️
sei-cosmos/x/distribution/keeper/fee_pool.go 85.71% <100.00%> (+3.89%) ⬆️
sei-cosmos/x/distribution/types/msg.go 56.96% <100.00%> (+1.11%) ⬆️
sei-cosmos/x/distribution/types/proposal.go 48.27% <100.00%> (+3.83%) ⬆️
sei-cosmos/x/distribution/keeper/allocation.go 86.48% <50.00%> (-2.41%) ⬇️
sei-cosmos/x/distribution/keeper/hooks.go 88.00% <50.00%> (-3.49%) ⬇️
sei-cosmos/x/distribution/keeper/keeper.go 86.04% <75.00%> (-1.46%) ⬇️
sei-cosmos/x/auth/legacy/legacytx/stdtx.go 76.23% <0.00%> (-2.34%) ⬇️

... and 100 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.

Convert commission Coins before writing truncated state, reject nil Ints
in CanConvertToDec, and cover the Dec conversion bit-length boundary.

Co-authored-by: Cursor <cursoragent@cursor.com>
@wen-coding
wen-coding requested review from codchen and shemnon August 25, 2026 03:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants