github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/migrations/v2/store_test.go (about)

     1  package v2_test
     2  
     3  import (
     4  	"fmt"
     5  	"sync/atomic"
     6  	"testing"
     7  	"time"
     8  
     9  	cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"cosmossdk.io/depinject"
    13  	"cosmossdk.io/log"
    14  	sdkmath "cosmossdk.io/math"
    15  	storetypes "cosmossdk.io/store/types"
    16  
    17  	"github.com/cosmos/cosmos-sdk/runtime"
    18  	"github.com/cosmos/cosmos-sdk/testutil"
    19  	simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
    20  	sdk "github.com/cosmos/cosmos-sdk/types"
    21  	moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
    22  	"github.com/cosmos/cosmos-sdk/x/auth"
    23  	authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
    24  	"github.com/cosmos/cosmos-sdk/x/auth/keeper"
    25  	v1 "github.com/cosmos/cosmos-sdk/x/auth/migrations/v1"
    26  	v4 "github.com/cosmos/cosmos-sdk/x/auth/migrations/v4"
    27  	authtestutil "github.com/cosmos/cosmos-sdk/x/auth/testutil"
    28  	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    29  	"github.com/cosmos/cosmos-sdk/x/auth/vesting/exported"
    30  	"github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
    31  	bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
    32  	stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
    33  	stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
    34  )
    35  
    36  type mockSubspace struct {
    37  	ps authtypes.Params
    38  }
    39  
    40  func newMockSubspace(ps authtypes.Params) mockSubspace {
    41  	return mockSubspace{ps: ps}
    42  }
    43  
    44  func (ms mockSubspace) GetParamSet(ctx sdk.Context, ps authexported.ParamSet) {
    45  	*ps.(*authtypes.Params) = ms.ps
    46  }
    47  
    48  func TestMigrateVestingAccounts(t *testing.T) {
    49  	encCfg := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{})
    50  	cdc := encCfg.Codec
    51  
    52  	storeKey := storetypes.NewKVStoreKey(v1.ModuleName)
    53  	tKey := storetypes.NewTransientStoreKey("transient_test")
    54  	ctx := testutil.DefaultContext(storeKey, tKey)
    55  	storeService := runtime.NewKVStoreService(storeKey)
    56  
    57  	var (
    58  		accountKeeper keeper.AccountKeeper
    59  		bankKeeper    bankkeeper.Keeper
    60  		stakingKeeper *stakingkeeper.Keeper
    61  	)
    62  	app, err := simtestutil.Setup(
    63  		depinject.Configs(
    64  			authtestutil.AppConfig,
    65  			depinject.Supply(log.NewNopLogger()),
    66  		),
    67  		&accountKeeper,
    68  		&bankKeeper,
    69  		&stakingKeeper,
    70  	)
    71  	require.NoError(t, err)
    72  
    73  	legacySubspace := newMockSubspace(authtypes.DefaultParams())
    74  	require.NoError(t, v4.Migrate(ctx, storeService, legacySubspace, cdc))
    75  
    76  	ctx = app.BaseApp.NewContextLegacy(false, cmtproto.Header{Time: time.Now()})
    77  	stakingKeeper.SetParams(ctx, stakingtypes.DefaultParams())
    78  	lastAccNum := uint64(1000)
    79  	createBaseAccount := func(addr sdk.AccAddress) *authtypes.BaseAccount {
    80  		baseAccount := authtypes.NewBaseAccountWithAddress(addr)
    81  		require.NoError(t, baseAccount.SetAccountNumber(atomic.AddUint64(&lastAccNum, 1)))
    82  		return baseAccount
    83  	}
    84  
    85  	testCases := []struct {
    86  		name        string
    87  		prepareFunc func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress)
    88  		garbageFunc func(ctx sdk.Context, vesting exported.VestingAccount, accounKeeper keeper.AccountKeeper) error
    89  		tokenAmount int64
    90  		expVested   int64
    91  		expFree     int64
    92  		blockTime   int64
    93  	}{
    94  		{
    95  			"delayed vesting has vested, multiple delegations less than the total account balance",
    96  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
    97  				baseAccount := createBaseAccount(delegatorAddr)
    98  				bondDenom, err := stakingKeeper.BondDenom(ctx)
    99  				require.NoError(t, err)
   100  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(200)))
   101  				delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
   102  				require.NoError(t, err)
   103  
   104  				ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
   105  
   106  				err = accountKeeper.Params.Set(ctx, authtypes.DefaultParams())
   107  				require.NoError(t, err)
   108  
   109  				accountKeeper.SetAccount(ctx, delayedAccount)
   110  
   111  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
   112  				require.NoError(t, err)
   113  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
   114  				require.NoError(t, err)
   115  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
   116  				require.NoError(t, err)
   117  			},
   118  			cleartTrackingFields,
   119  			300,
   120  			0,
   121  			300,
   122  			0,
   123  		},
   124  		{
   125  			"delayed vesting has vested, single delegations which exceed the vested amount",
   126  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   127  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   128  				require.NoError(t, err)
   129  				baseAccount := createBaseAccount(delegatorAddr)
   130  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(200)))
   131  				delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
   132  				require.NoError(t, err)
   133  
   134  				ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
   135  
   136  				accountKeeper.SetAccount(ctx, delayedAccount)
   137  
   138  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
   139  				require.NoError(t, err)
   140  			},
   141  			cleartTrackingFields,
   142  			300,
   143  			0,
   144  			300,
   145  			0,
   146  		},
   147  		{
   148  			"delayed vesting has vested, multiple delegations which exceed the vested amount",
   149  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   150  				baseAccount := createBaseAccount(delegatorAddr)
   151  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   152  				require.NoError(t, err)
   153  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(200)))
   154  				delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
   155  				require.NoError(t, err)
   156  
   157  				ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
   158  
   159  				accountKeeper.SetAccount(ctx, delayedAccount)
   160  
   161  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
   162  				require.NoError(t, err)
   163  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
   164  				require.NoError(t, err)
   165  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
   166  				require.NoError(t, err)
   167  			},
   168  			cleartTrackingFields,
   169  			300,
   170  			0,
   171  			300,
   172  			0,
   173  		},
   174  		{
   175  			"delayed vesting has not vested, single delegations  which exceed the vested amount",
   176  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   177  				baseAccount := createBaseAccount(delegatorAddr)
   178  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   179  				require.NoError(t, err)
   180  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(200)))
   181  				delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
   182  				require.NoError(t, err)
   183  
   184  				accountKeeper.SetAccount(ctx, delayedAccount)
   185  
   186  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
   187  				require.NoError(t, err)
   188  			},
   189  			cleartTrackingFields,
   190  			300,
   191  			200,
   192  			100,
   193  			0,
   194  		},
   195  		{
   196  			"delayed vesting has not vested, multiple delegations which exceed the vested amount",
   197  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   198  				baseAccount := createBaseAccount(delegatorAddr)
   199  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   200  				require.NoError(t, err)
   201  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(200)))
   202  				delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
   203  				require.NoError(t, err)
   204  
   205  				accountKeeper.SetAccount(ctx, delayedAccount)
   206  
   207  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
   208  				require.NoError(t, err)
   209  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
   210  				require.NoError(t, err)
   211  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
   212  				require.NoError(t, err)
   213  			},
   214  			cleartTrackingFields,
   215  			300,
   216  			200,
   217  			100,
   218  			0,
   219  		},
   220  		{
   221  			"not end time",
   222  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   223  				baseAccount := createBaseAccount(delegatorAddr)
   224  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   225  				require.NoError(t, err)
   226  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
   227  				delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
   228  				require.NoError(t, err)
   229  
   230  				accountKeeper.SetAccount(ctx, delayedAccount)
   231  
   232  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
   233  				require.NoError(t, err)
   234  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
   235  				require.NoError(t, err)
   236  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
   237  				require.NoError(t, err)
   238  			},
   239  			cleartTrackingFields,
   240  			300,
   241  			300,
   242  			0,
   243  			0,
   244  		},
   245  		{
   246  			"delayed vesting has not vested, single delegation greater than the total account balance",
   247  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   248  				baseAccount := createBaseAccount(delegatorAddr)
   249  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   250  				require.NoError(t, err)
   251  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
   252  				delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
   253  				require.NoError(t, err)
   254  
   255  				accountKeeper.SetAccount(ctx, delayedAccount)
   256  
   257  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
   258  				require.NoError(t, err)
   259  			},
   260  			cleartTrackingFields,
   261  			300,
   262  			300,
   263  			0,
   264  			0,
   265  		},
   266  		{
   267  			"delayed vesting has vested, single delegation greater than the total account balance",
   268  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   269  				baseAccount := createBaseAccount(delegatorAddr)
   270  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   271  				require.NoError(t, err)
   272  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
   273  				delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
   274  				require.NoError(t, err)
   275  
   276  				ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
   277  
   278  				accountKeeper.SetAccount(ctx, delayedAccount)
   279  
   280  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
   281  				require.NoError(t, err)
   282  			},
   283  			cleartTrackingFields,
   284  			300,
   285  			0,
   286  			300,
   287  			0,
   288  		},
   289  		{
   290  			"continuous vesting, start time after blocktime",
   291  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   292  				startTime := ctx.BlockTime().AddDate(1, 0, 0).Unix()
   293  				endTime := ctx.BlockTime().AddDate(2, 0, 0).Unix()
   294  				baseAccount := createBaseAccount(delegatorAddr)
   295  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   296  				require.NoError(t, err)
   297  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
   298  				delayedAccount, err := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime)
   299  				require.NoError(t, err)
   300  
   301  				ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
   302  
   303  				accountKeeper.SetAccount(ctx, delayedAccount)
   304  
   305  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
   306  				require.NoError(t, err)
   307  			},
   308  			cleartTrackingFields,
   309  			300,
   310  			300,
   311  			0,
   312  			0,
   313  		},
   314  		{
   315  			"continuous vesting, start time passed but not ended",
   316  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   317  				startTime := ctx.BlockTime().AddDate(-1, 0, 0).Unix()
   318  				endTime := ctx.BlockTime().AddDate(2, 0, 0).Unix()
   319  				baseAccount := createBaseAccount(delegatorAddr)
   320  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   321  				require.NoError(t, err)
   322  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
   323  				delayedAccount, err := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime)
   324  				require.NoError(t, err)
   325  
   326  				ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
   327  
   328  				accountKeeper.SetAccount(ctx, delayedAccount)
   329  
   330  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
   331  				require.NoError(t, err)
   332  			},
   333  			cleartTrackingFields,
   334  			300,
   335  			200,
   336  			100,
   337  			0,
   338  		},
   339  		{
   340  			"continuous vesting, start time and endtime passed",
   341  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   342  				startTime := ctx.BlockTime().AddDate(-2, 0, 0).Unix()
   343  				endTime := ctx.BlockTime().AddDate(-1, 0, 0).Unix()
   344  				baseAccount := createBaseAccount(delegatorAddr)
   345  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   346  				require.NoError(t, err)
   347  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
   348  				delayedAccount, err := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime)
   349  				require.NoError(t, err)
   350  
   351  				ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
   352  
   353  				accountKeeper.SetAccount(ctx, delayedAccount)
   354  
   355  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
   356  				require.NoError(t, err)
   357  			},
   358  			cleartTrackingFields,
   359  			300,
   360  			0,
   361  			300,
   362  			0,
   363  		},
   364  		{
   365  			"periodic vesting account, yet to be vested, some rewards delegated",
   366  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   367  				baseAccount := createBaseAccount(delegatorAddr)
   368  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   369  				require.NoError(t, err)
   370  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(100)))
   371  
   372  				start := ctx.BlockTime().Unix() + int64(time.Hour/time.Second)
   373  
   374  				periods := []types.Period{
   375  					{
   376  						Length: int64((24 * time.Hour) / time.Second),
   377  						Amount: vestedCoins,
   378  					},
   379  				}
   380  
   381  				account, err := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, start, periods)
   382  				require.NoError(t, err)
   383  
   384  				accountKeeper.SetAccount(ctx, account)
   385  
   386  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(150), stakingtypes.Unbonded, validator, true)
   387  				require.NoError(t, err)
   388  			},
   389  			cleartTrackingFields,
   390  			300,
   391  			100,
   392  			50,
   393  			0,
   394  		},
   395  		{
   396  			"periodic vesting account, nothing has vested yet",
   397  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   398  				/*
   399  					Test case:
   400  					 - periodic vesting account starts at time 1601042400
   401  					 - account balance and original vesting: 3666666670000
   402  					 - nothing has vested, we put the block time slightly after start time
   403  					 - expected vested: original vesting amount
   404  					 - expected free: zero
   405  					 - we're delegating the full original vesting
   406  				*/
   407  				startTime := int64(1601042400)
   408  				baseAccount := createBaseAccount(delegatorAddr)
   409  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   410  				require.NoError(t, err)
   411  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(3666666670000)))
   412  				periods := []types.Period{
   413  					{
   414  						Length: 31536000,
   415  						Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(1833333335000))),
   416  					},
   417  					{
   418  						Length: 15638400,
   419  						Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
   420  					},
   421  					{
   422  						Length: 15897600,
   423  						Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
   424  					},
   425  				}
   426  
   427  				delayedAccount, err := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
   428  				require.NoError(t, err)
   429  
   430  				accountKeeper.SetAccount(ctx, delayedAccount)
   431  
   432  				// delegation of the original vesting
   433  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(3666666670000), stakingtypes.Unbonded, validator, true)
   434  				require.NoError(t, err)
   435  			},
   436  			cleartTrackingFields,
   437  			3666666670000,
   438  			3666666670000,
   439  			0,
   440  			1601042400 + 1,
   441  		},
   442  		{
   443  			"periodic vesting account, all has vested",
   444  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   445  				/*
   446  					Test case:
   447  					 - periodic vesting account starts at time 1601042400
   448  					 - account balance and original vesting: 3666666670000
   449  					 - all has vested, so we set the block time at initial time + sum of all periods times + 1 => 1601042400 + 31536000 + 15897600 + 15897600 + 1
   450  					 - expected vested: zero
   451  					 - expected free: original vesting amount
   452  					 - we're delegating the full original vesting
   453  				*/
   454  				startTime := int64(1601042400)
   455  				baseAccount := createBaseAccount(delegatorAddr)
   456  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   457  				require.NoError(t, err)
   458  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(3666666670000)))
   459  				periods := []types.Period{
   460  					{
   461  						Length: 31536000,
   462  						Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(1833333335000))),
   463  					},
   464  					{
   465  						Length: 15638400,
   466  						Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
   467  					},
   468  					{
   469  						Length: 15897600,
   470  						Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
   471  					},
   472  				}
   473  
   474  				delayedAccount, err := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
   475  				require.NoError(t, err)
   476  
   477  				ctx = ctx.WithBlockTime(time.Unix(1601042400+31536000+15897600+15897600+1, 0))
   478  
   479  				accountKeeper.SetAccount(ctx, delayedAccount)
   480  
   481  				// delegation of the original vesting
   482  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(3666666670000), stakingtypes.Unbonded, validator, true)
   483  				require.NoError(t, err)
   484  			},
   485  			cleartTrackingFields,
   486  			3666666670000,
   487  			0,
   488  			3666666670000,
   489  			1601042400 + 31536000 + 15897600 + 15897600 + 1,
   490  		},
   491  		{
   492  			"periodic vesting account, first period has vested",
   493  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   494  				/*
   495  					Test case:
   496  					 - periodic vesting account starts at time 1601042400
   497  					 - account balance and original vesting: 3666666670000
   498  					 - first period have vested, so we set the block time at initial time + time of the first periods + 1 => 1601042400 + 31536000 + 1
   499  					 - expected vested: original vesting - first period amount
   500  					 - expected free: first period amount
   501  					 - we're delegating the full original vesting
   502  				*/
   503  				startTime := int64(1601042400)
   504  				baseAccount := createBaseAccount(delegatorAddr)
   505  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   506  				require.NoError(t, err)
   507  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(3666666670000)))
   508  				periods := []types.Period{
   509  					{
   510  						Length: 31536000,
   511  						Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(1833333335000))),
   512  					},
   513  					{
   514  						Length: 15638400,
   515  						Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
   516  					},
   517  					{
   518  						Length: 15897600,
   519  						Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
   520  					},
   521  				}
   522  
   523  				delayedAccount, err := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
   524  				require.NoError(t, err)
   525  
   526  				ctx = ctx.WithBlockTime(time.Unix(1601042400+31536000+1, 0))
   527  
   528  				accountKeeper.SetAccount(ctx, delayedAccount)
   529  
   530  				// delegation of the original vesting
   531  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(3666666670000), stakingtypes.Unbonded, validator, true)
   532  				require.NoError(t, err)
   533  			},
   534  			cleartTrackingFields,
   535  			3666666670000,
   536  			3666666670000 - 1833333335000,
   537  			1833333335000,
   538  			1601042400 + 31536000 + 1,
   539  		},
   540  		{
   541  			"periodic vesting account, first 2 period has vested",
   542  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   543  				/*
   544  					Test case:
   545  					 - periodic vesting account starts at time 1601042400
   546  					 - account balance and original vesting: 3666666670000
   547  					 - first 2 periods have vested, so we set the block time at initial time + time of the two periods + 1 => 1601042400 + 31536000 + 15638400 + 1
   548  					 - expected vested: original vesting - (sum of the first two periods amounts)
   549  					 - expected free: sum of the first two periods
   550  					 - we're delegating the full original vesting
   551  				*/
   552  				startTime := int64(1601042400)
   553  				baseAccount := createBaseAccount(delegatorAddr)
   554  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   555  				require.NoError(t, err)
   556  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(3666666670000)))
   557  				periods := []types.Period{
   558  					{
   559  						Length: 31536000,
   560  						Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(1833333335000))),
   561  					},
   562  					{
   563  						Length: 15638400,
   564  						Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
   565  					},
   566  					{
   567  						Length: 15897600,
   568  						Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
   569  					},
   570  				}
   571  
   572  				delayedAccount, err := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
   573  				require.NoError(t, err)
   574  
   575  				ctx = ctx.WithBlockTime(time.Unix(1601042400+31536000+15638400+1, 0))
   576  
   577  				accountKeeper.SetAccount(ctx, delayedAccount)
   578  
   579  				// delegation of the original vesting
   580  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(3666666670000), stakingtypes.Unbonded, validator, true)
   581  				require.NoError(t, err)
   582  			},
   583  			cleartTrackingFields,
   584  			3666666670000,
   585  			3666666670000 - 1833333335000 - 916666667500,
   586  			1833333335000 + 916666667500,
   587  			1601042400 + 31536000 + 15638400 + 1,
   588  		},
   589  		{
   590  			"vesting account has unbonding delegations in place",
   591  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   592  				baseAccount := createBaseAccount(delegatorAddr)
   593  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   594  				require.NoError(t, err)
   595  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
   596  
   597  				delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix())
   598  				require.NoError(t, err)
   599  
   600  				accountKeeper.SetAccount(ctx, delayedAccount)
   601  
   602  				// delegation of the original vesting
   603  				_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
   604  				require.NoError(t, err)
   605  
   606  				ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
   607  
   608  				valAddr, err := sdk.ValAddressFromBech32(validator.OperatorAddress)
   609  				require.NoError(t, err)
   610  
   611  				// un-delegation of the original vesting
   612  				_, _, err = stakingKeeper.Undelegate(ctx, delegatorAddr, valAddr, sdkmath.LegacyNewDecFromInt(sdkmath.NewInt(300)))
   613  				require.NoError(t, err)
   614  			},
   615  			cleartTrackingFields,
   616  			450,
   617  			300,
   618  			0,
   619  			0,
   620  		},
   621  		{
   622  			"vesting account has never delegated anything",
   623  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   624  				baseAccount := createBaseAccount(delegatorAddr)
   625  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   626  				require.NoError(t, err)
   627  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
   628  
   629  				delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix())
   630  				require.NoError(t, err)
   631  
   632  				accountKeeper.SetAccount(ctx, delayedAccount)
   633  			},
   634  			cleartTrackingFields,
   635  			450,
   636  			0,
   637  			0,
   638  			0,
   639  		},
   640  		{
   641  			"vesting account has no delegation but dirty DelegatedFree and DelegatedVesting fields",
   642  			func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
   643  				baseAccount := createBaseAccount(delegatorAddr)
   644  				bondDenom, err := stakingKeeper.BondDenom(ctx)
   645  				require.NoError(t, err)
   646  				vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
   647  
   648  				delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix())
   649  				require.NoError(t, err)
   650  
   651  				accountKeeper.SetAccount(ctx, delayedAccount)
   652  			},
   653  			dirtyTrackingFields,
   654  			450,
   655  			0,
   656  			0,
   657  			0,
   658  		},
   659  	}
   660  
   661  	for _, tc := range testCases {
   662  		tc := tc
   663  		t.Run(tc.name, func(t *testing.T) {
   664  			err := accountKeeper.Params.Set(ctx, authtypes.DefaultParams())
   665  			require.NoError(t, err)
   666  
   667  			addrs := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 1, sdkmath.NewInt(tc.tokenAmount))
   668  			delegatorAddr := addrs[0]
   669  
   670  			_, valAddr := createValidator(t, ctx, bankKeeper, stakingKeeper, tc.tokenAmount*2)
   671  			validator, err := stakingKeeper.GetValidator(ctx, valAddr)
   672  			require.NoError(t, err)
   673  
   674  			tc.prepareFunc(ctx, validator, delegatorAddr)
   675  
   676  			if tc.blockTime != 0 {
   677  				ctx = ctx.WithBlockTime(time.Unix(tc.blockTime, 0))
   678  			}
   679  
   680  			// We introduce the bug
   681  			savedAccount := accountKeeper.GetAccount(ctx, delegatorAddr)
   682  			vestingAccount, ok := savedAccount.(exported.VestingAccount)
   683  			require.True(t, ok)
   684  			require.NoError(t, tc.garbageFunc(ctx, vestingAccount, accountKeeper))
   685  
   686  			m := keeper.NewMigrator(accountKeeper, app.GRPCQueryRouter(), legacySubspace)
   687  			require.NoError(t, m.Migrate1to2(ctx))
   688  
   689  			var expVested sdk.Coins
   690  			var expFree sdk.Coins
   691  
   692  			bondDenom, err := stakingKeeper.BondDenom(ctx)
   693  			require.NoError(t, err)
   694  
   695  			if tc.expVested != 0 {
   696  				expVested = sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(tc.expVested)))
   697  			}
   698  
   699  			if tc.expFree != 0 {
   700  				expFree = sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(tc.expFree)))
   701  			}
   702  
   703  			trackingCorrected(
   704  				ctx,
   705  				t,
   706  				accountKeeper,
   707  				savedAccount.GetAddress(),
   708  				expVested,
   709  				expFree,
   710  			)
   711  		})
   712  	}
   713  }
   714  
   715  func trackingCorrected(ctx sdk.Context, t *testing.T, ak keeper.AccountKeeper, addr sdk.AccAddress, expDelVesting, expDelFree sdk.Coins) {
   716  	t.Helper()
   717  	baseAccount := ak.GetAccount(ctx, addr)
   718  	vDA, ok := baseAccount.(exported.VestingAccount)
   719  	require.True(t, ok)
   720  
   721  	vestedOk := expDelVesting.Equal(vDA.GetDelegatedVesting())
   722  	freeOk := expDelFree.Equal(vDA.GetDelegatedFree())
   723  	require.True(t, vestedOk, vDA.GetDelegatedVesting().String())
   724  	require.True(t, freeOk, vDA.GetDelegatedFree().String())
   725  }
   726  
   727  func cleartTrackingFields(ctx sdk.Context, vesting exported.VestingAccount, accountKeeper keeper.AccountKeeper) error {
   728  	switch t := vesting.(type) {
   729  	case *types.DelayedVestingAccount:
   730  		t.DelegatedFree = nil
   731  		t.DelegatedVesting = nil
   732  		accountKeeper.SetAccount(ctx, t)
   733  	case *types.ContinuousVestingAccount:
   734  		t.DelegatedFree = nil
   735  		t.DelegatedVesting = nil
   736  		accountKeeper.SetAccount(ctx, t)
   737  	case *types.PeriodicVestingAccount:
   738  		t.DelegatedFree = nil
   739  		t.DelegatedVesting = nil
   740  		accountKeeper.SetAccount(ctx, t)
   741  	default:
   742  		return fmt.Errorf("expected vesting account, found %t", t)
   743  	}
   744  
   745  	return nil
   746  }
   747  
   748  func dirtyTrackingFields(ctx sdk.Context, vesting exported.VestingAccount, accountKeeper keeper.AccountKeeper) error {
   749  	dirt := sdk.NewCoins(sdk.NewInt64Coin("stake", 42))
   750  
   751  	switch t := vesting.(type) {
   752  	case *types.DelayedVestingAccount:
   753  		t.DelegatedFree = dirt
   754  		t.DelegatedVesting = dirt
   755  		accountKeeper.SetAccount(ctx, t)
   756  	case *types.ContinuousVestingAccount:
   757  		t.DelegatedFree = dirt
   758  		t.DelegatedVesting = dirt
   759  		accountKeeper.SetAccount(ctx, t)
   760  	case *types.PeriodicVestingAccount:
   761  		t.DelegatedFree = dirt
   762  		t.DelegatedVesting = dirt
   763  		accountKeeper.SetAccount(ctx, t)
   764  	default:
   765  		return fmt.Errorf("expected vesting account, found %t", t)
   766  	}
   767  
   768  	return nil
   769  }
   770  
   771  func createValidator(t *testing.T, ctx sdk.Context, bankKeeper bankkeeper.Keeper, stakingKeeper *stakingkeeper.Keeper, powers int64) (sdk.AccAddress, sdk.ValAddress) {
   772  	valTokens := sdk.TokensFromConsensusPower(powers, sdk.DefaultPowerReduction)
   773  	addrs := simtestutil.AddTestAddrsIncremental(bankKeeper, stakingKeeper, ctx, 1, valTokens)
   774  	valAddrs := simtestutil.ConvertAddrsToValAddrs(addrs)
   775  	pks := simtestutil.CreateTestPubKeys(1)
   776  
   777  	val1, err := stakingtypes.NewValidator(valAddrs[0].String(), pks[0], stakingtypes.Description{})
   778  	require.NoError(t, err)
   779  
   780  	stakingKeeper.SetValidator(ctx, val1)
   781  	require.NoError(t, stakingKeeper.SetValidatorByConsAddr(ctx, val1))
   782  	stakingKeeper.SetNewValidatorByPowerIndex(ctx, val1)
   783  
   784  	_, err = stakingKeeper.Delegate(ctx, addrs[0], valTokens, stakingtypes.Unbonded, val1, true)
   785  	require.NoError(t, err)
   786  
   787  	stakingKeeper.EndBlocker(ctx)
   788  
   789  	return addrs[0], valAddrs[0]
   790  }