mukan-sdk/x/auth/migrations/v2/store_test.go
Mukan Erkin Törük abb1ff956e
Some checks are pending
Build SimApp / build (amd64) (push) Waiting to run
Build SimApp / build (arm64) (push) Waiting to run
CodeQL / Analyze (push) Waiting to run
Build & Push / build (push) Waiting to run
Run Gosec / Gosec (push) Waiting to run
Lint / golangci-lint (push) Waiting to run
Checks dependencies and mocks generation / Check go mod tidy (push) Waiting to run
Checks dependencies and mocks generation / Check up to date mocks (push) Waiting to run
System Tests / setup (push) Waiting to run
System Tests / test-system (push) Blocked by required conditions
System Tests / test-system-legacy (push) Blocked by required conditions
Tests / Code Coverage / split-test-files (push) Waiting to run
Tests / Code Coverage / tests (00) (push) Blocked by required conditions
Tests / Code Coverage / tests (01) (push) Blocked by required conditions
Tests / Code Coverage / tests (02) (push) Blocked by required conditions
Tests / Code Coverage / tests (03) (push) Blocked by required conditions
Tests / Code Coverage / test-integration (push) Waiting to run
Tests / Code Coverage / test-e2e (push) Waiting to run
Tests / Code Coverage / repo-analysis (push) Blocked by required conditions
Tests / Code Coverage / test-sim-nondeterminism (push) Waiting to run
Tests / Code Coverage / test-clientv2 (push) Waiting to run
Tests / Code Coverage / test-core (push) Waiting to run
Tests / Code Coverage / test-depinject (push) Waiting to run
Tests / Code Coverage / test-errors (push) Waiting to run
Tests / Code Coverage / test-math (push) Waiting to run
Tests / Code Coverage / test-schema (push) Waiting to run
Tests / Code Coverage / test-collections (push) Waiting to run
Tests / Code Coverage / test-cosmovisor (push) Waiting to run
Tests / Code Coverage / test-confix (push) Waiting to run
Tests / Code Coverage / test-store (push) Waiting to run
Tests / Code Coverage / test-log (push) Waiting to run
Tests / Code Coverage / test-x-tx (push) Waiting to run
Tests / Code Coverage / test-x-nft (push) Waiting to run
Tests / Code Coverage / test-x-circuit (push) Waiting to run
Tests / Code Coverage / test-x-feegrant (push) Waiting to run
Tests / Code Coverage / test-x-evidence (push) Waiting to run
Tests / Code Coverage / test-x-upgrade (push) Waiting to run
Tests / Code Coverage / test-tools-benchmark (push) Waiting to run
refactor: complete sovereign stack cleanup — all github.com upstream refs purged
2026-05-11 03:46:06 +03:00

792 lines
28 KiB
Go

