Skip to content

Commit

Permalink
Merge branch 'release/v0.48.x' into mergify/bp/release/v0.48.x/pr-1310
Browse files Browse the repository at this point in the history
  • Loading branch information
0Tech authored Mar 29, 2024
2 parents 1d9e552 + 0c0e2c2 commit f965188
Show file tree
Hide file tree
Showing 13 changed files with 150 additions and 15 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/collection) [\#1282](https://github.com/Finschia/finschia-sdk/pull/1282) eliminates potential risk for Insufficient Sanity Check of tokenID in Genesis (backport #1276)
* (x/collection) [\#1290](https://github.com/Finschia/finschia-sdk/pull/1290) export x/collection params into genesis (backport #1268)
* (x/foundation) [\#1295](https://github.com/Finschia/finschia-sdk/pull/1295) add missing error handling for migration
* (sec) [\#1302](https://github.com/Finschia/finschia-sdk/pull/1302) remove map iteration non-determinism with keys + sorting
* (client) [\#1303](https://github.com/Finschia/finschia-sdk/pull/1303) fix possible overflow in BuildUnsignedTx
* (types) [\#1299](https://github.com/Finschia/finschia-sdk/pull/1299) add missing nil checks
* (x/staking) [\#1301](https://github.com/Finschia/finschia-sdk/pull/1301) Use bytes instead of string comparison in delete validator queue (backport cosmos/cosmos-sdk#12303)
* (client/keys) [#1312](https://github.com/Finschia/finschia-sdk/pull/1312) ignore error when key not found in `keys delete`
* (store) [\#1310](https://github.com/Finschia/finschia-sdk/pull/1310) fix app-hash mismatch if upgrade migration commit is interrupted(backport cosmos/cosmos-sdk#13530)

### Removed
Expand Down
7 changes: 6 additions & 1 deletion baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"reflect"
"sort"
"strings"
"sync"

Expand All @@ -16,6 +17,7 @@ import (
"github.com/Finschia/ostracon/crypto/tmhash"
"github.com/Finschia/ostracon/libs/log"
dbm "github.com/tendermint/tm-db"
"golang.org/x/exp/maps"

"github.com/Finschia/finschia-sdk/codec/types"
"github.com/Finschia/finschia-sdk/server/config"
Expand Down Expand Up @@ -272,7 +274,10 @@ func (app *BaseApp) MountKVStores(keys map[string]*sdk.KVStoreKey) {
// MountMemoryStores mounts all in-memory KVStores with the BaseApp's internal
// commit multi-store.
func (app *BaseApp) MountMemoryStores(keys map[string]*sdk.MemoryStoreKey) {
for _, memKey := range keys {
skeys := maps.Keys(keys)
sort.Strings(skeys)
for _, key := range skeys {
memKey := keys[key]
app.MountStore(memKey, sdk.StoreTypeMemory)
}
}
Expand Down
3 changes: 2 additions & 1 deletion client/keys/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ private keys stored in a ledger device cannot be deleted with the CLI.
for _, name := range args {
info, err := clientCtx.Keyring.Key(name)
if err != nil {
return err
cmd.PrintErrf("key %s not found\n", name)
continue
}

// confirm deletion, unless -y is passed
Expand Down
3 changes: 1 addition & 2 deletions client/keys/delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ func Test_runDeleteCmd(t *testing.T) {
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)

err = cmd.ExecuteContext(ctx)
require.Error(t, err)
require.EqualError(t, err, "blah.info: key not found")
require.NoError(t, err)

// User confirmation missing
cmd.SetArgs([]string{
Expand Down
5 changes: 4 additions & 1 deletion client/tx/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package tx
import (
"errors"
"fmt"
"math/big"
"os"

"github.com/spf13/pflag"
Expand Down Expand Up @@ -212,7 +213,9 @@ func (f Factory) BuildUnsignedTx(msgs ...sdk.Msg) (client.TxBuilder, error) {
return nil, errors.New("cannot provide both fees and gas prices")
}

glDec := sdk.NewDec(int64(f.gas))
// f.gas is a uint64 and we should convert to LegacyDec
// without the risk of under/overflow via uint64->int64.
glDec := sdk.NewDecFromBigInt(new(big.Int).SetUint64(f.gas))

// Derive the fees based on the provided gas prices, where
// fee = ceil(gasPrice * gasLimit).
Expand Down
25 changes: 21 additions & 4 deletions store/rootmulti/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,19 @@ const (

const iavlDisablefastNodeDefault = true

// keysFromStoreKeyMap returns a slice of keys for the provided map lexically sorted by StoreKey.Name()
func keysFromStoreKeyMap[V any](m map[types.StoreKey]V) []types.StoreKey {
keys := make([]types.StoreKey, 0, len(m))
for key := range m {
keys = append(keys, key)
}
sort.Slice(keys, func(i, j int) bool {
ki, kj := keys[i], keys[j]
return ki.Name() < kj.Name()
})
return keys
}

// Store is composed of many CommitStores. Name contrasts with
// cacheMultiStore which is used for branching other MultiStores. It implements
// the CommitMultiStore interface.
Expand Down Expand Up @@ -691,8 +704,9 @@ func (rs *Store) Snapshot(height uint64, protoWriter protoio.Writer) error {
*iavl.Store
name string
}
stores := []namedStore{}
for key := range rs.stores {
stores := make([]namedStore, 0)
keys := keysFromStoreKeyMap(rs.stores)
for _, key := range keys {
switch store := rs.GetCommitKVStore(key).(type) {
case *iavl.Store:
stores = append(stores, namedStore{name: key.Name(), Store: store})
Expand Down Expand Up @@ -900,9 +914,12 @@ func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, id types.CommitID
}

func (rs *Store) buildCommitInfo(version int64) *types.CommitInfo {
keys := keysFromStoreKeyMap(rs.stores)
storeInfos := []types.StoreInfo{}
for key, store := range rs.stores {
if store.GetStoreType() == types.StoreTypeTransient {
for _, key := range keys {
store := rs.stores[key]
storeType := store.GetStoreType()
if storeType == types.StoreTypeTransient || storeType == types.StoreTypeMemory {
continue
}
storeInfos = append(storeInfos, types.StoreInfo{
Expand Down
5 changes: 5 additions & 0 deletions types/coin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package types

import (
"encoding/json"
"errors"
"fmt"
"regexp"
"sort"
Expand Down Expand Up @@ -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)
}
Expand Down
33 changes: 33 additions & 0 deletions types/coin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,39 @@ 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: sdk.NewInt(100)}, ""},
{"negative coin", sdk.Coin{Denom: "atom", Amount: sdk.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)
Expand Down
10 changes: 7 additions & 3 deletions types/dec_coin.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,14 @@ func sanitizeDecCoins(decCoins []DecCoin) DecCoins {
// NewDecCoinsFromCoins constructs a new coin set with decimal values
// from regular Coins.
func NewDecCoinsFromCoins(coins ...Coin) DecCoins {
decCoins := make(DecCoins, len(coins))
if len(coins) == 0 {
return DecCoins{}
}

decCoins := make([]DecCoin, 0, len(coins))
newCoins := NewCoins(coins...)
for i, coin := range newCoins {
decCoins[i] = NewDecCoinFromCoin(coin)
for _, coin := range newCoins {
decCoins = append(decCoins, NewDecCoinFromCoin(coin))
}

return decCoins
Expand Down
23 changes: 23 additions & 0 deletions types/dec_coin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,29 @@ func (s *decCoinTestSuite) TestNewDecCoinsWithIsValid() {
}
}

func (s *decCoinTestSuite) TestNewDecCoinsWithZeroCoins() {
zeroCoins := append(sdk.NewCoins(sdk.NewCoin("mytoken", sdk.NewInt(0))), sdk.Coin{Denom: "wbtc", Amount: sdk.NewInt(10)})

tests := []struct {
coins sdk.Coins
expectLength int
}{
{
sdk.NewCoins(sdk.NewCoin("mytoken", sdk.NewInt(10)), sdk.NewCoin("wbtc", sdk.NewInt(10))),
2,
},
{
zeroCoins,
1,
},
}

for _, tc := range tests {
tc := tc
s.Require().Equal(sdk.NewDecCoinsFromCoins(tc.coins...).Len(), tc.expectLength)
}
}

func (s *decCoinTestSuite) TestDecCoins_AddDecCoinWithIsValid() {
lengthTestDecCoins := sdk.NewDecCoins().Add(sdk.NewDecCoin("mytoken", sdk.NewInt(10))).Add(sdk.DecCoin{Denom: "BTC", Amount: sdk.NewDec(10)})
s.Require().Equal(2, len(lengthTestDecCoins), "should be 2")
Expand Down
24 changes: 24 additions & 0 deletions types/fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package types

import (
"testing"

"github.com/Finschia/finschia-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)
})
}
6 changes: 5 additions & 1 deletion types/module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (

ocabci "github.com/Finschia/ostracon/abci/types"
abci "github.com/tendermint/tendermint/abci/types"
"golang.org/x/exp/maps"

"github.com/Finschia/finschia-sdk/client"
"github.com/Finschia/finschia-sdk/codec"
Expand Down Expand Up @@ -351,13 +352,16 @@ func (m *Manager) assertNoForgottenModules(setOrderFnName string, moduleNames []
for _, m := range moduleNames {
ms[m] = true
}

allKeys := maps.Keys(m.Modules)
var missing []string
for m := range m.Modules {
for _, m := range allKeys {
if !ms[m] {
missing = append(missing, m)
}
}
if len(missing) != 0 {
sort.Strings(missing)
panic(fmt.Sprintf(
"%s: all modules must be defined when setting %s, missing: %v", setOrderFnName, setOrderFnName, missing))
}
Expand Down
16 changes: 14 additions & 2 deletions x/staking/keeper/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,9 +375,21 @@ func (k Keeper) DeleteValidatorQueue(ctx sdk.Context, val types.Validator) {
addrs := k.GetUnbondingValidators(ctx, val.UnbondingTime, val.UnbondingHeight)
newAddrs := []string{}

// since address string may change due to Bech32 prefix change, we parse the addresses into bytes
// format for normalization
deletingAddr, err := sdk.ValAddressFromBech32(val.OperatorAddress)
if err != nil {
panic(err)
}

for _, addr := range addrs {
if addr != val.OperatorAddress {
newAddrs = append(newAddrs, addr)
storedAddr, err := sdk.ValAddressFromBech32(addr)
if err != nil {
// even if we don't panic here, it will panic in UnbondAllMatureValidators at unbond time
panic(err)
}
if !storedAddr.Equals(deletingAddr) {
newAddrs = append(newAddrs, storedAddr.String())
}
}

Expand Down

0 comments on commit f965188

Please sign in to comment.