diff --git a/.github/workflows/sims.yml b/.github/workflows/sims.yml index d0b4b0fe7f6c..9e750db4c487 100644 --- a/.github/workflows/sims.yml +++ b/.github/workflows/sims.yml @@ -51,7 +51,7 @@ jobs: with: path: ~/go/bin key: ${{ runner.os }}-go-runsim-binary - - name: test nondeterminism + - name: test-sim-nondeterminism run: | make test-sim-nondeterminism @@ -97,9 +97,9 @@ jobs: with: path: ~/go/bin key: ${{ runner.os }}-go-runsim-binary - - name: test after import + - name: test-sim-after-import run: | - make test-sim-import-export + make test-sim-after-import test-sim-multi-seed-short: runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index ce320d48f65d..162c3bbea90a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -99,6 +99,7 @@ types (eg. keys) to the `auth` module internal amino codec. * (rest) [\#5906](https://github.com/cosmos/cosmos-sdk/pull/5906) Fix an issue that make some REST calls panic when sending invalid or incomplete requests. * (x/genutil) [\#5938](https://github.com/cosmos/cosmos-sdk/pull/5938) Fix `InitializeNodeValidatorFiles` error handling. +* (x/staking) [\#5949](https://github.com/cosmos/cosmos-sdk/pull/5949) Skip staking `HistoricalInfoKey` in simulations as headers are not exported. * (x/auth) [\#5950](https://github.com/cosmos/cosmos-sdk/pull/5950) Fix `IncrementSequenceDecorator` to use is `IsReCheckTx` instead of `IsCheckTx` to allow account sequence incrementing. ### State Machine Breaking diff --git a/simapp/app.go b/simapp/app.go index e9c32a713918..90e75741399b 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -236,7 +236,7 @@ func NewSimApp( // During begin block slashing happens after distr.BeginBlocker so that // there is nothing left over in the validator fee pool, so as to keep the // CanWithdrawInvariant invariant. - app.mm.SetOrderBeginBlockers(upgrade.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName, evidence.ModuleName) + app.mm.SetOrderBeginBlockers(upgrade.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName, evidence.ModuleName, staking.ModuleName) app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName) // NOTE: The genutils moodule must occur after staking so that pools are diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 6053ff83cc75..bcfb64398717 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -148,6 +148,7 @@ func TestAppImportExport(t *testing.T) { {app.keys[staking.StoreKey], newApp.keys[staking.StoreKey], [][]byte{ staking.UnbondingQueueKey, staking.RedelegationQueueKey, staking.ValidatorQueueKey, + staking.HistoricalInfoKey, }}, // ordering may change but it doesn't matter {app.keys[slashing.StoreKey], newApp.keys[slashing.StoreKey], [][]byte{}}, {app.keys[mint.StoreKey], newApp.keys[mint.StoreKey], [][]byte{}}, diff --git a/store/types/utils.go b/store/types/utils.go index 8d4c83735460..8cfc2921eab5 100644 --- a/store/types/utils.go +++ b/store/types/utils.go @@ -38,20 +38,17 @@ func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvAs, kvBs []t kvB = tmkv.Pair{Key: iterB.Key(), Value: iterB.Value()} iterB.Next() } - if !bytes.Equal(kvA.Key, kvB.Key) { - kvAs = append(kvAs, kvA) - kvBs = append(kvBs, kvB) - continue // no need to compare the value - } compareValue := true for _, prefix := range prefixesToSkip { // Skip value comparison if we matched a prefix - if bytes.Equal(kvA.Key[:len(prefix)], prefix) { + if bytes.HasPrefix(kvA.Key, prefix) || bytes.HasPrefix(kvB.Key, prefix) { compareValue = false + break } } - if compareValue && !bytes.Equal(kvA.Value, kvB.Value) { + + if compareValue && (!bytes.Equal(kvA.Key, kvB.Key) || !bytes.Equal(kvA.Value, kvB.Value)) { kvAs = append(kvAs, kvA) kvBs = append(kvBs, kvB) } diff --git a/x/staking/alias.go b/x/staking/alias.go index 1b7c78772f73..3568daebe2cc 100644 --- a/x/staking/alias.go +++ b/x/staking/alias.go @@ -12,7 +12,6 @@ const ( DefaultParamspace = keeper.DefaultParamspace ModuleName = types.ModuleName StoreKey = types.StoreKey - TStoreKey = types.TStoreKey QuerierRoute = types.QuerierRoute RouterKey = types.RouterKey DefaultUnbondingTime = types.DefaultUnbondingTime diff --git a/x/staking/genesis.go b/x/staking/genesis.go index 8a2ecce10740..76ecf0c5c827 100644 --- a/x/staking/genesis.go +++ b/x/staking/genesis.go @@ -144,10 +144,6 @@ func InitGenesis( // GenesisState will contain the pool, params, validators, and bonds found in // the keeper. func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { - params := keeper.GetParams(ctx) - lastTotalPower := keeper.GetLastTotalPower(ctx) - validators := keeper.GetAllValidators(ctx) - delegations := keeper.GetAllDelegations(ctx) var unbondingDelegations []types.UnbondingDelegation keeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd types.UnbondingDelegation) (stop bool) { unbondingDelegations = append(unbondingDelegations, ubd) @@ -165,11 +161,11 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { }) return types.GenesisState{ - Params: params, - LastTotalPower: lastTotalPower, + Params: keeper.GetParams(ctx), + LastTotalPower: keeper.GetLastTotalPower(ctx), LastValidatorPowers: lastValidatorPowers, - Validators: validators, - Delegations: delegations, + Validators: keeper.GetAllValidators(ctx), + Delegations: keeper.GetAllDelegations(ctx), UnbondingDelegations: unbondingDelegations, Redelegations: redelegations, Exported: true, diff --git a/x/staking/keeper/historical_info.go b/x/staking/keeper/historical_info.go index 2ce0aee7dbcc..01ae38cc4092 100644 --- a/x/staking/keeper/historical_info.go +++ b/x/staking/keeper/historical_info.go @@ -36,6 +36,32 @@ func (k Keeper) DeleteHistoricalInfo(ctx sdk.Context, height int64) { store.Delete(key) } +// IterateHistoricalInfo provides an interator over all stored HistoricalInfo +// objects. For each HistoricalInfo object, cb will be called. If the cb returns +// true, the iterator will close and stop. +func (k Keeper) IterateHistoricalInfo(ctx sdk.Context, cb func(types.HistoricalInfo) bool) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, types.HistoricalInfoKey) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + histInfo := types.MustUnmarshalHistoricalInfo(k.cdc, iterator.Value()) + if cb(histInfo) { + break + } + } +} + +// GetAllHistoricalInfo returns all stored HistoricalInfo objects. +func (k Keeper) GetAllHistoricalInfo(ctx sdk.Context) []types.HistoricalInfo { + var infos []types.HistoricalInfo + k.IterateHistoricalInfo(ctx, func(histInfo types.HistoricalInfo) bool { + infos = append(infos, histInfo) + return false + }) + return infos +} + // TrackHistoricalInfo saves the latest historical-info and deletes the oldest // heights that are below pruning height func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { diff --git a/x/staking/keeper/historical_info_test.go b/x/staking/keeper/historical_info_test.go index 3a3f1100592b..37e3b7237f58 100644 --- a/x/staking/keeper/historical_info_test.go +++ b/x/staking/keeper/historical_info_test.go @@ -114,3 +114,32 @@ func TestTrackHistoricalInfo(t *testing.T) { require.False(t, found, "GetHistoricalInfo did not prune first prune height") require.Equal(t, types.HistoricalInfo{}, recv, "GetHistoricalInfo at height 5 is not empty after prune") } + +func TestGetAllHistoricalInfo(t *testing.T) { + _, app, ctx := createTestInput() + + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 50, sdk.NewInt(0)) + addrVals := simapp.ConvertAddrsToValAddrs(addrDels) + + valSet := []types.Validator{ + types.NewValidator(addrVals[0], PKs[0], types.Description{}), + types.NewValidator(addrVals[1], PKs[1], types.Description{}), + } + + header1 := abci.Header{ChainID: "HelloChain", Height: 10} + header2 := abci.Header{ChainID: "HelloChain", Height: 11} + header3 := abci.Header{ChainID: "HelloChain", Height: 12} + + hist1 := types.HistoricalInfo{Header: header1, Valset: valSet} + hist2 := types.HistoricalInfo{Header: header2, Valset: valSet} + hist3 := types.HistoricalInfo{Header: header3, Valset: valSet} + + expHistInfos := []types.HistoricalInfo{hist1, hist2, hist3} + + for i, hi := range expHistInfos { + app.StakingKeeper.SetHistoricalInfo(ctx, int64(10+i), hi) + } + + infos := app.StakingKeeper.GetAllHistoricalInfo(ctx) + require.Equal(t, expHistInfos, infos) +} diff --git a/x/staking/keeper/keeper.go b/x/staking/keeper/keeper.go index feddaf3b96f8..c4f19286597e 100644 --- a/x/staking/keeper/keeper.go +++ b/x/staking/keeper/keeper.go @@ -37,6 +37,7 @@ func NewKeeper( cdc codec.Marshaler, key sdk.StoreKey, bk types.BankKeeper, sk types.SupplyKeeper, ps paramtypes.Subspace, ) Keeper { + // set KeyTable if it has not already been set if !ps.HasKeyTable() { ps = ps.WithKeyTable(ParamKeyTable()) } diff --git a/x/staking/simulation/decoder.go b/x/staking/simulation/decoder.go index 86f1cecc9e00..efd8cb917e42 100644 --- a/x/staking/simulation/decoder.go +++ b/x/staking/simulation/decoder.go @@ -51,6 +51,12 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB tmkv.Pair) string { cdc.MustUnmarshalBinaryBare(kvB.Value, &redB) return fmt.Sprintf("%v\n%v", redA, redB) + case bytes.Equal(kvA.Key[:1], types.HistoricalInfoKey): + var histInfoA, histInfoB types.HistoricalInfo + cdc.MustUnmarshalBinaryBare(kvA.Value, &histInfoA) + cdc.MustUnmarshalBinaryBare(kvB.Value, &histInfoB) + return fmt.Sprintf("%v\n%v", histInfoA, histInfoB) + default: panic(fmt.Sprintf("invalid staking key prefix %X", kvA.Key[:1])) } diff --git a/x/staking/simulation/decoder_test.go b/x/staking/simulation/decoder_test.go index 40dd39710e84..813f7fc74a6f 100644 --- a/x/staking/simulation/decoder_test.go +++ b/x/staking/simulation/decoder_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/ed25519" tmkv "github.com/tendermint/tendermint/libs/kv" @@ -38,6 +39,7 @@ func TestDecodeStore(t *testing.T) { del := types.NewDelegation(delAddr1, valAddr1, sdk.OneDec()) ubd := types.NewUnbondingDelegation(delAddr1, valAddr1, 15, bondTime, sdk.OneInt()) red := types.NewRedelegation(delAddr1, valAddr1, valAddr1, 12, bondTime, sdk.OneInt(), sdk.OneDec()) + histInfo := types.NewHistoricalInfo(abci.Header{ChainID: "gaia", Height: 10, Time: bondTime}, types.Validators{val}) kvPairs := tmkv.Pairs{ tmkv.Pair{Key: types.LastTotalPowerKey, Value: cdc.MustMarshalBinaryBare(sdk.OneInt())}, @@ -46,6 +48,7 @@ func TestDecodeStore(t *testing.T) { tmkv.Pair{Key: types.GetDelegationKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(del)}, tmkv.Pair{Key: types.GetUBDKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(ubd)}, tmkv.Pair{Key: types.GetREDKey(delAddr1, valAddr1, valAddr1), Value: cdc.MustMarshalBinaryBare(red)}, + tmkv.Pair{Key: types.GetHistoricalInfoKey(10), Value: cdc.MustMarshalBinaryBare(histInfo)}, tmkv.Pair{Key: []byte{0x99}, Value: []byte{0x99}}, } @@ -59,6 +62,7 @@ func TestDecodeStore(t *testing.T) { {"Delegation", fmt.Sprintf("%v\n%v", del, del)}, {"UnbondingDelegation", fmt.Sprintf("%v\n%v", ubd, ubd)}, {"Redelegation", fmt.Sprintf("%v\n%v", red, red)}, + {"HistoricalInfo", fmt.Sprintf("%v\n%v", histInfo, histInfo)}, {"other", ""}, } for i, tt := range tests { diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index d278b50db3e7..dc4d027b66f2 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -15,9 +15,6 @@ const ( // StoreKey is the string store representation StoreKey = ModuleName - // TStoreKey is the string transient store representation - TStoreKey = "transient_" + ModuleName - // QuerierRoute is the querier route for the staking module QuerierRoute = ModuleName