Skip to content

Commit

Permalink
Improve Import/Export Simulation Errors (cosmos#4607)
Browse files Browse the repository at this point in the history
  • Loading branch information
fedekunze authored and Alessio Treglia committed Jun 28, 2019
1 parent f9dea98 commit 4a0fbb3
Show file tree
Hide file tree
Showing 9 changed files with 593 additions and 47 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ mytestnet
# Testing
coverage.txt
profile.out
sim_log_file

# Vagrant
.vagrant/
Expand Down
2 changes: 2 additions & 0 deletions .pending/improvements/sdk/4535-improve-sim-err
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#4535 Improve import-export simulation errors by decoding the `KVPair.Value` into its
respective type
5 changes: 1 addition & 4 deletions simapp/sim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}

}
Expand Down
23 changes: 0 additions & 23 deletions simapp/test_util.go

This file was deleted.

256 changes: 256 additions & 0 deletions simapp/utils.go
Original file line number Diff line number Diff line change
@@ -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]))
}
}
Loading

0 comments on commit 4a0fbb3

Please sign in to comment.