package v0_16 import ( "io/ioutil" "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" v039auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v039" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" vestexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" v036supply "github.com/cosmos/cosmos-sdk/x/bank/legacy/v036" v038bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v038" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" tmjson "github.com/tendermint/tendermint/libs/json" tmtypes "github.com/tendermint/tendermint/types" "github.com/kava-labs/kava/app" "github.com/kava-labs/kava/migrate/v0_16/legacyaccounts" ) func TestMigrateGenesisDoc(t *testing.T) { expected := getTestDataJSON("genesis-v16.json") genDoc, err := tmtypes.GenesisDocFromFile(filepath.Join("testdata", "genesis-v15.json")) assert.NoError(t, err) actualGenDoc, err := Migrate(genDoc, newClientContext()) assert.NoError(t, err) actualJson, err := tmjson.Marshal(actualGenDoc) assert.NoError(t, err) assert.JSONEq(t, expected, string(actualJson)) assert.LessOrEqual(t, actualGenDoc.ConsensusParams.Evidence.MaxBytes, actualGenDoc.ConsensusParams.Block.MaxBytes) } func TestMigrateFull(t *testing.T) { t.Skip() // avoid committing mainnet state - test also currently fails due to https://github.com/cosmos/cosmos-sdk/issues/10862. If you apply the patch, it will pass genDoc, err := tmtypes.GenesisDocFromFile(filepath.Join("testdata", "kava-8-block-1627000.json")) assert.NoError(t, err) newGenDoc, err := Migrate(genDoc, newClientContext()) assert.NoError(t, err) encodingConfig := app.MakeEncodingConfig() var appMap genutiltypes.AppMap err = tmjson.Unmarshal(newGenDoc.AppState, &appMap) assert.NoError(t, err) err = app.ModuleBasics.ValidateGenesis(encodingConfig.Marshaler, encodingConfig.TxConfig, appMap) assert.NoError(t, err) tApp := app.NewTestApp() require.NotPanics(t, func() { tApp.InitializeFromGenesisStatesWithTimeAndChainID(newGenDoc.GenesisTime, newGenDoc.ChainID, app.GenesisState(appMap)) }) } func TestAccountBalances(t *testing.T) { t.Skip() // avoid committing test data app.SetSDKConfig() // load auth state from kava-8 with empty accounts removed (keeps size down) authbz, err := ioutil.ReadFile(filepath.Join("testdata", "kava-8-test-auth-state.json")) require.NoError(t, err) // load bank state from kava-8, required for migration bankbz, err := ioutil.ReadFile(filepath.Join("testdata", "kava-8-test-bank-state.json")) require.NoError(t, err) // load supply state from kava-8, required for migration supplybz, err := ioutil.ReadFile(filepath.Join("testdata", "kava-8-test-supply-state.json")) require.NoError(t, err) // codec to read old auth data v039Codec := codec.NewLegacyAmino() legacyaccounts.RegisterLegacyAminoCodec(v039Codec) // store old auth genesis state for comparison to migrated state var prevAuthGenState legacyaccounts.GenesisState v039Codec.MustUnmarshalJSON(authbz, &prevAuthGenState) // migrate auth state to kava-9, with periodic vesting account changes and bank conversion appState := genutiltypes.AppMap{ v039auth.ModuleName: authbz, v038bank.ModuleName: bankbz, v036supply.ModuleName: supplybz, } clientCtx := newClientContext() appState = MigrateCosmosAppState(appState, clientCtx, GenesisTime) // store new auth and bank state var migratedAuthGenState authtypes.GenesisState clientCtx.Codec.MustUnmarshalJSON(appState[authtypes.ModuleName], &migratedAuthGenState) var migratedBankGenState banktypes.GenesisState clientCtx.Codec.MustUnmarshalJSON(appState[banktypes.ModuleName], &migratedBankGenState) // store map of accouauthexportednt coins from the bank module migratedAccCoins := make(map[string]sdk.Coins) for _, bal := range migratedBankGenState.Balances { migratedAccCoins[bal.Address] = bal.Coins } for i, anyAcc := range migratedAuthGenState.Accounts { var acc authtypes.AccountI err := clientCtx.InterfaceRegistry.UnpackAny(anyAcc, &acc) require.NoError(t, err) oldAcc := prevAuthGenState.Accounts[i] oldAcc.SpendableCoins(GenesisTime) newBalance, ok := migratedAccCoins[acc.GetAddress().String()] // all accounts have a corresponding balance require.True(t, ok, "expected balance to exist") // this is the same account require.Equal(t, oldAcc.GetAddress(), acc.GetAddress(), "expected account address to match") // the owned coins did not change require.Equal(t, oldAcc.GetCoins(), newBalance, "expected base coins to not change") // ensure spenable coins at genesis time is equal require.Equal(t, oldAcc.SpendableCoins(GenesisTime), getSpendableCoinsForAccount(acc, newBalance, GenesisTime), "expected spendable coins to not change") // check 30 days futureDate := GenesisTime.Add(30 * 24 * time.Hour) require.Equal(t, oldAcc.SpendableCoins(futureDate), getSpendableCoinsForAccount(acc, newBalance, futureDate), "expected spendable coins to not change") // check 90 days futureDate = GenesisTime.Add(90 * 24 * time.Hour) require.Equal(t, oldAcc.SpendableCoins(futureDate), getSpendableCoinsForAccount(acc, newBalance, futureDate), "expected spendable coins to not change") // check 180 days futureDate = GenesisTime.Add(180 * 24 * time.Hour) require.Equal(t, oldAcc.SpendableCoins(futureDate), getSpendableCoinsForAccount(acc, newBalance, futureDate), "expected spendable coins to not change") // check 365 days futureDate = GenesisTime.Add(365 * 24 * time.Hour) require.Equal(t, oldAcc.SpendableCoins(futureDate), getSpendableCoinsForAccount(acc, newBalance, futureDate), "expected spendable coins to not change") // check 2 years futureDate = GenesisTime.Add(2 * 365 * 24 * time.Hour) require.Equal(t, oldAcc.SpendableCoins(futureDate), getSpendableCoinsForAccount(acc, newBalance, futureDate), "expected spendable coins to not change") if vacc, ok := acc.(*vestingtypes.PeriodicVestingAccount); ok { // old account must be a periodic vesting account oldVacc, ok := oldAcc.(*legacyaccounts.PeriodicVestingAccount) require.True(t, ok) // total delegated coins must match oldTotalDelegated := oldVacc.DelegatedFree.Add(oldVacc.DelegatedVesting...) newTotalDelegated := vacc.DelegatedFree.Add(vacc.DelegatedVesting...) require.Equal(t, oldTotalDelegated, newTotalDelegated, "expected total amount of tracked delegations to not change") // delegated vesting must be less or equal to original vesting require.True(t, vacc.DelegatedVesting.IsAllLTE(vacc.OriginalVesting), "expected delegated vesting to be less or equal to original vesting") // vested coins must be nil for the new account require.Equal(t, sdk.Coins(nil), vacc.GetVestedCoins(GenesisTime), "expected no vested coins at genesis time") // vesting coins must not be nil require.NotEqual(t, sdk.Coins(nil), vacc.GetVestingCoins(GenesisTime), "expected vesting coins to be greater than 0") // new account as less than or equal require.LessOrEqual(t, len(vacc.VestingPeriods), len(oldVacc.VestingPeriods), "expected vesting periods of new account to be less than or equal to old") // start time should equal genesis time require.Equal(t, vacc.StartTime, GenesisTime.Unix(), "expected start time to be equal to genesis time") // end time should not change require.Equal(t, oldVacc.EndTime, vacc.EndTime, "expected end time to not change") // end time should be after genesis time require.Greater(t, vacc.EndTime, GenesisTime.Unix(), "expected end time to be after genesis time") // vesting account must have one or more periods require.GreaterOrEqual(t, len(vacc.VestingPeriods), 1, "expected one or more vesting periods") } } } func getSpendableCoinsForAccount(acc authtypes.AccountI, balance sdk.Coins, blockTime time.Time) sdk.Coins { if vacc, ok := acc.(vestexported.VestingAccount); ok { return balance.Sub(vacc.LockedCoins(blockTime)) } return balance }