Write back account changes after tracking delegation/undelegation for vesting accounts (#8865)
Delegations and undelegations calculations performed during accounting operations for vesting accounts were correct but were not written back to the account store. closes: #8601 closes: #8812 Co-authored-by: Alessio Treglia <alessio@tendermint.com> Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: Jonathan Gimeno <jgimeno@gmail.com> Co-authored-by: Frojdi Dymylja <frojdi.dymylja@gmail.com> Co-authored-by: Adam Bozanich <adam.boz@gmail.com> Co-authored-by: Amaury <1293565+amaurym@users.noreply.github.com> Co-authored-by: SaReN <sahithnarahari@gmail.com>
This commit is contained in:
parent
3a5550a938
commit
93965e0bcc
@ -206,7 +206,7 @@ func (ak AccountKeeper) GetModuleAccount(ctx sdk.Context, moduleName string) typ
|
||||
}
|
||||
|
||||
// SetModuleAccount sets the module account to the auth account store
|
||||
func (ak AccountKeeper) SetModuleAccount(ctx sdk.Context, macc types.ModuleAccountI) { //nolint:interfacer
|
||||
func (ak AccountKeeper) SetModuleAccount(ctx sdk.Context, macc types.ModuleAccountI) {
|
||||
ak.SetAccount(ctx, macc)
|
||||
}
|
||||
|
||||
|
||||
42
x/auth/keeper/migrations.go
Normal file
42
x/auth/keeper/migrations.go
Normal file
@ -0,0 +1,42 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
v043 "github.com/cosmos/cosmos-sdk/x/auth/legacy/v043"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/gogo/protobuf/grpc"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// Migrator is a struct for handling in-place store migrations.
|
||||
type Migrator struct {
|
||||
keeper AccountKeeper
|
||||
queryServer grpc.Server
|
||||
}
|
||||
|
||||
// NewMigrator returns a new Migrator.
|
||||
func NewMigrator(keeper AccountKeeper, queryServer grpc.Server) Migrator {
|
||||
return Migrator{keeper: keeper, queryServer: queryServer}
|
||||
}
|
||||
|
||||
// Migrate1to2 migrates from version 1 to 2.
|
||||
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
|
||||
var iterErr error
|
||||
|
||||
m.keeper.IterateAccounts(ctx, func(account types.AccountI) (stop bool) {
|
||||
wb, err := v043.MigrateAccount(ctx, account, m.queryServer)
|
||||
if err != nil {
|
||||
iterErr = err
|
||||
return true
|
||||
}
|
||||
|
||||
if wb == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
m.keeper.SetAccount(ctx, wb)
|
||||
return false
|
||||
})
|
||||
|
||||
return iterErr
|
||||
}
|
||||
268
x/auth/legacy/v043/store.go
Normal file
268
x/auth/legacy/v043/store.go
Normal file
@ -0,0 +1,268 @@
|
||||
package v043
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/vesting/exported"
|
||||
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
"github.com/gogo/protobuf/grpc"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const (
|
||||
delegatorDelegationPath = "/cosmos.staking.v1beta1.Query/DelegatorDelegations"
|
||||
stakingParamsPath = "/cosmos.staking.v1beta1.Query/Params"
|
||||
delegatorUnbondingDelegationsPath = "/cosmos.staking.v1beta1.Query/DelegatorUnbondingDelegations"
|
||||
balancesPath = "/cosmos.bank.v1beta1.Query/AllBalances"
|
||||
)
|
||||
|
||||
func migrateVestingAccounts(ctx sdk.Context, account types.AccountI, queryServer grpc.Server) (types.AccountI, error) {
|
||||
bondDenom, err := getBondDenom(ctx, queryServer)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
asVesting, ok := account.(exported.VestingAccount)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
addr := account.GetAddress().String()
|
||||
balance, err := getBalance(
|
||||
ctx,
|
||||
addr,
|
||||
queryServer,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
delegations, err := getDelegatorDelegationsSum(
|
||||
ctx,
|
||||
addr,
|
||||
queryServer,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
unbondingDelegations, err := getDelegatorUnbondingDelegationsSum(
|
||||
ctx,
|
||||
addr,
|
||||
bondDenom,
|
||||
queryServer,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
delegations = delegations.Add(unbondingDelegations...)
|
||||
|
||||
asVesting, ok = resetVestingDelegatedBalances(asVesting)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// balance before any delegation includes balance of delegation
|
||||
for _, coin := range delegations {
|
||||
balance = balance.Add(coin)
|
||||
}
|
||||
|
||||
asVesting.TrackDelegation(ctx.BlockTime(), balance, delegations)
|
||||
|
||||
return asVesting.(types.AccountI), nil
|
||||
}
|
||||
|
||||
func resetVestingDelegatedBalances(evacct exported.VestingAccount) (exported.VestingAccount, bool) {
|
||||
// reset `DelegatedVesting` and `DelegatedFree` to zero
|
||||
df := sdk.NewCoins()
|
||||
dv := sdk.NewCoins()
|
||||
|
||||
switch vacct := evacct.(type) {
|
||||
case *vestingtypes.ContinuousVestingAccount:
|
||||
vacct.DelegatedVesting = dv
|
||||
vacct.DelegatedFree = df
|
||||
return vacct, true
|
||||
case *vestingtypes.DelayedVestingAccount:
|
||||
vacct.DelegatedVesting = dv
|
||||
vacct.DelegatedFree = df
|
||||
return vacct, true
|
||||
case *vestingtypes.PeriodicVestingAccount:
|
||||
vacct.DelegatedVesting = dv
|
||||
vacct.DelegatedFree = df
|
||||
return vacct, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
func getDelegatorDelegationsSum(ctx sdk.Context, address string, queryServer grpc.Server) (sdk.Coins, error) {
|
||||
querier, ok := queryServer.(*baseapp.GRPCQueryRouter)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected type: %T wanted *baseapp.GRPCQueryRouter", queryServer)
|
||||
}
|
||||
|
||||
queryFn := querier.Route(delegatorDelegationPath)
|
||||
|
||||
q := &stakingtypes.QueryDelegatorDelegationsRequest{
|
||||
DelegatorAddr: address,
|
||||
}
|
||||
|
||||
b, err := proto.Marshal(q)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot marshal staking type query request, %w", err)
|
||||
}
|
||||
req := abci.RequestQuery{
|
||||
Data: b,
|
||||
Path: delegatorDelegationPath,
|
||||
}
|
||||
resp, err := queryFn(ctx, req)
|
||||
if err != nil {
|
||||
e, ok := status.FromError(err)
|
||||
if ok && e.Code() == codes.NotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf("staking query error, %w", err)
|
||||
}
|
||||
|
||||
balance := new(stakingtypes.QueryDelegatorDelegationsResponse)
|
||||
if err := proto.Unmarshal(resp.Value, balance); err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal delegator query delegations: %w", err)
|
||||
}
|
||||
|
||||
res := sdk.NewCoins()
|
||||
for _, i := range balance.DelegationResponses {
|
||||
res = res.Add(i.Balance)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func getDelegatorUnbondingDelegationsSum(ctx sdk.Context, address, bondDenom string, queryServer grpc.Server) (sdk.Coins, error) {
|
||||
querier, ok := queryServer.(*baseapp.GRPCQueryRouter)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected type: %T wanted *baseapp.GRPCQueryRouter", queryServer)
|
||||
}
|
||||
|
||||
queryFn := querier.Route(delegatorUnbondingDelegationsPath)
|
||||
|
||||
q := &stakingtypes.QueryDelegatorUnbondingDelegationsRequest{
|
||||
DelegatorAddr: address,
|
||||
}
|
||||
|
||||
b, err := proto.Marshal(q)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot marshal staking type query request, %w", err)
|
||||
}
|
||||
req := abci.RequestQuery{
|
||||
Data: b,
|
||||
Path: delegatorUnbondingDelegationsPath,
|
||||
}
|
||||
resp, err := queryFn(ctx, req)
|
||||
if err != nil && !errors.Is(err, sdkerrors.ErrNotFound) {
|
||||
e, ok := status.FromError(err)
|
||||
if ok && e.Code() == codes.NotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf("staking query error, %w", err)
|
||||
}
|
||||
|
||||
balance := new(stakingtypes.QueryDelegatorUnbondingDelegationsResponse)
|
||||
if err := proto.Unmarshal(resp.Value, balance); err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal delegator query delegations: %w", err)
|
||||
}
|
||||
|
||||
res := sdk.NewCoins()
|
||||
for _, i := range balance.UnbondingResponses {
|
||||
for _, r := range i.Entries {
|
||||
res = res.Add(sdk.NewCoin(bondDenom, r.Balance))
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func getBalance(ctx sdk.Context, address string, queryServer grpc.Server) (sdk.Coins, error) {
|
||||
querier, ok := queryServer.(*baseapp.GRPCQueryRouter)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected type: %T wanted *baseapp.GRPCQueryRouter", queryServer)
|
||||
}
|
||||
|
||||
queryFn := querier.Route(balancesPath)
|
||||
|
||||
q := &banktypes.QueryAllBalancesRequest{
|
||||
Address: address,
|
||||
Pagination: nil,
|
||||
}
|
||||
b, err := proto.Marshal(q)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot marshal bank type query request, %w", err)
|
||||
}
|
||||
|
||||
req := abci.RequestQuery{
|
||||
Data: b,
|
||||
Path: balancesPath,
|
||||
}
|
||||
resp, err := queryFn(ctx, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("bank query error, %w", err)
|
||||
}
|
||||
balance := new(banktypes.QueryAllBalancesResponse)
|
||||
if err := proto.Unmarshal(resp.Value, balance); err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal bank balance response: %w", err)
|
||||
}
|
||||
return balance.Balances, nil
|
||||
}
|
||||
|
||||
func getBondDenom(ctx sdk.Context, queryServer grpc.Server) (string, error) {
|
||||
querier, ok := queryServer.(*baseapp.GRPCQueryRouter)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unexpected type: %T wanted *baseapp.GRPCQueryRouter", queryServer)
|
||||
}
|
||||
|
||||
queryFn := querier.Route(stakingParamsPath)
|
||||
|
||||
q := &stakingtypes.QueryParamsRequest{}
|
||||
|
||||
b, err := proto.Marshal(q)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("cannot marshal staking params query request, %w", err)
|
||||
}
|
||||
req := abci.RequestQuery{
|
||||
Data: b,
|
||||
Path: stakingParamsPath,
|
||||
}
|
||||
|
||||
resp, err := queryFn(ctx, req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("staking query error, %w", err)
|
||||
}
|
||||
|
||||
params := new(stakingtypes.QueryParamsResponse)
|
||||
if err := proto.Unmarshal(resp.Value, params); err != nil {
|
||||
return "", fmt.Errorf("unable to unmarshal delegator query delegations: %w", err)
|
||||
}
|
||||
|
||||
return params.Params.BondDenom, nil
|
||||
}
|
||||
|
||||
// MigrateAccount migrates vesting account to make the DelegatedVesting and DelegatedFree fields correctly
|
||||
// track delegations.
|
||||
// References: https://github.com/cosmos/cosmos-sdk/issues/8601, https://github.com/cosmos/cosmos-sdk/issues/8812
|
||||
func MigrateAccount(ctx sdk.Context, account types.AccountI, queryServer grpc.Server) (types.AccountI, error) {
|
||||
return migrateVestingAccounts(ctx, account, queryServer)
|
||||
}
|
||||
687
x/auth/legacy/v043/store_test.go
Normal file
687
x/auth/legacy/v043/store_test.go
Normal file
@ -0,0 +1,687 @@
|
||||
package v043_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/vesting/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
)
|
||||
|
||||
func TestMigrateVestingAccounts(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
prepareFunc func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress)
|
||||
garbageFunc func(ctx sdk.Context, vesting exported.VestingAccount, app *simapp.SimApp) error
|
||||
tokenAmount int64
|
||||
expVested int64
|
||||
expFree int64
|
||||
blockTime int64
|
||||
}{
|
||||
{
|
||||
"delayed vesting has vested, multiple delegations less than the total account balance",
|
||||
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
|
||||
|
||||
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(200)))
|
||||
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
|
||||
|
||||
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
|
||||
require.NoError(t, err)
|
||||
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
|
||||
require.NoError(t, err)
|
||||
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.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(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
|
||||
|
||||
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(200)))
|
||||
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
|
||||
|
||||
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.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(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
|
||||
|
||||
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(200)))
|
||||
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
|
||||
|
||||
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
|
||||
require.NoError(t, err)
|
||||
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
|
||||
require.NoError(t, err)
|
||||
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.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(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
|
||||
|
||||
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(200)))
|
||||
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.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(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
|
||||
|
||||
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(200)))
|
||||
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
|
||||
require.NoError(t, err)
|
||||
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
|
||||
require.NoError(t, err)
|
||||
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
|
||||
require.NoError(t, err)
|
||||
},
|
||||
cleartTrackingFields,
|
||||
300,
|
||||
200,
|
||||
100,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"not end time",
|
||||
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
|
||||
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
|
||||
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
|
||||
require.NoError(t, err)
|
||||
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(100), stakingtypes.Unbonded, validator, true)
|
||||
require.NoError(t, err)
|
||||
_, err = app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.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(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
|
||||
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
|
||||
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(1, 0, 0).Unix())
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.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(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
|
||||
|
||||
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
|
||||
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().Unix())
|
||||
|
||||
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(300), stakingtypes.Unbonded, validator, true)
|
||||
require.NoError(t, err)
|
||||
},
|
||||
cleartTrackingFields,
|
||||
300,
|
||||
0,
|
||||
300,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"continuous vesting, start time after blocktime",
|
||||
func(app *simapp.SimApp, 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 := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
|
||||
delayedAccount := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime)
|
||||
|
||||
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(300), stakingtypes.Unbonded, validator, true)
|
||||
require.NoError(t, err)
|
||||
},
|
||||
cleartTrackingFields,
|
||||
300,
|
||||
300,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"continuous vesting, start time passed but not ended",
|
||||
func(app *simapp.SimApp, 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 := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
|
||||
delayedAccount := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime)
|
||||
|
||||
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(300), stakingtypes.Unbonded, validator, true)
|
||||
require.NoError(t, err)
|
||||
},
|
||||
cleartTrackingFields,
|
||||
300,
|
||||
200,
|
||||
100,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"continuous vesting, start time and endtime passed",
|
||||
func(app *simapp.SimApp, 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 := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
|
||||
delayedAccount := types.NewContinuousVestingAccount(baseAccount, vestedCoins, startTime, endTime)
|
||||
|
||||
ctx = ctx.WithBlockTime(ctx.BlockTime().AddDate(1, 0, 0))
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.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(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
|
||||
|
||||
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(100)))
|
||||
|
||||
start := ctx.BlockTime().Unix() + int64(time.Hour/time.Second)
|
||||
|
||||
periods := []types.Period{
|
||||
{
|
||||
Length: int64((24 * time.Hour) / time.Second),
|
||||
Amount: vestedCoins,
|
||||
},
|
||||
}
|
||||
|
||||
account := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, start, periods)
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, account)
|
||||
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(150), stakingtypes.Unbonded, validator, true)
|
||||
require.NoError(t, err)
|
||||
},
|
||||
cleartTrackingFields,
|
||||
300,
|
||||
100,
|
||||
50,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"periodic vesting account, nothing has vested yet",
|
||||
func(app *simapp.SimApp, 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 := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(3666666670000)))
|
||||
periods := []types.Period{
|
||||
{
|
||||
Length: 31536000,
|
||||
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(1833333335000))),
|
||||
},
|
||||
{
|
||||
Length: 15638400,
|
||||
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
|
||||
},
|
||||
{
|
||||
Length: 15897600,
|
||||
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
|
||||
},
|
||||
}
|
||||
|
||||
delayedAccount := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
// delegation of the original vesting
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.NewInt(3666666670000), stakingtypes.Unbonded, validator, true)
|
||||
require.NoError(t, err)
|
||||
},
|
||||
cleartTrackingFields,
|
||||
3666666670000,
|
||||
3666666670000,
|
||||
0,
|
||||
1601042400 + 1,
|
||||
},
|
||||
{
|
||||
"periodic vesting account, all has vested",
|
||||
func(app *simapp.SimApp, 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 := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(3666666670000)))
|
||||
periods := []types.Period{
|
||||
{
|
||||
Length: 31536000,
|
||||
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(1833333335000))),
|
||||
},
|
||||
{
|
||||
Length: 15638400,
|
||||
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
|
||||
},
|
||||
{
|
||||
Length: 15897600,
|
||||
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
|
||||
},
|
||||
}
|
||||
|
||||
delayedAccount := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
|
||||
|
||||
ctx = ctx.WithBlockTime(time.Unix(1601042400+31536000+15897600+15897600+1, 0))
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
// delegation of the original vesting
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.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(app *simapp.SimApp, 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 := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(3666666670000)))
|
||||
periods := []types.Period{
|
||||
{
|
||||
Length: 31536000,
|
||||
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(1833333335000))),
|
||||
},
|
||||
{
|
||||
Length: 15638400,
|
||||
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
|
||||
},
|
||||
{
|
||||
Length: 15897600,
|
||||
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
|
||||
},
|
||||
}
|
||||
|
||||
delayedAccount := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
|
||||
|
||||
ctx = ctx.WithBlockTime(time.Unix(1601042400+31536000+1, 0))
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
// delegation of the original vesting
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.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(app *simapp.SimApp, 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 := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(3666666670000)))
|
||||
periods := []types.Period{
|
||||
{
|
||||
Length: 31536000,
|
||||
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(1833333335000))),
|
||||
},
|
||||
{
|
||||
Length: 15638400,
|
||||
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
|
||||
},
|
||||
{
|
||||
Length: 15897600,
|
||||
Amount: sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(916666667500))),
|
||||
},
|
||||
}
|
||||
|
||||
delayedAccount := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods)
|
||||
|
||||
ctx = ctx.WithBlockTime(time.Unix(1601042400+31536000+15638400+1, 0))
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
// delegation of the original vesting
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.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(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
|
||||
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
|
||||
|
||||
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix())
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
|
||||
// delegation of the original vesting
|
||||
_, err := app.StakingKeeper.Delegate(ctx, delegatorAddr, sdk.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 = app.StakingKeeper.Undelegate(ctx, delegatorAddr, valAddr, sdk.NewDecFromInt(sdk.NewInt(300)))
|
||||
require.NoError(t, err)
|
||||
},
|
||||
cleartTrackingFields,
|
||||
450,
|
||||
300,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"vesting account has never delegated anything",
|
||||
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
|
||||
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
|
||||
|
||||
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix())
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
},
|
||||
cleartTrackingFields,
|
||||
450,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"vesting account has no delegation but dirty DelegatedFree and DelegatedVesting fields",
|
||||
func(app *simapp.SimApp, ctx sdk.Context, validator stakingtypes.Validator, delegatorAddr sdk.AccAddress) {
|
||||
baseAccount := authtypes.NewBaseAccountWithAddress(delegatorAddr)
|
||||
vestedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(300)))
|
||||
|
||||
delayedAccount := types.NewDelayedVestingAccount(baseAccount, vestedCoins, ctx.BlockTime().AddDate(10, 0, 0).Unix())
|
||||
|
||||
app.AccountKeeper.SetAccount(ctx, delayedAccount)
|
||||
},
|
||||
dirtyTrackingFields,
|
||||
450,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
app := simapp.Setup(false)
|
||||
ctx := app.BaseApp.NewContext(false, tmproto.Header{
|
||||
Time: time.Now(),
|
||||
})
|
||||
|
||||
addrs := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(tc.tokenAmount))
|
||||
delegatorAddr := addrs[0]
|
||||
|
||||
_, valAddr := createValidator(t, ctx, app, tc.tokenAmount*2)
|
||||
validator, found := app.StakingKeeper.GetValidator(ctx, valAddr)
|
||||
require.True(t, found)
|
||||
|
||||
tc.prepareFunc(app, ctx, validator, delegatorAddr)
|
||||
|
||||
if tc.blockTime != 0 {
|
||||
ctx = ctx.WithBlockTime(time.Unix(tc.blockTime, 0))
|
||||
}
|
||||
|
||||
// We introduce the bug
|
||||
savedAccount := app.AccountKeeper.GetAccount(ctx, delegatorAddr)
|
||||
vestingAccount, ok := savedAccount.(exported.VestingAccount)
|
||||
require.True(t, ok)
|
||||
require.NoError(t, tc.garbageFunc(ctx, vestingAccount, app))
|
||||
|
||||
m := authkeeper.NewMigrator(app.AccountKeeper, app.GRPCQueryRouter())
|
||||
require.NoError(t, m.Migrate1to2(ctx))
|
||||
|
||||
var expVested sdk.Coins
|
||||
var expFree sdk.Coins
|
||||
|
||||
if tc.expVested != 0 {
|
||||
expVested = sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(tc.expVested)))
|
||||
}
|
||||
|
||||
if tc.expFree != 0 {
|
||||
expFree = sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), sdk.NewInt(tc.expFree)))
|
||||
}
|
||||
|
||||
trackingCorrected(
|
||||
ctx,
|
||||
t,
|
||||
app.AccountKeeper,
|
||||
savedAccount.GetAddress(),
|
||||
expVested,
|
||||
expFree,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func trackingCorrected(ctx sdk.Context, t *testing.T, ak authkeeper.AccountKeeper, addr sdk.AccAddress, expDelVesting sdk.Coins, expDelFree sdk.Coins) {
|
||||
t.Helper()
|
||||
baseAccount := ak.GetAccount(ctx, addr)
|
||||
vDA, ok := baseAccount.(exported.VestingAccount)
|
||||
require.True(t, ok)
|
||||
|
||||
vestedOk := expDelVesting.IsEqual(vDA.GetDelegatedVesting())
|
||||
freeOk := expDelFree.IsEqual(vDA.GetDelegatedFree())
|
||||
require.True(t, vestedOk, vDA.GetDelegatedVesting().String())
|
||||
require.True(t, freeOk, vDA.GetDelegatedFree().String())
|
||||
}
|
||||
|
||||
func cleartTrackingFields(ctx sdk.Context, vesting exported.VestingAccount, app *simapp.SimApp) error {
|
||||
switch t := vesting.(type) {
|
||||
case *types.DelayedVestingAccount:
|
||||
t.DelegatedFree = nil
|
||||
t.DelegatedVesting = nil
|
||||
app.AccountKeeper.SetAccount(ctx, t)
|
||||
case *types.ContinuousVestingAccount:
|
||||
t.DelegatedFree = nil
|
||||
t.DelegatedVesting = nil
|
||||
app.AccountKeeper.SetAccount(ctx, t)
|
||||
case *types.PeriodicVestingAccount:
|
||||
t.DelegatedFree = nil
|
||||
t.DelegatedVesting = nil
|
||||
app.AccountKeeper.SetAccount(ctx, t)
|
||||
default:
|
||||
return fmt.Errorf("expected vesting account, found %t", t)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func dirtyTrackingFields(ctx sdk.Context, vesting exported.VestingAccount, app *simapp.SimApp) error {
|
||||
dirt := sdk.NewCoins(sdk.NewInt64Coin("stake", 42))
|
||||
|
||||
switch t := vesting.(type) {
|
||||
case *types.DelayedVestingAccount:
|
||||
t.DelegatedFree = dirt
|
||||
t.DelegatedVesting = dirt
|
||||
app.AccountKeeper.SetAccount(ctx, t)
|
||||
case *types.ContinuousVestingAccount:
|
||||
t.DelegatedFree = dirt
|
||||
t.DelegatedVesting = dirt
|
||||
app.AccountKeeper.SetAccount(ctx, t)
|
||||
case *types.PeriodicVestingAccount:
|
||||
t.DelegatedFree = dirt
|
||||
t.DelegatedVesting = dirt
|
||||
app.AccountKeeper.SetAccount(ctx, t)
|
||||
default:
|
||||
return fmt.Errorf("expected vesting account, found %t", t)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createValidator(t *testing.T, ctx sdk.Context, app *simapp.SimApp, powers int64) (sdk.AccAddress, sdk.ValAddress) {
|
||||
valTokens := sdk.TokensFromConsensusPower(powers)
|
||||
addrs := simapp.AddTestAddrsIncremental(app, ctx, 1, valTokens)
|
||||
valAddrs := simapp.ConvertAddrsToValAddrs(addrs)
|
||||
pks := simapp.CreateTestPubKeys(1)
|
||||
cdc := simapp.MakeTestEncodingConfig().Marshaler
|
||||
|
||||
app.StakingKeeper = stakingkeeper.NewKeeper(
|
||||
cdc,
|
||||
app.GetKey(stakingtypes.StoreKey),
|
||||
app.AccountKeeper,
|
||||
app.BankKeeper,
|
||||
app.GetSubspace(stakingtypes.ModuleName),
|
||||
)
|
||||
|
||||
val1, err := stakingtypes.NewValidator(valAddrs[0], pks[0], stakingtypes.Description{})
|
||||
require.NoError(t, err)
|
||||
|
||||
app.StakingKeeper.SetValidator(ctx, val1)
|
||||
require.NoError(t, app.StakingKeeper.SetValidatorByConsAddr(ctx, val1))
|
||||
app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val1)
|
||||
|
||||
_, err = app.StakingKeeper.Delegate(ctx, addrs[0], valTokens, stakingtypes.Unbonded, val1, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
_ = staking.EndBlocker(ctx, app.StakingKeeper)
|
||||
|
||||
return addrs[0], valAddrs[0]
|
||||
}
|
||||
@ -129,6 +129,11 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd
|
||||
// module-specific GRPC queries.
|
||||
func (am AppModule) RegisterServices(cfg module.Configurator) {
|
||||
types.RegisterQueryServer(cfg.QueryServer(), am.accountKeeper)
|
||||
m := keeper.NewMigrator(am.accountKeeper, cfg.QueryServer())
|
||||
err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// InitGenesis performs genesis initialization for the auth module. It returns
|
||||
@ -148,7 +153,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json
|
||||
}
|
||||
|
||||
// ConsensusVersion implements AppModule/ConsensusVersion.
|
||||
func (AppModule) ConsensusVersion() uint64 { return 1 }
|
||||
func (AppModule) ConsensusVersion() uint64 { return 2 }
|
||||
|
||||
// BeginBlock returns the begin blocker for the auth module.
|
||||
func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}
|
||||
|
||||
@ -446,6 +446,7 @@ func (k BaseKeeper) trackDelegation(ctx sdk.Context, addr sdk.AccAddress, balanc
|
||||
if ok {
|
||||
// TODO: return error on account.TrackDelegation
|
||||
vacc.TrackDelegation(ctx.BlockHeader().Time, balance, amt)
|
||||
k.ak.SetAccount(ctx, acc)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -461,6 +462,7 @@ func (k BaseKeeper) trackUndelegation(ctx sdk.Context, addr sdk.AccAddress, amt
|
||||
if ok {
|
||||
// TODO: return error on account.TrackUndelegation
|
||||
vacc.TrackUndelegation(amt)
|
||||
k.ak.SetAccount(ctx, acc)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/vesting/exported"
|
||||
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
@ -904,6 +905,12 @@ func (suite *IntegrationTestSuite) TestDelegateCoins() {
|
||||
// require the ability for a vesting account to delegate
|
||||
suite.Require().NoError(app.BankKeeper.DelegateCoins(ctx, addr1, addrModule, delCoins))
|
||||
suite.Require().Equal(delCoins, app.BankKeeper.GetAllBalances(ctx, addr1))
|
||||
|
||||
// require that delegated vesting amount is equal to what was delegated with DelegateCoins
|
||||
acc = app.AccountKeeper.GetAccount(ctx, addr1)
|
||||
vestingAcc, ok := acc.(exported.VestingAccount)
|
||||
suite.Require().True(ok)
|
||||
suite.Require().Equal(delCoins, vestingAcc.GetDelegatedVesting())
|
||||
}
|
||||
|
||||
func (suite *IntegrationTestSuite) TestDelegateCoins_Invalid() {
|
||||
@ -978,6 +985,12 @@ func (suite *IntegrationTestSuite) TestUndelegateCoins() {
|
||||
|
||||
suite.Require().Equal(origCoins, app.BankKeeper.GetAllBalances(ctx, addr1))
|
||||
suite.Require().True(app.BankKeeper.GetAllBalances(ctx, addrModule).Empty())
|
||||
|
||||
// require that delegated vesting amount is completely empty, since they were completely undelegated
|
||||
acc = app.AccountKeeper.GetAccount(ctx, addr1)
|
||||
vestingAcc, ok := acc.(exported.VestingAccount)
|
||||
suite.Require().True(ok)
|
||||
suite.Require().Empty(vestingAcc.GetDelegatedVesting())
|
||||
}
|
||||
|
||||
func (suite *IntegrationTestSuite) TestUndelegateCoins_Invalid() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user