fix: types: ensure .Amount is non-nil in Coin.Validate() (#15691)
This change fixes a scenario in which Coin.Validate() would panic when given a nil Amount. While here, added a fuzz test along with unit/regression tests. Fixes #15690
This commit is contained in:
parent
5b1ee227c2
commit
a7e2df2a46
@ -168,6 +168,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (types) [#15691](https://github.com/cosmos/cosmos-sdk/pull/15691) Make Coin.Validate() check that .Amount is not nil
|
||||
* (types) [#15433](https://github.com/cosmos/cosmos-sdk/pull/15433) Allow disabling of account address caches (for printing bech32 account addresses).
|
||||
* (x/auth) [#15059](https://github.com/cosmos/cosmos-sdk/pull/15059) `ante.CountSubKeys` returns 0 when passing a nil `Pubkey`.
|
||||
* (x/capability) [#15030](https://github.com/cosmos/cosmos-sdk/pull/15030) Prevent `x/capability` from consuming `GasMeter` gas during `InitMemStore`
|
||||
|
||||
@ -2,6 +2,7 @@ package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
@ -44,6 +45,10 @@ func (coin Coin) Validate() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if coin.Amount.IsNil() {
|
||||
return errors.New("amount is nil")
|
||||
}
|
||||
|
||||
if coin.Amount.IsNegative() {
|
||||
return fmt.Errorf("negative coin amount: %v", coin.Amount)
|
||||
}
|
||||
|
||||
@ -1276,6 +1276,40 @@ func (s *coinTestSuite) TestMarshalJSONCoins() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *coinTestSuite) TestCoinValidate() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
coin sdk.Coin
|
||||
wantErr string
|
||||
}{
|
||||
{"nil coin: nil Amount", sdk.Coin{}, "invalid denom"},
|
||||
{"non-blank coin, nil Amount", sdk.Coin{Denom: "atom"}, "amount is nil"},
|
||||
{"valid coin", sdk.Coin{Denom: "atom", Amount: math.NewInt(100)}, ""},
|
||||
{"negative coin", sdk.Coin{Denom: "atom", Amount: math.NewInt(-999)}, "negative coin amount"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t := s.T()
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := tc.coin.Validate()
|
||||
if tc.wantErr == "" {
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
if err == nil {
|
||||
t.Error("Expected an error")
|
||||
} else if !strings.Contains(err.Error(), tc.wantErr) {
|
||||
t.Errorf("Error mismatch\n\tGot: %q\nWant: %q", err, tc.wantErr)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *coinTestSuite) TestCoinAminoEncoding() {
|
||||
cdc := codec.NewLegacyAmino()
|
||||
c := sdk.NewInt64Coin(testDenom1, 5)
|
||||
|
||||
24
types/fuzz_test.go
Normal file
24
types/fuzz_test.go
Normal file
@ -0,0 +1,24 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
)
|
||||
|
||||
func FuzzCoinUnmarshalJSON(f *testing.F) {
|
||||
if testing.Short() {
|
||||
f.Skip()
|
||||
}
|
||||
|
||||
cdc := codec.NewLegacyAmino()
|
||||
f.Add(`{"denom":"atom","amount":"1000"}`)
|
||||
f.Add(`{"denom":"atom","amount":"-1000"}`)
|
||||
f.Add(`{"denom":"uatom","amount":"1000111111111111111111111"}`)
|
||||
f.Add(`{"denom":"mu","amount":"0"}`)
|
||||
|
||||
f.Fuzz(func(t *testing.T, jsonBlob string) {
|
||||
var c Coin
|
||||
_ = cdc.UnmarshalJSON([]byte(jsonBlob), &c)
|
||||
})
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user