Skip to content
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

fix: all: remove map iteration non-determinism with keys + sorting #13377

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package baseapp

import (
"fmt"
"sort"
"strings"

abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
dbm "github.com/tendermint/tm-db"
"golang.org/x/exp/maps"

"github.com/cosmos/gogoproto/proto"

Expand Down Expand Up @@ -251,7 +253,10 @@ func (app *BaseApp) MountTransientStores(keys map[string]*storetypes.TransientSt
// MountMemoryStores mounts all in-memory KVStores with the BaseApp's internal
// commit multi-store.
func (app *BaseApp) MountMemoryStores(keys map[string]*storetypes.MemoryStoreKey) {
for _, memKey := range keys {
skeys := maps.Keys(keys)
sort.Strings(skeys)
for _, key := range skeys {
memKey := keys[key]
app.MountStore(memKey, storetypes.StoreTypeMemory)
}
}
Expand Down
8 changes: 7 additions & 1 deletion orm/model/ormdb/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ func (m moduleDB) DefaultJSON(target ormjson.WriteTarget) error {

func (m moduleDB) ValidateJSON(source ormjson.ReadSource) error {
errMap := map[protoreflect.FullName]error{}
for name, table := range m.tablesByName {
names := maps.Keys(m.tablesByName)
sort.Slice(names, func(i, j int) bool {
ti, tj := names[i], names[j]
return ti.Name() < tj.Name()
})
for _, name := range names {
r, err := source.OpenReader(name)
if err != nil {
return err
Expand All @@ -52,6 +57,7 @@ func (m moduleDB) ValidateJSON(source ormjson.ReadSource) error {
continue
}

table := m.tablesByName[name]
err = table.ValidateJSON(r)
if err != nil {
errMap[name] = err
Expand Down
15 changes: 14 additions & 1 deletion store/rootmulti/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ const (

const iavlDisablefastNodeDefault = false

func keysForStoreKeyMap[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 @@ -718,7 +730,8 @@ func (rs *Store) Snapshot(height uint64, protoWriter protoio.Writer) error {
name string
}
stores := []namedStore{}
for key := range rs.stores {
keys := keysForStoreKeyMap(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
2 changes: 1 addition & 1 deletion types/coin.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ func (coins Coins) safeAdd(coinsB Coins) (coalesced Coins) {
}
}

for denom, cL := range uniqCoins {
for denom, cL := range uniqCoins { //#nosec
comboCoin := Coin{Denom: denom, Amount: NewInt(0)}
for _, c := range cL {
comboCoin = comboCoin.Add(c)
Expand Down
4 changes: 3 additions & 1 deletion types/module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,13 +339,15 @@ 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
10 changes: 9 additions & 1 deletion x/group/keeper/invariants.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package keeper
import (
"fmt"
"math"
"sort"

"golang.org/x/exp/maps"

storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -53,7 +56,12 @@ func GroupTotalWeightInvariantHelper(ctx sdk.Context, key storetypes.StoreKey, g
groups[groupInfo.Id] = groupInfo
}

for _, groupInfo := range groups {
groupByIDs := maps.Keys(groups)
sort.Slice(groupByIDs, func(i, j int) bool {
return groupByIDs[i] < groupByIDs[j]
})
for _, groupID := range groupByIDs {
groupInfo := groups[groupID]
membersWeight, err := groupmath.NewNonNegativeDecFromString("0")
if err != nil {
msg += fmt.Sprintf("error while parsing positive dec zero for group member\n%v\n", err)
Expand Down