diff --git a/.gitignore b/.gitignore index 62debadaf98c..b7422778b77d 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ mytestnet # Testing coverage.txt profile.out +sim_log_file # Vagrant .vagrant/ diff --git a/.pending/improvements/sdk/4535-improve-sim-err b/.pending/improvements/sdk/4535-improve-sim-err new file mode 100644 index 000000000000..d338161fb800 --- /dev/null +++ b/.pending/improvements/sdk/4535-improve-sim-err @@ -0,0 +1,2 @@ +#4535 Improve import-export simulation errors by decoding the `KVPair.Value` into its +respective type \ No newline at end of file diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 33e00cb576be..eedbac68b390 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -930,10 +930,7 @@ func TestAppImportExport(t *testing.T) { storeB := ctxB.KVStore(storeKeyB) kvA, kvB, count, equal := sdk.DiffKVStores(storeA, storeB, prefixes) fmt.Printf("Compared %d key/value pairs between %s and %s\n", count, storeKeyA, storeKeyB) - require.True(t, equal, - "unequal stores: %s / %s:\nstore A %X => %X\nstore B %X => %X", - storeKeyA, storeKeyB, kvA.Key, kvA.Value, kvB.Key, kvB.Value, - ) + require.True(t, equal, getSimulationLog(storeKeyA.Name(), app.cdc, newApp.cdc, kvA, kvB)) } } diff --git a/simapp/test_util.go b/simapp/test_util.go deleted file mode 100644 index ea5f7b05485c..000000000000 --- a/simapp/test_util.go +++ /dev/null @@ -1,23 +0,0 @@ -package simapp - -import ( - "io" - - dbm "github.com/tendermint/tendermint/libs/db" - "github.com/tendermint/tendermint/libs/log" - - bam "github.com/cosmos/cosmos-sdk/baseapp" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/staking" -) - -// NewSimAppUNSAFE is used for debugging purposes only. -// -// NOTE: to not use this function with non-test code -func NewSimAppUNSAFE(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, - invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp), -) (gapp *SimApp, keyMain, keyStaking *sdk.KVStoreKey, stakingKeeper staking.Keeper) { - - gapp = NewSimApp(logger, db, traceStore, loadLatest, invCheckPeriod, baseAppOptions...) - return gapp, gapp.keyMain, gapp.keyStaking, gapp.stakingKeeper -} diff --git a/simapp/utils.go b/simapp/utils.go new file mode 100644 index 000000000000..2c97b5343b18 --- /dev/null +++ b/simapp/utils.go @@ -0,0 +1,256 @@ +//nolint +package simapp + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + + "github.com/tendermint/tendermint/crypto" + cmn "github.com/tendermint/tendermint/libs/common" + + "github.com/cosmos/cosmos-sdk/codec" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" + + bam "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/distribution" + "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/cosmos/cosmos-sdk/x/mint" + "github.com/cosmos/cosmos-sdk/x/slashing" + "github.com/cosmos/cosmos-sdk/x/staking" +) + +// NewSimAppUNSAFE is used for debugging purposes only. +// +// NOTE: to not use this function with non-test code +func NewSimAppUNSAFE(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, + invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp), +) (gapp *SimApp, keyMain, keyStaking *sdk.KVStoreKey, stakingKeeper staking.Keeper) { + + gapp = NewSimApp(logger, db, traceStore, loadLatest, invCheckPeriod, baseAppOptions...) + return gapp, gapp.keyMain, gapp.keyStaking, gapp.stakingKeeper +} + +// getSimulationLog unmarshals the KVPair's Value to the corresponding type based on the +// each's module store key and the prefix bytes of the KVPair's key. +func getSimulationLog(storeName string, cdcA, cdcB *codec.Codec, kvA, kvB cmn.KVPair) (log string) { + log = fmt.Sprintf("store A %X => %X\nstore B %X => %X\n", kvA.Key, kvA.Value, kvB.Key, kvB.Value) + + if len(kvA.Value) == 0 && len(kvB.Value) == 0 { + return + } + + switch storeName { + case auth.StoreKey: + return decodeAccountStore(cdcA, cdcB, kvA, kvB) + case mint.StoreKey: + return decodeMintStore(cdcA, cdcB, kvA, kvB) + case staking.StoreKey: + return decodeStakingStore(cdcA, cdcB, kvA, kvB) + case slashing.StoreKey: + return decodeSlashingStore(cdcA, cdcB, kvA, kvB) + case gov.StoreKey: + return decodeGovStore(cdcA, cdcB, kvA, kvB) + case distribution.StoreKey: + return decodeDistributionStore(cdcA, cdcB, kvA, kvB) + default: + return + } +} + +func decodeAccountStore(cdcA, cdcB *codec.Codec, kvA, kvB cmn.KVPair) string { + switch { + case bytes.Equal(kvA.Key[:1], auth.AddressStoreKeyPrefix): + var accA, accB auth.Account + cdcA.MustUnmarshalBinaryBare(kvA.Value, &accA) + cdcB.MustUnmarshalBinaryBare(kvB.Value, &accB) + return fmt.Sprintf("%v\n%v", accA, accB) + case bytes.Equal(kvA.Key, auth.GlobalAccountNumberKey): + var globalAccNumberA, globalAccNumberB uint64 + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &globalAccNumberA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &globalAccNumberB) + return fmt.Sprintf("GlobalAccNumberA: %d\nGlobalAccNumberB: %d", globalAccNumberA, globalAccNumberB) + default: + panic(fmt.Sprintf("invalid account key %X", kvA.Key)) + } +} + +func decodeMintStore(cdcA, cdcB *codec.Codec, kvA, kvB cmn.KVPair) string { + switch { + case bytes.Equal(kvA.Key, mint.MinterKey): + var minterA, minterB mint.Minter + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &minterA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &minterB) + return fmt.Sprintf("%v\n%v", minterA, minterB) + default: + panic(fmt.Sprintf("invalid mint key %X", kvA.Key)) + } +} + +func decodeDistributionStore(cdcA, cdcB *codec.Codec, kvA, kvB cmn.KVPair) string { + switch { + case bytes.Equal(kvA.Key[:1], distribution.FeePoolKey): + var feePoolA, feePoolB distribution.FeePool + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &feePoolA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &feePoolB) + return fmt.Sprintf("%v\n%v", feePoolA, feePoolB) + + case bytes.Equal(kvA.Key[:1], distribution.ProposerKey): + return fmt.Sprintf("%v\n%v", sdk.ConsAddress(kvA.Value), sdk.ConsAddress(kvB.Value)) + + case bytes.Equal(kvA.Key[:1], distribution.ValidatorOutstandingRewardsPrefix): + var rewardsA, rewardsB distribution.ValidatorOutstandingRewards + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &rewardsA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &rewardsB) + return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) + + case bytes.Equal(kvA.Key[:1], distribution.DelegatorWithdrawAddrPrefix): + return fmt.Sprintf("%v\n%v", sdk.AccAddress(kvA.Value), sdk.AccAddress(kvB.Value)) + + case bytes.Equal(kvA.Key[:1], distribution.DelegatorStartingInfoPrefix): + var infoA, infoB distribution.DelegatorStartingInfo + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &infoA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &infoB) + return fmt.Sprintf("%v\n%v", infoA, infoB) + + case bytes.Equal(kvA.Key[:1], distribution.ValidatorHistoricalRewardsPrefix): + var rewardsA, rewardsB distribution.ValidatorHistoricalRewards + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &rewardsA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &rewardsB) + return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) + + case bytes.Equal(kvA.Key[:1], distribution.ValidatorCurrentRewardsPrefix): + var rewardsA, rewardsB distribution.ValidatorCurrentRewards + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &rewardsA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &rewardsB) + return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) + + case bytes.Equal(kvA.Key[:1], distribution.ValidatorAccumulatedCommissionPrefix): + var commissionA, commissionB distribution.ValidatorAccumulatedCommission + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &commissionA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &commissionB) + return fmt.Sprintf("%v\n%v", commissionA, commissionB) + + case bytes.Equal(kvA.Key[:1], distribution.ValidatorSlashEventPrefix): + var eventA, eventB distribution.ValidatorSlashEvent + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &eventA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &eventB) + return fmt.Sprintf("%v\n%v", eventA, eventB) + + default: + panic(fmt.Sprintf("invalid distribution key prefix %X", kvA.Key[:1])) + } +} + +func decodeStakingStore(cdcA, cdcB *codec.Codec, kvA, kvB cmn.KVPair) string { + switch { + case bytes.Equal(kvA.Key[:1], staking.PoolKey): + var poolA, poolB staking.Pool + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &poolA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &poolB) + return fmt.Sprintf("%v\n%v", poolA, poolB) + + case bytes.Equal(kvA.Key[:1], staking.LastTotalPowerKey): + var powerA, powerB sdk.Int + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &powerA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &powerB) + return fmt.Sprintf("%v\n%v", powerA, powerB) + + case bytes.Equal(kvA.Key[:1], staking.ValidatorsKey): + var validatorA, validatorB staking.Validator + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &validatorA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &validatorB) + return fmt.Sprintf("%v\n%v", validatorA, validatorB) + + case bytes.Equal(kvA.Key[:1], staking.LastValidatorPowerKey), + bytes.Equal(kvA.Key[:1], staking.ValidatorsByConsAddrKey), + bytes.Equal(kvA.Key[:1], staking.ValidatorsByPowerIndexKey): + return fmt.Sprintf("%v\n%v", sdk.ValAddress(kvA.Value), sdk.ValAddress(kvB.Value)) + + case bytes.Equal(kvA.Key[:1], staking.DelegationKey): + var delegationA, delegationB staking.Delegation + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &delegationA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &delegationB) + return fmt.Sprintf("%v\n%v", delegationA, delegationB) + + case bytes.Equal(kvA.Key[:1], staking.UnbondingDelegationKey), + bytes.Equal(kvA.Key[:1], staking.UnbondingDelegationByValIndexKey): + var ubdA, ubdB staking.UnbondingDelegation + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &ubdA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &ubdB) + return fmt.Sprintf("%v\n%v", ubdA, ubdB) + + case bytes.Equal(kvA.Key[:1], staking.RedelegationKey), + bytes.Equal(kvA.Key[:1], staking.RedelegationByValSrcIndexKey): + var redA, redB staking.Redelegation + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &redA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &redB) + return fmt.Sprintf("%v\n%v", redA, redB) + + default: + panic(fmt.Sprintf("invalid staking key prefix %X", kvA.Key[:1])) + } +} + +func decodeSlashingStore(cdcA, cdcB *codec.Codec, kvA, kvB cmn.KVPair) string { + switch { + case bytes.Equal(kvA.Key[:1], slashing.ValidatorSigningInfoKey): + var infoA, infoB slashing.ValidatorSigningInfo + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &infoA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &infoB) + return fmt.Sprintf("%v\n%v", infoA, infoB) + + case bytes.Equal(kvA.Key[:1], slashing.ValidatorMissedBlockBitArrayKey): + var missedA, missedB bool + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &missedA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &missedB) + return fmt.Sprintf("missedA: %v\nmissedB: %v", missedA, missedB) + + case bytes.Equal(kvA.Key[:1], slashing.AddrPubkeyRelationKey): + var pubKeyA, pubKeyB crypto.PubKey + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &pubKeyA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &pubKeyB) + bechPKA := sdk.MustBech32ifyAccPub(pubKeyA) + bechPKB := sdk.MustBech32ifyAccPub(pubKeyB) + return fmt.Sprintf("PubKeyA: %s\nPubKeyB: %s", bechPKA, bechPKB) + + default: + panic(fmt.Sprintf("invalid slashing key prefix %X", kvA.Key[:1])) + } +} + +func decodeGovStore(cdcA, cdcB *codec.Codec, kvA, kvB cmn.KVPair) string { + switch { + case bytes.Equal(kvA.Key[:1], gov.ProposalsKeyPrefix): + var proposalA, proposalB gov.Proposal + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &proposalA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &proposalB) + return fmt.Sprintf("%v\n%v", proposalA, proposalB) + + case bytes.Equal(kvA.Key[:1], gov.ActiveProposalQueuePrefix), + bytes.Equal(kvA.Key[:1], gov.InactiveProposalQueuePrefix), + bytes.Equal(kvA.Key[:1], gov.ProposalIDKey): + proposalIDA := binary.LittleEndian.Uint64(kvA.Value) + proposalIDB := binary.LittleEndian.Uint64(kvB.Value) + return fmt.Sprintf("proposalIDA: %d\nProposalIDB: %d", proposalIDA, proposalIDB) + + case bytes.Equal(kvA.Key[:1], gov.DepositsKeyPrefix): + var depositA, depositB gov.Deposit + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &depositA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &depositB) + return fmt.Sprintf("%v\n%v", depositA, depositB) + + case bytes.Equal(kvA.Key[:1], gov.VotesKeyPrefix): + var voteA, voteB gov.Vote + cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &voteA) + cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &voteB) + return fmt.Sprintf("%v\n%v", voteA, voteB) + + default: + panic(fmt.Sprintf("invalid governance key prefix %X", kvA.Key[:1])) + } +} diff --git a/simapp/utils_test.go b/simapp/utils_test.go new file mode 100644 index 000000000000..f03691f2c277 --- /dev/null +++ b/simapp/utils_test.go @@ -0,0 +1,304 @@ +package simapp + +import ( + "encoding/binary" + "fmt" + "time" + + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/tendermint/tendermint/crypto/ed25519" + cmn "github.com/tendermint/tendermint/libs/common" + + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/distribution" + distr "github.com/cosmos/cosmos-sdk/x/distribution" + "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/cosmos/cosmos-sdk/x/mint" + "github.com/cosmos/cosmos-sdk/x/slashing" + "github.com/cosmos/cosmos-sdk/x/staking" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var ( + delPk1 = ed25519.GenPrivKey().PubKey() + delAddr1 = sdk.AccAddress(delPk1.Address()) + valAddr1 = sdk.ValAddress(delPk1.Address()) + consAddr1 = sdk.ConsAddress(delPk1.Address().Bytes()) +) + +func makeTestCodec() (cdc *codec.Codec) { + cdc = codec.New() + sdk.RegisterCodec(cdc) + codec.RegisterCrypto(cdc) + auth.RegisterCodec(cdc) + distr.RegisterCodec(cdc) + gov.RegisterCodec(cdc) + staking.RegisterCodec(cdc) + return +} + +func TestGetSimulationLog(t *testing.T) { + cdc := makeTestCodec() + + tests := []struct { + store string + kvPair cmn.KVPair + }{ + {auth.StoreKey, cmn.KVPair{Key: auth.AddressStoreKey(delAddr1), Value: cdc.MustMarshalBinaryBare(auth.BaseAccount{})}}, + {mint.StoreKey, cmn.KVPair{Key: mint.MinterKey, Value: cdc.MustMarshalBinaryLengthPrefixed(mint.Minter{})}}, + {staking.StoreKey, cmn.KVPair{Key: staking.LastValidatorPowerKey, Value: valAddr1.Bytes()}}, + {gov.StoreKey, cmn.KVPair{Key: gov.VoteKey(1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(gov.Vote{})}}, + {distribution.StoreKey, cmn.KVPair{Key: distr.ProposerKey, Value: consAddr1.Bytes()}}, + {slashing.StoreKey, cmn.KVPair{Key: slashing.GetValidatorMissedBlockBitArrayKey(consAddr1, 6), Value: cdc.MustMarshalBinaryLengthPrefixed(true)}}, + {"Empty", cmn.KVPair{}}, + {"OtherStore", cmn.KVPair{Key: []byte("key"), Value: []byte("value")}}, + } + + for _, tt := range tests { + t.Run(tt.store, func(t *testing.T) { + require.NotPanics(t, func() { getSimulationLog(tt.store, cdc, cdc, tt.kvPair, tt.kvPair) }, tt.store) + }) + } +} + +func TestDecodeAccountStore(t *testing.T) { + cdc := makeTestCodec() + acc := auth.NewBaseAccountWithAddress(delAddr1) + globalAccNumber := uint64(10) + + kvPairs := cmn.KVPairs{ + cmn.KVPair{Key: auth.AddressStoreKey(delAddr1), Value: cdc.MustMarshalBinaryBare(acc)}, + cmn.KVPair{Key: auth.GlobalAccountNumberKey, Value: cdc.MustMarshalBinaryLengthPrefixed(globalAccNumber)}, + cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, + } + tests := []struct { + name string + expectedLog string + }{ + {"Minter", fmt.Sprintf("%v\n%v", acc, acc)}, + {"GlobalAccNumber", fmt.Sprintf("GlobalAccNumberA: %d\nGlobalAccNumberB: %d", globalAccNumber, globalAccNumber)}, + {"other", ""}, + } + + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + switch i { + case len(tests) - 1: + require.Panics(t, func() { decodeAccountStore(cdc, cdc, kvPairs[i], kvPairs[i]) }, tt.name) + default: + require.Equal(t, tt.expectedLog, decodeAccountStore(cdc, cdc, kvPairs[i], kvPairs[i]), tt.name) + } + }) + } +} + +func TestDecodeMintStore(t *testing.T) { + cdc := makeTestCodec() + minter := mint.NewMinter(sdk.OneDec(), sdk.NewDec(15)) + + kvPairs := cmn.KVPairs{ + cmn.KVPair{Key: mint.MinterKey, Value: cdc.MustMarshalBinaryLengthPrefixed(minter)}, + cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, + } + tests := []struct { + name string + expectedLog string + }{ + {"Minter", fmt.Sprintf("%v\n%v", minter, minter)}, + {"other", ""}, + } + + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + switch i { + case len(tests) - 1: + require.Panics(t, func() { decodeMintStore(cdc, cdc, kvPairs[i], kvPairs[i]) }, tt.name) + default: + require.Equal(t, tt.expectedLog, decodeMintStore(cdc, cdc, kvPairs[i], kvPairs[i]), tt.name) + } + }) + } +} + +func TestDecodeDistributionStore(t *testing.T) { + cdc := makeTestCodec() + + decCoins := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.OneDec())} + feePool := distr.InitialFeePool() + feePool.CommunityPool = decCoins + info := distr.NewDelegatorStartingInfo(2, sdk.OneDec(), 200) + outstanding := distr.ValidatorOutstandingRewards{decCoins[0]} + commission := distr.ValidatorAccumulatedCommission{decCoins[0]} + historicalRewards := distr.NewValidatorHistoricalRewards(decCoins, 100) + currentRewards := distr.NewValidatorCurrentRewards(decCoins, 5) + slashEvent := distr.NewValidatorSlashEvent(10, sdk.OneDec()) + + kvPairs := cmn.KVPairs{ + cmn.KVPair{Key: distr.FeePoolKey, Value: cdc.MustMarshalBinaryLengthPrefixed(feePool)}, + cmn.KVPair{Key: distr.ProposerKey, Value: consAddr1.Bytes()}, + cmn.KVPair{Key: distr.GetValidatorOutstandingRewardsKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(outstanding)}, + cmn.KVPair{Key: distr.GetDelegatorWithdrawAddrKey(delAddr1), Value: delAddr1.Bytes()}, + cmn.KVPair{Key: distr.GetDelegatorStartingInfoKey(valAddr1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(info)}, + cmn.KVPair{Key: distr.GetValidatorHistoricalRewardsKey(valAddr1, 100), Value: cdc.MustMarshalBinaryLengthPrefixed(historicalRewards)}, + cmn.KVPair{Key: distr.GetValidatorCurrentRewardsKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(currentRewards)}, + cmn.KVPair{Key: distr.GetValidatorAccumulatedCommissionKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(commission)}, + cmn.KVPair{Key: distr.GetValidatorSlashEventKey(valAddr1, 13), Value: cdc.MustMarshalBinaryLengthPrefixed(slashEvent)}, + cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, + } + + tests := []struct { + name string + expectedLog string + }{ + {"FeePool", fmt.Sprintf("%v\n%v", feePool, feePool)}, + {"Proposer", fmt.Sprintf("%v\n%v", consAddr1, consAddr1)}, + {"ValidatorOutstandingRewards", fmt.Sprintf("%v\n%v", outstanding, outstanding)}, + {"DelegatorWithdrawAddr", fmt.Sprintf("%v\n%v", delAddr1, delAddr1)}, + {"DelegatorStartingInfo", fmt.Sprintf("%v\n%v", info, info)}, + {"ValidatorHistoricalRewards", fmt.Sprintf("%v\n%v", historicalRewards, historicalRewards)}, + {"ValidatorCurrentRewards", fmt.Sprintf("%v\n%v", currentRewards, currentRewards)}, + {"ValidatorAccumulatedCommission", fmt.Sprintf("%v\n%v", commission, commission)}, + {"ValidatorSlashEvent", fmt.Sprintf("%v\n%v", slashEvent, slashEvent)}, + {"other", ""}, + } + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + switch i { + case len(tests) - 1: + require.Panics(t, func() { decodeDistributionStore(cdc, cdc, kvPairs[i], kvPairs[i]) }, tt.name) + default: + require.Equal(t, tt.expectedLog, decodeDistributionStore(cdc, cdc, kvPairs[i], kvPairs[i]), tt.name) + } + }) + } +} + +func TestDecodeStakingStore(t *testing.T) { + cdc := makeTestCodec() + + bondTime := time.Now().UTC() + + pool := staking.InitialPool() + val := staking.NewValidator(valAddr1, delPk1, staking.NewDescription("test", "test", "test", "test")) + del := staking.NewDelegation(delAddr1, valAddr1, sdk.OneDec()) + ubd := staking.NewUnbondingDelegation(delAddr1, valAddr1, 15, bondTime, sdk.OneInt()) + red := staking.NewRedelegation(delAddr1, valAddr1, valAddr1, 12, bondTime, sdk.OneInt(), sdk.OneDec()) + + kvPairs := cmn.KVPairs{ + cmn.KVPair{Key: staking.PoolKey, Value: cdc.MustMarshalBinaryLengthPrefixed(pool)}, + cmn.KVPair{Key: staking.LastTotalPowerKey, Value: cdc.MustMarshalBinaryLengthPrefixed(sdk.OneInt())}, + cmn.KVPair{Key: staking.GetValidatorKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(val)}, + cmn.KVPair{Key: staking.LastValidatorPowerKey, Value: valAddr1.Bytes()}, + cmn.KVPair{Key: staking.GetDelegationKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(del)}, + cmn.KVPair{Key: staking.GetUBDKey(delAddr1, valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(ubd)}, + cmn.KVPair{Key: staking.GetREDKey(delAddr1, valAddr1, valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(red)}, + cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, + } + + tests := []struct { + name string + expectedLog string + }{ + {"Pool", fmt.Sprintf("%v\n%v", pool, pool)}, + {"LastTotalPower", fmt.Sprintf("%v\n%v", sdk.OneInt(), sdk.OneInt())}, + {"Validator", fmt.Sprintf("%v\n%v", val, val)}, + {"LastValidatorPower/ValidatorsByConsAddr/ValidatorsByPowerIndex", fmt.Sprintf("%v\n%v", valAddr1, valAddr1)}, + {"Delegation", fmt.Sprintf("%v\n%v", del, del)}, + {"UnbondingDelegation", fmt.Sprintf("%v\n%v", ubd, ubd)}, + {"Redelegation", fmt.Sprintf("%v\n%v", red, red)}, + {"other", ""}, + } + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + switch i { + case len(tests) - 1: + require.Panics(t, func() { decodeStakingStore(cdc, cdc, kvPairs[i], kvPairs[i]) }, tt.name) + default: + require.Equal(t, tt.expectedLog, decodeStakingStore(cdc, cdc, kvPairs[i], kvPairs[i]), tt.name) + } + }) + } +} + +func TestDecodeSlashingStore(t *testing.T) { + cdc := makeTestCodec() + + info := slashing.NewValidatorSigningInfo(consAddr1, 0, 1, time.Now().UTC(), false, 0) + bechPK := sdk.MustBech32ifyAccPub(delPk1) + missed := true + + kvPairs := cmn.KVPairs{ + cmn.KVPair{Key: slashing.GetValidatorSigningInfoKey(consAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(info)}, + cmn.KVPair{Key: slashing.GetValidatorMissedBlockBitArrayKey(consAddr1, 6), Value: cdc.MustMarshalBinaryLengthPrefixed(missed)}, + cmn.KVPair{Key: slashing.GetAddrPubkeyRelationKey(delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(delPk1)}, + cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, + } + + tests := []struct { + name string + expectedLog string + }{ + {"ValidatorSigningInfo", fmt.Sprintf("%v\n%v", info, info)}, + {"ValidatorMissedBlockBitArray", fmt.Sprintf("missedA: %v\nmissedB: %v", missed, missed)}, + {"AddrPubkeyRelation", fmt.Sprintf("PubKeyA: %s\nPubKeyB: %s", bechPK, bechPK)}, + {"other", ""}, + } + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + switch i { + case len(tests) - 1: + require.Panics(t, func() { decodeSlashingStore(cdc, cdc, kvPairs[i], kvPairs[i]) }, tt.name) + default: + require.Equal(t, tt.expectedLog, decodeSlashingStore(cdc, cdc, kvPairs[i], kvPairs[i]), tt.name) + } + }) + } +} + +func TestDecodeGovStore(t *testing.T) { + cdc := makeTestCodec() + + endTime := time.Now().UTC() + + content := gov.ContentFromProposalType("test", "test", gov.ProposalTypeText) + proposal := gov.NewProposal(content, 1, endTime, endTime.Add(24*time.Hour)) + proposalIDBz := make([]byte, 8) + binary.LittleEndian.PutUint64(proposalIDBz, 1) + deposit := gov.NewDeposit(1, delAddr1, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()))) + vote := gov.NewVote(1, delAddr1, gov.OptionYes) + + kvPairs := cmn.KVPairs{ + cmn.KVPair{Key: gov.ProposalKey(1), Value: cdc.MustMarshalBinaryLengthPrefixed(proposal)}, + cmn.KVPair{Key: gov.InactiveProposalQueueKey(1, endTime), Value: proposalIDBz}, + cmn.KVPair{Key: gov.DepositKey(1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(deposit)}, + cmn.KVPair{Key: gov.VoteKey(1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(vote)}, + cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, + } + + tests := []struct { + name string + expectedLog string + }{ + {"proposals", fmt.Sprintf("%v\n%v", proposal, proposal)}, + {"proposal IDs", "proposalIDA: 1\nProposalIDB: 1"}, + {"deposits", fmt.Sprintf("%v\n%v", deposit, deposit)}, + {"votes", fmt.Sprintf("%v\n%v", vote, vote)}, + {"other", ""}, + } + + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + switch i { + case len(tests) - 1: + require.Panics(t, func() { decodeGovStore(cdc, cdc, kvPairs[i], kvPairs[i]) }, tt.name) + default: + require.Equal(t, tt.expectedLog, decodeGovStore(cdc, cdc, kvPairs[i], kvPairs[i]), tt.name) + } + }) + } +} diff --git a/x/distribution/keeper/key.go b/x/distribution/keeper/key.go index c11b9536837e..35c636103c77 100644 --- a/x/distribution/keeper/key.go +++ b/x/distribution/keeper/key.go @@ -12,7 +12,26 @@ const ( DefaultParamspace = types.ModuleName ) -// keys +// Keys for distribution store +// Items are stored with the following key: values +// +// - 0x00: FeePol +// +// - 0x01: sdk.ConsAddress +// +// - 0x02: ValidatorOutstandingRewards +// +// - 0x03: sdk.AccAddress +// +// - 0x04: DelegatorStartingInfo +// +// - 0x05: ValidatorHistoricalRewards +// +// - 0x06: ValidatorCurrentRewards +// +// - 0x07: ValidatorCurrentRewards +// +// - 0x08: ValidatorSlashEvent var ( FeePoolKey = []byte{0x00} // key for global distribution state ProposerKey = []byte{0x01} // key for the proposer operator address diff --git a/x/slashing/alias.go b/x/slashing/alias.go index 9a686247dd7b..7eb169c2904d 100644 --- a/x/slashing/alias.go +++ b/x/slashing/alias.go @@ -46,8 +46,6 @@ var ( GetValidatorSigningInfoAddress = types.GetValidatorSigningInfoAddress GetValidatorMissedBlockBitArrayPrefixKey = types.GetValidatorMissedBlockBitArrayPrefixKey GetValidatorMissedBlockBitArrayKey = types.GetValidatorMissedBlockBitArrayKey - GetValidatorSlashingPeriodPrefix = types.GetValidatorSlashingPeriodPrefix - GetValidatorSlashingPeriodKey = types.GetValidatorSlashingPeriodKey GetAddrPubkeyRelationKey = types.GetAddrPubkeyRelationKey NewMsgUnjail = types.NewMsgUnjail ParamKeyTable = types.ParamKeyTable @@ -61,7 +59,6 @@ var ( ModuleCdc = types.ModuleCdc ValidatorSigningInfoKey = types.ValidatorSigningInfoKey ValidatorMissedBlockBitArrayKey = types.ValidatorMissedBlockBitArrayKey - ValidatorSlashingPeriodKey = types.ValidatorSlashingPeriodKey AddrPubkeyRelationKey = types.AddrPubkeyRelationKey DoubleSignJailEndTime = types.DoubleSignJailEndTime DefaultMinSignedPerWindow = types.DefaultMinSignedPerWindow diff --git a/x/slashing/types/keys.go b/x/slashing/types/keys.go index 522101a06e0e..294b9c9a1cad 100644 --- a/x/slashing/types/keys.go +++ b/x/slashing/types/keys.go @@ -27,12 +27,18 @@ const ( QuerySigningInfos = "signingInfos" ) -// key prefix bytes +// Keys for slashing store +// Items are stored with the following key: values +// +// - 0x01: ValidatorSigningInfo +// +// - 0x02: bool +// +// - 0x03: crypto.PubKey var ( ValidatorSigningInfoKey = []byte{0x01} // Prefix for signing info ValidatorMissedBlockBitArrayKey = []byte{0x02} // Prefix for missed block bit array - ValidatorSlashingPeriodKey = []byte{0x03} // Prefix for slashing period - AddrPubkeyRelationKey = []byte{0x04} // Prefix for address-pubkey relation + AddrPubkeyRelationKey = []byte{0x03} // Prefix for address-pubkey relation ) // stored by *Consensus* address (not operator address) @@ -61,19 +67,6 @@ func GetValidatorMissedBlockBitArrayKey(v sdk.ConsAddress, i int64) []byte { return append(GetValidatorMissedBlockBitArrayPrefixKey(v), b...) } -// stored by *Consensus* address (not operator address) -func GetValidatorSlashingPeriodPrefix(v sdk.ConsAddress) []byte { - return append(ValidatorSlashingPeriodKey, v.Bytes()...) -} - -// stored by *Consensus* address (not operator address) followed by start height -func GetValidatorSlashingPeriodKey(v sdk.ConsAddress, startHeight int64) []byte { - b := make([]byte, 8) - // this needs to be height + ValidatorUpdateDelay because the slashing period for genesis validators starts at height -ValidatorUpdateDelay - binary.BigEndian.PutUint64(b, uint64(startHeight+sdk.ValidatorUpdateDelay)) - return append(GetValidatorSlashingPeriodPrefix(v), b...) -} - // get pubkey relation key used to get the pubkey from the address func GetAddrPubkeyRelationKey(address []byte) []byte { return append(AddrPubkeyRelationKey, address...)