package v2_test
import (
"fmt"
"sync/atomic"
"testing"
"time"
cmtproto "git.cw.tr/mukan-network/mukan-consensus/proto/tendermint/types"
"github.com/stretchr/testify/require"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
sdkmath "cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"
"git.cw.tr/mukan-network/mukan-sdk/runtime"
"git.cw.tr/mukan-network/mukan-sdk/testutil"
simtestutil "git.cw.tr/mukan-network/mukan-sdk/testutil/sims"
sdk "git.cw.tr/mukan-network/mukan-sdk/types"
moduletestutil "git.cw.tr/mukan-network/mukan-sdk/types/module/testutil"
"git.cw.tr/mukan-network/mukan-sdk/x/auth"
authexported "git.cw.tr/mukan-network/mukan-sdk/x/auth/exported"
"git.cw.tr/mukan-network/mukan-sdk/x/auth/keeper"
v1 "git.cw.tr/mukan-network/mukan-sdk/x/auth/migrations/v1"
v4 "git.cw.tr/mukan-network/mukan-sdk/x/auth/migrations/v4"
authtestutil "git.cw.tr/mukan-network/mukan-sdk/x/auth/testutil"
authtypes "git.cw.tr/mukan-network/mukan-sdk/x/auth/types"
"git.cw.tr/mukan-network/mukan-sdk/x/auth/vesting/exported"
"git.cw.tr/mukan-network/mukan-sdk/x/auth/vesting/types"
bankkeeper "git.cw.tr/mukan-network/mukan-sdk/x/bank/keeper"
stakingkeeper "git.cw.tr/mukan-network/mukan-sdk/x/staking/keeper"
stakingtypes "git.cw.tr/mukan-network/mukan-sdk/x/staking/types"
)
type mockSubspace struct {
ps authtypes.Params
}
func newMockSubspace(ps authtypes.Params) mockSubspace {
return mockSubspace{ps: ps}
}
func (ms mockSubspace) GetParamSet(ctx sdk.Context, ps authexported.ParamSet) {
*ps.(*authtypes.Params) = ms.ps
}
func TestMigrateVestingAccounts(t *testing.T) {
encCfg := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{})
cdc := encCfg.Codec
storeKey := storetypes.NewKVStoreKey(v1.ModuleName)
tKey := storetypes.NewTransientStoreKey("transient_test")
ctx := testutil.DefaultContext(storeKey, tKey)
storeService := runtime.NewKVStoreService(storeKey)
var (
accountKeeper keeper.AccountKeeper
bankKeeper bankkeeper.Keeper
stakingKeeper *stakingkeeper.Keeper
)
app, err := simtestutil.Setup(
depinject.Configs(
authtestutil.AppConfig,
depinject.Supply(log.NewNopLogger()),
),
&accountKeeper,
&bankKeeper,
&stakingKeeper,
)
require.NoError(t, err)
legacySubspace := newMockSubspace(authtypes.DefaultParams())
require.NoError(t, v4.Migrate(ctx, storeService, legacySubspace, cdc))
ctx = app.NewContextLegacy(false, cmtproto.Header{Time: time.Now()})
require.NoError(t, stakingKeeper.SetParams(ctx, stakingtypes.DefaultParams()))
lastAccNum := uint64(1000)
createBaseAccount := func(addr sdk.AccAddress) *authtypes.BaseAccount {
baseAccount := authtypes.NewBaseAccountWithAddress(addr)
require.NoError(t, baseAccount.SetAccountNumber(atomic.AddUint64(&lastAccNum, 1)))
return baseAccount
}
testCases := []struct {
name string
prepareFunc func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress)
garbageFunc func(ctx sdk.Context, vesting exported.VestingAccount, accounKeeper keeper.AccountKeeper) error
tokenAmount int64
expVested int64
expFree int64
blockTime int64
}{
{
"delayed vesting has vested, multiple delegations less than the total account balance",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(200)))
delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
require.NoError(t, err)
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
err = accountKeeper.Params.Set(ctx, authtypes.DefaultParams())
require.NoError(t, err)
accountKeeper.SetAccount(ctx, delayedAccount)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
0,
300,
0,
},
{
"delayed vesting has vested, single delegations which exceed the vested amount",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
baseAccount := createBaseAccount(delegatorAddr)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(200)))
delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
require.NoError(t, err)
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
accountKeeper.SetAccount(ctx, delayedAccount)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
0,
300,
0,
},
{
"delayed vesting has vested, multiple delegations which exceed the vested amount",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(200)))
delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
require.NoError(t, err)
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
accountKeeper.SetAccount(ctx, delayedAccount)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
0,
300,
0,
},
{
"delayed vesting has not vested, single delegations which exceed the vested amount",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(200)))
delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
require.NoError(t, err)
accountKeeper.SetAccount(ctx, delayedAccount)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
200,
100,
0,
},
{
"delayed vesting has not vested, multiple delegations which exceed the vested amount",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(200)))
delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
require.NoError(t, err)
accountKeeper.SetAccount(ctx, delayedAccount)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
200,
100,
0,
},
{
"not end time",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
require.NoError(t, err)
accountKeeper.SetAccount(ctx, delayedAccount)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(100), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
300,
0,
0,
},
{
"delayed vesting has not vested, single delegation greater than the total account balance",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
require.NoError(t, err)
accountKeeper.SetAccount(ctx, delayedAccount)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
300,
0,
0,
},
{
"delayed vesting has vested, single delegation greater than the total account balance",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
require.NoError(t, err)
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
accountKeeper.SetAccount(ctx, delayedAccount)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
0,
300,
0,
},
{
"continuous vesting, start time after blocktime",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
startTime := ctx.BlockTime().AddDate(1, 0, 0).Unix()
endTime := ctx.BlockTime().AddDate(2, 0, 0).Unix()
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
delayedAccount, err := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime)
require.NoError(t, err)
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
accountKeeper.SetAccount(ctx, delayedAccount)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
300,
0,
0,
},
{
"continuous vesting, start time passed but not ended",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
startTime := ctx.BlockTime().AddDate(-1, 0, 0).Unix()
endTime := ctx.BlockTime().AddDate(2, 0, 0).Unix()
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
delayedAccount, err := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime)
require.NoError(t, err)
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
accountKeeper.SetAccount(ctx, delayedAccount)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
200,
100,
0,
},
{
"continuous vesting, start time and endtime passed",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
startTime := ctx.BlockTime().AddDate(-2, 0, 0).Unix()
endTime := ctx.BlockTime().AddDate(-1, 0, 0).Unix()
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
delayedAccount, err := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime)
require.NoError(t, err)
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
accountKeeper.SetAccount(ctx, delayedAccount)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
0,
300,
0,
},
{
"periodic vesting account, yet to be vested, some rewards delegated",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(100)))
start := ctx.BlockTime().Unix() + int64(time.Hour/time.Second)
periods := []types.Period{
{
Length: int64((24 * time.Hour) / time.Second),
Amount: vestedCoins,
},
}
account, err := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, start, periods)
require.NoError(t, err)
accountKeeper.SetAccount(ctx, account)
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(150), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
300,
100,
50,
0,
},
{
"periodic vesting account, nothing has vested yet",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
/*
Test case:
- periodic vesting account starts at time 1601042400
- account balance and original vesting: 3666666670000
- nothing has vested, we put the block time slightly after start time
- expected vested: original vesting amount
- expected free: zero
- we're delegating the full original vesting
*/
startTime := int64(1601042400)
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(3666666670000)))
periods := []types.Period{
{
Length: 31536000,
Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(1833333335000))),
},
{
Length: 15638400,
Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
},
{
Length: 15897600,
Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
},
}
delayedAccount, err := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
require.NoError(t, err)
accountKeeper.SetAccount(ctx, delayedAccount)
// delegation of the original vesting
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(3666666670000), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
3666666670000,
3666666670000,
0,
1601042400 + 1,
},
{
"periodic vesting account, all has vested",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
/*
Test case:
- periodic vesting account starts at time 1601042400
- account balance and original vesting: 3666666670000
- all has vested, so we set the block time at initial time + sum of all periods times + 1 => 1601042400 + 31536000 + 15897600 + 15897600 + 1
- expected vested: zero
- expected free: original vesting amount
- we're delegating the full original vesting
*/
startTime := int64(1601042400)
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(3666666670000)))
periods := []types.Period{
{
Length: 31536000,
Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(1833333335000))),
},
{
Length: 15638400,
Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
},
{
Length: 15897600,
Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
},
}
delayedAccount, err := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
require.NoError(t, err)
ctx = ctx.WithBlockTime(time.Unix(1601042400+31536000+15897600+15897600+1, 0))
accountKeeper.SetAccount(ctx, delayedAccount)
// delegation of the original vesting
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(3666666670000), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
3666666670000,
0,
3666666670000,
1601042400 + 31536000 + 15897600 + 15897600 + 1,
},
{
"periodic vesting account, first period has vested",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
/*
Test case:
- periodic vesting account starts at time 1601042400
- account balance and original vesting: 3666666670000
- first period have vested, so we set the block time at initial time + time of the first periods + 1 => 1601042400 + 31536000 + 1
- expected vested: original vesting - first period amount
- expected free: first period amount
- we're delegating the full original vesting
*/
startTime := int64(1601042400)
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(3666666670000)))
periods := []types.Period{
{
Length: 31536000,
Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(1833333335000))),
},
{
Length: 15638400,
Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
},
{
Length: 15897600,
Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
},
}
delayedAccount, err := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
require.NoError(t, err)
ctx = ctx.WithBlockTime(time.Unix(1601042400+31536000+1, 0))
accountKeeper.SetAccount(ctx, delayedAccount)
// delegation of the original vesting
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(3666666670000), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
3666666670000,
3666666670000 - 1833333335000,
1833333335000,
1601042400 + 31536000 + 1,
},
{
"periodic vesting account, first 2 period has vested",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
/*
Test case:
- periodic vesting account starts at time 1601042400
- account balance and original vesting: 3666666670000
- first 2 periods have vested, so we set the block time at initial time + time of the two periods + 1 => 1601042400 + 31536000 + 15638400 + 1
- expected vested: original vesting - (sum of the first two periods amounts)
- expected free: sum of the first two periods
- we're delegating the full original vesting
*/
startTime := int64(1601042400)
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(3666666670000)))
periods := []types.Period{
{
Length: 31536000,
Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(1833333335000))),
},
{
Length: 15638400,
Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
},
{
Length: 15897600,
Amount: sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(916666667500))),
},
}
delayedAccount, err := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
require.NoError(t, err)
ctx = ctx.WithBlockTime(time.Unix(1601042400+31536000+15638400+1, 0))
accountKeeper.SetAccount(ctx, delayedAccount)
// delegation of the original vesting
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(3666666670000), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
},
cleartTrackingFields,
3666666670000,
3666666670000 - 1833333335000 - 916666667500,
1833333335000 + 916666667500,
1601042400 + 31536000 + 15638400 + 1,
},
{
"vesting account has unbonding delegations in place",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix())
require.NoError(t, err)
accountKeeper.SetAccount(ctx, delayedAccount)
// delegation of the original vesting
_, err = stakingKeeper.Delegate(ctx, delegatorAddr, sdkmath.NewInt(300), stakingtypes.Unbonded, validator, true)
require.NoError(t, err)
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
valAddr, err := sdk.ValAddressFromBech32(validator.OperatorAddress)
require.NoError(t, err)
// un-delegation of the original vesting
_, _, err = stakingKeeper.Undelegate(ctx, delegatorAddr, valAddr, sdkmath.LegacyNewDecFromInt(sdkmath.NewInt(300)))
require.NoError(t, err)
},
cleartTrackingFields,
450,
300,
0,
0,
},
{
"vesting account has never delegated anything",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix())
require.NoError(t, err)
accountKeeper.SetAccount(ctx, delayedAccount)
},
cleartTrackingFields,
450,
0,
0,
0,
},
{
"vesting account has no delegation but dirty DelegatedFree and DelegatedVesting fields",
func(ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
baseAccount := createBaseAccount(delegatorAddr)
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
vestedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(300)))
delayedAccount, err := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix())
require.NoError(t, err)
accountKeeper.SetAccount(ctx, delayedAccount)
},
dirtyTrackingFields,
450,
0,
0,
0,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := accountKeeper.Params.Set(ctx, authtypes.DefaultParams())
require.NoError(t, err)
addrs := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 1, sdkmath.NewInt(tc.tokenAmount))
delegatorAddr := addrs[0]
_, valAddr := createValidator(t, ctx, bankKeeper, stakingKeeper, tc.tokenAmount*2)
validator, err := stakingKeeper.GetValidator(ctx, valAddr)
require.NoError(t, err)
tc.prepareFunc(ctx, validator, delegatorAddr)
if tc.blockTime != 0 {
ctx = ctx.WithBlockTime(time.Unix(tc.blockTime, 0))
}
// We introduce the bug
savedAccount := accountKeeper.GetAccount(ctx, delegatorAddr)
vestingAccount, ok := savedAccount.(exported.VestingAccount)
require.True(t, ok)
require.NoError(t, tc.garbageFunc(ctx, vestingAccount, accountKeeper))
m := keeper.NewMigrator(accountKeeper, app.GRPCQueryRouter(), legacySubspace)
require.NoError(t, m.Migrate1to2(ctx))
var expVested sdk.Coins
var expFree sdk.Coins
bondDenom, err := stakingKeeper.BondDenom(ctx)
require.NoError(t, err)
if tc.expVested != 0 {
expVested = sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(tc.expVested)))
}
if tc.expFree != 0 {
expFree = sdk.NewCoins(sdk.NewCoin(bondDenom, sdkmath.NewInt(tc.expFree)))
}
trackingCorrected(
t,
ctx,
accountKeeper,
savedAccount.GetAddress(),
expVested,
expFree,
)
})
}
}
func trackingCorrected(t *testing.T, ctx sdk.Context, ak keeper.AccountKeeper, addr sdk.AccAddress, expDelVesting, expDelFree sdk.Coins) {
t.Helper()
baseAccount := ak.GetAccount(ctx, addr)
vDA, ok := baseAccount.(exported.VestingAccount)
require.True(t, ok)
vestedOk := expDelVesting.Equal(vDA.GetDelegatedVesting())
freeOk := expDelFree.Equal(vDA.GetDelegatedFree())
require.True(t, vestedOk, vDA.GetDelegatedVesting().String())
require.True(t, freeOk, vDA.GetDelegatedFree().String())
}
func cleartTrackingFields(ctx sdk.Context, vesting exported.VestingAccount, accountKeeper keeper.AccountKeeper) error {
switch t := vesting.(type) {
case *types.DelayedVestingAccount:
t.DelegatedFree = nil
t.DelegatedVesting = nil
accountKeeper.SetAccount(ctx, t)
case *types.ContinuousVestingAccount:
t.DelegatedFree = nil
t.DelegatedVesting = nil
accountKeeper.SetAccount(ctx, t)
case *types.PeriodicVestingAccount:
t.DelegatedFree = nil
t.DelegatedVesting = nil
accountKeeper.SetAccount(ctx, t)
default:
return fmt.Errorf("expected vesting account, found %t", t)
}
return nil
}
func dirtyTrackingFields(ctx sdk.Context, vesting exported.VestingAccount, accountKeeper keeper.AccountKeeper) error {
dirt := sdk.NewCoins(sdk.NewInt64Coin("stake", 42))
switch t := vesting.(type) {
case *types.DelayedVestingAccount:
t.DelegatedFree = dirt
t.DelegatedVesting = dirt
accountKeeper.SetAccount(ctx, t)
case *types.ContinuousVestingAccount:
t.DelegatedFree = dirt
t.DelegatedVesting = dirt
accountKeeper.SetAccount(ctx, t)
case *types.PeriodicVestingAccount:
t.DelegatedFree = dirt
t.DelegatedVesting = dirt
accountKeeper.SetAccount(ctx, t)
default:
return fmt.Errorf("expected vesting account, found %t", t)
}
return nil
}
func createValidator(t *testing.T, ctx sdk.Context, bankKeeper bankkeeper.Keeper, stakingKeeper *stakingkeeper.Keeper, powers int64) (sdk.AccAddress, sdk.ValAddress) {
t.Helper()
valTokens := sdk.TokensFromConsensusPower(powers, sdk.DefaultPowerReduction)
addrs := simtestutil.AddTestAddrsIncremental(bankKeeper, stakingKeeper, ctx, 1, valTokens)
valAddrs := simtestutil.ConvertAddrsToValAddrs(addrs)
pks := simtestutil.CreateTestPubKeys(1)
val1, err := stakingtypes.NewValidator(valAddrs[0].String(), pks[0], stakingtypes.Description{})
require.NoError(t, err)
require.NoError(t, stakingKeeper.SetValidator(ctx, val1))
require.NoError(t, stakingKeeper.SetValidatorByConsAddr(ctx, val1))
require.NoError(t, stakingKeeper.SetNewValidatorByPowerIndex(ctx, val1))
_, err = stakingKeeper.Delegate(ctx, addrs[0], valTokens, stakingtypes.Unbonded, val1, true)
require.NoError(t, err)
_, err = stakingKeeper.EndBlocker(ctx)
require.NoError(t, err)
return addrs[0], valAddrs[0]
}