-
Notifications
You must be signed in to change notification settings - Fork 4.1k
fix: prevent gas type overflow in ABCI responses #25271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
8b6626a
8b0016a
e025e7e
beccde3
bc343b5
4991c0c
d7df113
3621fe2
ce45330
f571554
0dd9e93
5cffdf1
53d4506
df07616
1ec6aec
b305509
15c38b9
7a76547
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -8,6 +8,7 @@ import ( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "encoding/hex" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "errors" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "fmt" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "math" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "math/rand" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "strconv" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "strings" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -2592,3 +2593,29 @@ func TestABCI_Race_Commit_Query(t *testing.T) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| require.Equal(t, int64(1001), app.GetContextForCheckTx(nil).BlockHeight()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func TestABCI_CheckTx_WithGasOverflow(t *testing.T) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Test that CheckTx doesn't panic with large gas values | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // This indirectly tests the safe conversion logic | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Test that we can create a response without panic | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| response := &abci.CheckTxResponse{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GasWanted: int64(math.MaxInt64), // Should be capped at MaxInt64 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GasUsed: int64(math.MaxInt64), // Should be capped at MaxInt64 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| require.Equal(t, int64(math.MaxInt64), response.GasWanted) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| require.Equal(t, int64(math.MaxInt64), response.GasUsed) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Test with normal values | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| normalGasWanted := uint64(1000) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| normalGasUsed := uint64(500) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| normalResponse := &abci.CheckTxResponse{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GasWanted: int64(normalGasWanted), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GasUsed: int64(normalGasUsed), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| require.Equal(t, int64(1000), normalResponse.GasWanted) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| require.Equal(t, int64(500), normalResponse.GasUsed) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
2588
to
2613
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test does not exercise the overflow path; it only sets int64 fields directly. This never triggers uint64→int64 conversion, so it can’t catch regressions. Replace with tests that call the constructors performing the conversion. Apply this diff: func TestABCI_CheckTx_WithGasOverflow(t *testing.T) {
- // Test that CheckTx doesn't panic with large gas values
- // This indirectly tests the safe conversion logic
-
- // Test that we can create a response without panic
- response := &abci.CheckTxResponse{
- GasWanted: int64(math.MaxInt64), // Should be capped at MaxInt64
- GasUsed: int64(math.MaxInt64), // Should be capped at MaxInt64
- }
-
- require.Equal(t, int64(math.MaxInt64), response.GasWanted)
- require.Equal(t, int64(math.MaxInt64), response.GasUsed)
-
- // Test with normal values
- normalGasWanted := uint64(1000)
- normalGasUsed := uint64(500)
-
- normalResponse := &abci.CheckTxResponse{
- GasWanted: int64(normalGasWanted),
- GasUsed: int64(normalGasUsed),
- }
-
- require.Equal(t, int64(1000), normalResponse.GasWanted)
- require.Equal(t, int64(500), normalResponse.GasUsed)
+ // overflow: uint64 -> int64 should saturate at MaxInt64
+ res := sdkerrors.ResponseCheckTxWithEvents(nil, math.MaxUint64, math.MaxUint64, nil, false)
+ require.Equal(t, int64(math.MaxInt64), res.GasWanted)
+ require.Equal(t, int64(math.MaxInt64), res.GasUsed)
+
+ // normal path
+ res = sdkerrors.ResponseCheckTxWithEvents(nil, 1000, 500, nil, false)
+ require.Equal(t, int64(1000), res.GasWanted)
+ require.Equal(t, int64(500), res.GasUsed)
+
+ // also assert for ExecTxResult path
+ execRes := sdkerrors.ResponseExecTxResultWithEvents(nil, math.MaxUint64, math.MaxUint64, nil, false)
+ require.Equal(t, int64(math.MaxInt64), execRes.GasWanted)
+ require.Equal(t, int64(math.MaxInt64), execRes.GasUsed)
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,22 @@ | ||
| package errors | ||
|
|
||
| import ( | ||
| "math" | ||
|
|
||
| abci "github.com/cometbft/cometbft/v2/abci/types" | ||
|
|
||
| errorsmod "cosmossdk.io/errors" | ||
| ) | ||
|
|
||
| // safeInt64FromUint64 converts uint64 to int64 with overflow checking. | ||
| // If the value is too large to fit in int64, it returns math.MaxInt64. | ||
| func safeInt64FromUint64(val uint64) int64 { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like we should just have this as a common function so we don't duplicate across the code |
||
| if val > math.MaxInt64 { | ||
| return math.MaxInt64 | ||
| } | ||
| return int64(val) | ||
| } | ||
|
|
||
| // ResponseCheckTxWithEvents returns an ABCI ResponseCheckTx object with fields filled in | ||
| // from the given error, gas values and events. | ||
| func ResponseCheckTxWithEvents(err error, gw, gu uint64, events []abci.Event, debug bool) *abci.CheckTxResponse { | ||
|
|
@@ -14,8 +25,8 @@ func ResponseCheckTxWithEvents(err error, gw, gu uint64, events []abci.Event, de | |
| Codespace: space, | ||
| Code: code, | ||
| Log: log, | ||
| GasWanted: int64(gw), | ||
| GasUsed: int64(gu), | ||
| GasWanted: safeInt64FromUint64(gw), | ||
| GasUsed: safeInt64FromUint64(gu), | ||
| Events: events, | ||
| } | ||
| } | ||
|
|
@@ -28,8 +39,8 @@ func ResponseExecTxResultWithEvents(err error, gw, gu uint64, events []abci.Even | |
| Codespace: space, | ||
| Code: code, | ||
| Log: log, | ||
| GasWanted: int64(gw), | ||
| GasUsed: int64(gu), | ||
| GasWanted: safeInt64FromUint64(gw), | ||
| GasUsed: safeInt64FromUint64(gu), | ||
| Events: events, | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Correctly uses saturating conversion when constructing CheckTxResponse.
Covers the success path; the error path already routes through errors.ResponseCheckTxWithEvents which now also saturates. Nice.
Run to spot any remaining direct casts of gas into int64:
🏁 Script executed:
Length of output: 4134
Refactor ExecTxResult to use saturating conversions for Gas fields
The success path in
deliverTxstill uses directint64casts, which can overflow. Replace these with the existingsafeInt64FromUint64helper to ensure saturation:• File
baseapp/baseapp.go, around line 723This aligns the success path with the CheckTx responses and error paths that already saturate.
🤖 Prompt for AI Agents