mukan-sdk/x/staking/keeper/delegation_test.go
Mukan Erkin Törük 20afb5db80
Some checks failed
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
Build & Push SDK Proto Builder / build (push) Has been cancelled
initial: sovereign Mukan Network fork
2026-05-11 03:18:24 +03:00

1170 lines
47 KiB
Go

package keeper_test
import (
"time"
"go.uber.org/mock/gomock"
"cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/codec/address"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
"github.com/cosmos/cosmos-sdk/x/staking/testutil"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
func createValAddrs(count int) ([]sdk.AccAddress, []sdk.ValAddress) {
addrs := simtestutil.CreateIncrementalAccounts(count)
valAddrs := simtestutil.ConvertAddrsToValAddrs(addrs)
return addrs, valAddrs
}
// tests GetDelegation, GetDelegatorDelegations, SetDelegation, RemoveDelegation, GetDelegatorDelegations
func (s *KeeperTestSuite) TestDelegation() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
addrDels, valAddrs := createValAddrs(3)
s.accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec("cosmos")).AnyTimes()
// construct the validators
amts := []math.Int{math.NewInt(9), math.NewInt(8), math.NewInt(7)}
var validators [3]stakingtypes.Validator
for i, amt := range amts {
validators[i] = testutil.NewValidator(s.T(), valAddrs[i], PKs[i])
validators[i], _ = validators[i].AddTokensFromDel(amt)
validators[i] = stakingkeeper.TestingUpdateValidator(keeper, ctx, validators[i], true)
}
// first add a validators[0] to delegate too
bond1to1 := stakingtypes.NewDelegation(addrDels[0].String(), valAddrs[0].String(), math.LegacyNewDec(9))
// check the empty keeper first
_, err := keeper.GetDelegation(ctx, addrDels[0], valAddrs[0])
require.ErrorIs(err, stakingtypes.ErrNoDelegation)
// set and retrieve a record
require.NoError(keeper.SetDelegation(ctx, bond1to1))
resBond, err := keeper.GetDelegation(ctx, addrDels[0], valAddrs[0])
require.NoError(err)
require.Equal(bond1to1, resBond)
// modify a records, save, and retrieve
bond1to1.Shares = math.LegacyNewDec(99)
require.NoError(keeper.SetDelegation(ctx, bond1to1))
resBond, err = keeper.GetDelegation(ctx, addrDels[0], valAddrs[0])
require.NoError(err)
require.Equal(bond1to1, resBond)
// add some more records
bond1to2 := stakingtypes.NewDelegation(addrDels[0].String(), valAddrs[1].String(), math.LegacyNewDec(9))
bond1to3 := stakingtypes.NewDelegation(addrDels[0].String(), valAddrs[2].String(), math.LegacyNewDec(9))
bond2to1 := stakingtypes.NewDelegation(addrDels[1].String(), valAddrs[0].String(), math.LegacyNewDec(9))
bond2to2 := stakingtypes.NewDelegation(addrDels[1].String(), valAddrs[1].String(), math.LegacyNewDec(9))
bond2to3 := stakingtypes.NewDelegation(addrDels[1].String(), valAddrs[2].String(), math.LegacyNewDec(9))
require.NoError(keeper.SetDelegation(ctx, bond1to2))
require.NoError(keeper.SetDelegation(ctx, bond1to3))
require.NoError(keeper.SetDelegation(ctx, bond2to1))
require.NoError(keeper.SetDelegation(ctx, bond2to2))
require.NoError(keeper.SetDelegation(ctx, bond2to3))
// test all bond retrieve capabilities
resBonds, err := keeper.GetDelegatorDelegations(ctx, addrDels[0], 5)
require.NoError(err)
require.Equal(3, len(resBonds))
require.Equal(bond1to1, resBonds[0])
require.Equal(bond1to2, resBonds[1])
require.Equal(bond1to3, resBonds[2])
resBonds, err = keeper.GetAllDelegatorDelegations(ctx, addrDels[0])
require.NoError(err)
require.Equal(3, len(resBonds))
resBonds, err = keeper.GetDelegatorDelegations(ctx, addrDels[0], 2)
require.NoError(err)
require.Equal(2, len(resBonds))
resBonds, err = keeper.GetDelegatorDelegations(ctx, addrDels[1], 5)
require.NoError(err)
require.Equal(3, len(resBonds))
require.Equal(bond2to1, resBonds[0])
require.Equal(bond2to2, resBonds[1])
require.Equal(bond2to3, resBonds[2])
allBonds, err := keeper.GetAllDelegations(ctx)
require.NoError(err)
require.Equal(6, len(allBonds))
require.Equal(bond1to1, allBonds[0])
require.Equal(bond1to2, allBonds[1])
require.Equal(bond1to3, allBonds[2])
require.Equal(bond2to1, allBonds[3])
require.Equal(bond2to2, allBonds[4])
require.Equal(bond2to3, allBonds[5])
resVals, err := keeper.GetDelegatorValidators(ctx, addrDels[0], 3)
require.NoError(err)
require.Equal(3, len(resVals.Validators))
resVals, err = keeper.GetDelegatorValidators(ctx, addrDels[1], 4)
require.NoError(err)
require.Equal(3, len(resVals.Validators))
for i := range 3 {
resVal, err := keeper.GetDelegatorValidator(ctx, addrDels[0], valAddrs[i])
require.Nil(err)
require.Equal(valAddrs[i].String(), resVal.GetOperator())
resVal, err = keeper.GetDelegatorValidator(ctx, addrDels[1], valAddrs[i])
require.Nil(err)
require.Equal(valAddrs[i].String(), resVal.GetOperator())
resDels, err := keeper.GetValidatorDelegations(ctx, valAddrs[i])
require.NoError(err)
require.Len(resDels, 2)
}
// test total bonded for single delegator
expBonded := bond1to1.Shares.Add(bond2to1.Shares).Add(bond1to3.Shares)
resDelBond, err := keeper.GetDelegatorBonded(ctx, addrDels[0])
require.NoError(err)
require.Equal(expBonded, math.LegacyNewDecFromInt(resDelBond))
// delete a record
require.NoError(keeper.RemoveDelegation(ctx, bond2to3))
_, err = keeper.GetDelegation(ctx, addrDels[1], valAddrs[2])
require.ErrorIs(err, stakingtypes.ErrNoDelegation)
resBonds, err = keeper.GetDelegatorDelegations(ctx, addrDels[1], 5)
require.NoError(err)
require.Equal(2, len(resBonds))
require.Equal(bond2to1, resBonds[0])
require.Equal(bond2to2, resBonds[1])
resBonds, err = keeper.GetAllDelegatorDelegations(ctx, addrDels[1])
require.NoError(err)
require.Equal(2, len(resBonds))
// delete all the records from delegator 2
require.NoError(keeper.RemoveDelegation(ctx, bond2to1))
require.NoError(keeper.RemoveDelegation(ctx, bond2to2))
_, err = keeper.GetDelegation(ctx, addrDels[1], valAddrs[0])
require.ErrorIs(err, stakingtypes.ErrNoDelegation)
_, err = keeper.GetDelegation(ctx, addrDels[1], valAddrs[1])
require.ErrorIs(err, stakingtypes.ErrNoDelegation)
resBonds, err = keeper.GetDelegatorDelegations(ctx, addrDels[1], 5)
require.NoError(err)
require.Equal(0, len(resBonds))
}
func (s *KeeperTestSuite) TestDelegationsByValIndex() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
addrDels, valAddrs := createValAddrs(3)
for _, addr := range addrDels {
s.bankKeeper.EXPECT().DelegateCoinsFromAccountToModule(gomock.Any(), addr, gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
}
s.accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec("cosmos")).AnyTimes()
// construct the validators
amts := []math.Int{math.NewInt(9), math.NewInt(8), math.NewInt(7)}
var validators [3]stakingtypes.Validator
for i, amt := range amts {
validators[i] = testutil.NewValidator(s.T(), valAddrs[i], PKs[i])
validators[i], _ = validators[i].AddTokensFromDel(amt)
validators[i] = stakingkeeper.TestingUpdateValidator(keeper, ctx, validators[i], true)
}
// delegate 2 tokens
//
// total delegations after delegating: del1 -> 2stake
_, err := s.msgServer.Delegate(ctx, stakingtypes.NewMsgDelegate(addrDels[0].String(), valAddrs[0].String(), sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(2))))
require.NoError(err)
dels, err := s.stakingKeeper.GetValidatorDelegations(ctx, valAddrs[0])
require.NoError(err)
require.Len(dels, 1)
// delegate 4 tokens
//
// total delegations after delegating: del1 -> 2stake, del2 -> 4stake
_, err = s.msgServer.Delegate(ctx, stakingtypes.NewMsgDelegate(addrDels[1].String(), valAddrs[0].String(), sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(4))))
require.NoError(err)
dels, err = s.stakingKeeper.GetValidatorDelegations(ctx, valAddrs[0])
require.NoError(err)
require.Len(dels, 2)
// undelegate 1 token from del1
//
// total delegations after undelegating: del1 -> 1stake, del2 -> 4stake
_, err = s.msgServer.Undelegate(ctx, stakingtypes.NewMsgUndelegate(addrDels[0].String(), valAddrs[0].String(), sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1))))
require.NoError(err)
dels, err = s.stakingKeeper.GetValidatorDelegations(ctx, valAddrs[0])
require.NoError(err)
require.Len(dels, 2)
// undelegate 1 token from del1
//
// total delegations after undelegating: del2 -> 4stake
_, err = s.msgServer.Undelegate(ctx, stakingtypes.NewMsgUndelegate(addrDels[0].String(), valAddrs[0].String(), sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1))))
require.NoError(err)
dels, err = s.stakingKeeper.GetValidatorDelegations(ctx, valAddrs[0])
require.NoError(err)
require.Len(dels, 1)
// undelegate 2 tokens from del2
//
// total delegations after undelegating: del2 -> 2stake
_, err = s.msgServer.Undelegate(ctx, stakingtypes.NewMsgUndelegate(addrDels[1].String(), valAddrs[0].String(), sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(2))))
require.NoError(err)
dels, err = s.stakingKeeper.GetValidatorDelegations(ctx, valAddrs[0])
require.NoError(err)
require.Len(dels, 1)
// undelegate 2 tokens from del2
//
// total delegations after undelegating: []
_, err = s.msgServer.Undelegate(ctx, stakingtypes.NewMsgUndelegate(addrDels[1].String(), valAddrs[0].String(), sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(2))))
require.NoError(err)
dels, err = s.stakingKeeper.GetValidatorDelegations(ctx, valAddrs[0])
require.NoError(err)
require.Len(dels, 0)
}
// tests Get/Set/Remove UnbondingDelegation
func (s *KeeperTestSuite) TestUnbondingDelegation() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
delAddrs, valAddrs := createValAddrs(2)
s.accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec("cosmos")).AnyTimes()
ubd := stakingtypes.NewUnbondingDelegation(
delAddrs[0],
valAddrs[0],
0,
time.Unix(0, 0).UTC(),
math.NewInt(5),
0,
address.NewBech32Codec("cosmosvaloper"), address.NewBech32Codec("cosmos"),
)
// set and retrieve a record
require.NoError(keeper.SetUnbondingDelegation(ctx, ubd))
resUnbond, err := keeper.GetUnbondingDelegation(ctx, delAddrs[0], valAddrs[0])
require.NoError(err)
require.Equal(ubd, resUnbond)
// modify a records, save, and retrieve
expUnbond := math.NewInt(21)
ubd.Entries[0].Balance = expUnbond
require.NoError(keeper.SetUnbondingDelegation(ctx, ubd))
resUnbonds, err := keeper.GetUnbondingDelegations(ctx, delAddrs[0], 5)
require.NoError(err)
require.Equal(1, len(resUnbonds))
resUnbonds, err = keeper.GetAllUnbondingDelegations(ctx, delAddrs[0])
require.NoError(err)
require.Equal(1, len(resUnbonds))
resUnbond, err = keeper.GetUnbondingDelegation(ctx, delAddrs[0], valAddrs[0])
require.NoError(err)
require.Equal(ubd, resUnbond)
resDelUnbond, err := keeper.GetDelegatorUnbonding(ctx, delAddrs[0])
require.NoError(err)
require.Equal(expUnbond, resDelUnbond)
// delete a record
require.NoError(keeper.RemoveUnbondingDelegation(ctx, ubd))
_, err = keeper.GetUnbondingDelegation(ctx, delAddrs[0], valAddrs[0])
require.ErrorIs(err, stakingtypes.ErrNoUnbondingDelegation)
resUnbonds, err = keeper.GetUnbondingDelegations(ctx, delAddrs[0], 5)
require.NoError(err)
require.Equal(0, len(resUnbonds))
resUnbonds, err = keeper.GetAllUnbondingDelegations(ctx, delAddrs[0])
require.NoError(err)
require.Equal(0, len(resUnbonds))
}
func (s *KeeperTestSuite) TestUnbondingDelegationsFromValidator() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
delAddrs, valAddrs := createValAddrs(2)
ubd := stakingtypes.NewUnbondingDelegation(
delAddrs[0],
valAddrs[0],
0,
time.Unix(0, 0).UTC(),
math.NewInt(5),
0,
address.NewBech32Codec("cosmosvaloper"), address.NewBech32Codec("cosmos"),
)
// set and retrieve a record
require.NoError(keeper.SetUnbondingDelegation(ctx, ubd))
resUnbond, err := keeper.GetUnbondingDelegation(ctx, delAddrs[0], valAddrs[0])
require.NoError(err)
require.Equal(ubd, resUnbond)
// modify a records, save, and retrieve
expUnbond := math.NewInt(21)
ubd.Entries[0].Balance = expUnbond
require.NoError(keeper.SetUnbondingDelegation(ctx, ubd))
resUnbonds, err := keeper.GetUnbondingDelegations(ctx, delAddrs[0], 5)
require.NoError(err)
require.Equal(1, len(resUnbonds))
resUnbonds, err = keeper.GetAllUnbondingDelegations(ctx, delAddrs[0])
require.NoError(err)
require.Equal(1, len(resUnbonds))
resUnbonds, err = keeper.GetUnbondingDelegationsFromValidator(ctx, valAddrs[0])
require.NoError(err)
require.Equal(1, len(resUnbonds))
resUnbond, err = keeper.GetUnbondingDelegation(ctx, delAddrs[0], valAddrs[0])
require.NoError(err)
require.Equal(ubd, resUnbond)
resDelUnbond, err := keeper.GetDelegatorUnbonding(ctx, delAddrs[0])
require.NoError(err)
require.Equal(expUnbond, resDelUnbond)
// delete a record
require.NoError(keeper.RemoveUnbondingDelegation(ctx, ubd))
_, err = keeper.GetUnbondingDelegation(ctx, delAddrs[0], valAddrs[0])
require.ErrorIs(err, stakingtypes.ErrNoUnbondingDelegation)
resUnbonds, err = keeper.GetUnbondingDelegations(ctx, delAddrs[0], 5)
require.NoError(err)
require.Equal(0, len(resUnbonds))
resUnbonds, err = keeper.GetAllUnbondingDelegations(ctx, delAddrs[0])
require.NoError(err)
require.Equal(0, len(resUnbonds))
resUnbonds, err = keeper.GetUnbondingDelegationsFromValidator(ctx, valAddrs[0])
require.NoError(err)
require.Equal(0, len(resUnbonds))
}
func (s *KeeperTestSuite) TestUnbondDelegation() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
delAddrs, valAddrs := createValAddrs(1)
startTokens := keeper.TokensFromConsensusPower(ctx, 10)
validator := testutil.NewValidator(s.T(), valAddrs[0], PKs[0])
validator, issuedShares := validator.AddTokensFromDel(startTokens)
require.Equal(startTokens, issuedShares.RoundInt())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
_ = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
delegation := stakingtypes.NewDelegation(delAddrs[0].String(), valAddrs[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, delegation))
bondTokens := keeper.TokensFromConsensusPower(ctx, 6)
amount, err := keeper.Unbond(ctx, delAddrs[0], valAddrs[0], math.LegacyNewDecFromInt(bondTokens))
require.NoError(err)
require.Equal(bondTokens, amount) // shares to be added to an unbonding delegation
delegation, err = keeper.GetDelegation(ctx, delAddrs[0], valAddrs[0])
require.NoError(err)
validator, err = keeper.GetValidator(ctx, valAddrs[0])
require.NoError(err)
remainingTokens := startTokens.Sub(bondTokens)
require.Equal(remainingTokens, delegation.Shares.RoundInt())
require.Equal(remainingTokens, validator.BondedTokens())
}
// // test undelegating self delegation from a validator pushing it below MinSelfDelegation
// // shift it from the bonded to unbonding state and jailed
func (s *KeeperTestSuite) TestUndelegateSelfDelegationBelowMinSelfDelegation() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
addrDels, addrVals := createValAddrs(1)
delTokens := keeper.TokensFromConsensusPower(ctx, 10)
// create a validator with a self-delegation
validator := testutil.NewValidator(s.T(), addrVals[0], PKs[0])
validator.MinSelfDelegation = delTokens
validator, issuedShares := validator.AddTokensFromDel(delTokens)
require.Equal(delTokens, issuedShares.RoundInt())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validator = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
require.NoError(keeper.SetValidatorByConsAddr(ctx, validator))
require.True(validator.IsBonded())
selfDelegation := stakingtypes.NewDelegation(sdk.AccAddress(addrVals[0].Bytes()).String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, selfDelegation))
// create a second delegation to this validator
require.NoError(keeper.DeleteValidatorByPowerIndex(ctx, validator))
validator, issuedShares = validator.AddTokensFromDel(delTokens)
require.True(validator.IsBonded())
require.Equal(delTokens, issuedShares.RoundInt())
validator = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
delegation := stakingtypes.NewDelegation(addrDels[0].String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, delegation))
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, gomock.Any())
_, _, err := keeper.Undelegate(ctx, val0AccAddr, addrVals[0], math.LegacyNewDecFromInt(keeper.TokensFromConsensusPower(ctx, 6)))
require.NoError(err)
// end block
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, gomock.Any())
s.applyValidatorSetUpdates(ctx, keeper, 1)
validator, err = keeper.GetValidator(ctx, addrVals[0])
require.NoError(err)
require.Equal(keeper.TokensFromConsensusPower(ctx, 14), validator.Tokens)
require.Equal(stakingtypes.Unbonding, validator.Status)
require.True(validator.Jailed)
}
func (s *KeeperTestSuite) TestUndelegateFromUnbondingValidator() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
delTokens := keeper.TokensFromConsensusPower(ctx, 10)
addrDels, addrVals := createValAddrs(2)
// create a validator with a self-delegation
validator := testutil.NewValidator(s.T(), addrVals[0], PKs[0])
require.NoError(keeper.SetValidatorByConsAddr(ctx, validator))
validator, issuedShares := validator.AddTokensFromDel(delTokens)
require.Equal(delTokens, issuedShares.RoundInt())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validator = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
require.True(validator.IsBonded())
selfDelegation := stakingtypes.NewDelegation(addrDels[0].String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, selfDelegation))
// create a second delegation to this validator
require.NoError(keeper.DeleteValidatorByPowerIndex(ctx, validator))
validator, issuedShares = validator.AddTokensFromDel(delTokens)
require.Equal(delTokens, issuedShares.RoundInt())
stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
delegation := stakingtypes.NewDelegation(addrDels[1].String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, delegation))
header := ctx.BlockHeader()
blockHeight := int64(10)
header.Height = blockHeight
blockTime := time.Unix(333, 0)
header.Time = blockTime
ctx = ctx.WithBlockHeader(header)
// unbond the all self-delegation to put validator in unbonding state
val0AccAddr := sdk.AccAddress(addrVals[0])
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, gomock.Any())
_, amount, err := keeper.Undelegate(ctx, val0AccAddr, addrVals[0], math.LegacyNewDecFromInt(delTokens))
require.NoError(err)
require.Equal(amount, delTokens)
// end block
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, gomock.Any())
s.applyValidatorSetUpdates(ctx, keeper, 1)
validator, err = keeper.GetValidator(ctx, addrVals[0])
require.NoError(err)
require.Equal(blockHeight, validator.UnbondingHeight)
params, err := keeper.GetParams(ctx)
require.NoError(err)
require.True(blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime))
blockHeight2 := int64(20)
blockTime2 := time.Unix(444, 0).UTC()
ctx = ctx.WithBlockHeight(blockHeight2)
ctx = ctx.WithBlockTime(blockTime2)
// unbond some of the other delegation's shares
undelegateAmount := math.LegacyNewDec(6)
_, undelegatedAmount, err := keeper.Undelegate(ctx, addrDels[1], addrVals[0], undelegateAmount)
require.NoError(err)
require.Equal(math.LegacyNewDecFromInt(undelegatedAmount), undelegateAmount)
// retrieve the unbonding delegation
ubd, err := keeper.GetUnbondingDelegation(ctx, addrDels[1], addrVals[0])
require.NoError(err)
require.Len(ubd.Entries, 1)
require.True(ubd.Entries[0].Balance.Equal(math.NewInt(6)))
require.Equal(blockHeight2, ubd.Entries[0].CreationHeight)
require.True(blockTime2.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime))
}
func (s *KeeperTestSuite) TestUndelegateFromUnbondedValidator() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
delTokens := keeper.TokensFromConsensusPower(ctx, 10)
addrDels, addrVals := createValAddrs(2)
// create a validator with a self-delegation
validator := testutil.NewValidator(s.T(), addrVals[0], PKs[0])
require.NoError(keeper.SetValidatorByConsAddr(ctx, validator))
valTokens := keeper.TokensFromConsensusPower(ctx, 10)
validator, issuedShares := validator.AddTokensFromDel(valTokens)
require.Equal(valTokens, issuedShares.RoundInt())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validator = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
require.True(validator.IsBonded())
val0AccAddr := sdk.AccAddress(addrVals[0])
selfDelegation := stakingtypes.NewDelegation(val0AccAddr.String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, selfDelegation))
// create a second delegation to this validator
require.NoError(keeper.DeleteValidatorByPowerIndex(ctx, validator))
validator, issuedShares = validator.AddTokensFromDel(delTokens)
require.Equal(delTokens, issuedShares.RoundInt())
validator = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
require.True(validator.IsBonded())
delegation := stakingtypes.NewDelegation(addrDels[1].String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, delegation))
ctx = ctx.WithBlockHeight(10)
ctx = ctx.WithBlockTime(time.Unix(333, 0))
// unbond the all self-delegation to put validator in unbonding state
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, gomock.Any())
_, amount, err := keeper.Undelegate(ctx, val0AccAddr, addrVals[0], math.LegacyNewDecFromInt(valTokens))
require.NoError(err)
require.Equal(amount, valTokens)
// end block
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, gomock.Any())
s.applyValidatorSetUpdates(ctx, keeper, 1)
validator, err = keeper.GetValidator(ctx, addrVals[0])
require.NoError(err)
require.Equal(ctx.BlockHeight(), validator.UnbondingHeight)
params, err := keeper.GetParams(ctx)
require.NoError(err)
require.True(ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime))
// unbond the validator
ctx = ctx.WithBlockTime(validator.UnbondingTime)
err = keeper.UnbondAllMatureValidators(ctx)
require.NoError(err)
// Make sure validator is still in state because there is still an outstanding delegation
validator, err = keeper.GetValidator(ctx, addrVals[0])
require.NoError(err)
require.Equal(validator.Status, stakingtypes.Unbonded)
// unbond some of the other delegation's shares
unbondTokens := keeper.TokensFromConsensusPower(ctx, 6)
_, amount2, err := keeper.Undelegate(ctx, addrDels[1], addrVals[0], math.LegacyNewDecFromInt(unbondTokens))
require.NoError(err)
require.Equal(amount2, unbondTokens)
// unbond rest of the other delegation's shares
remainingTokens := delTokens.Sub(unbondTokens)
_, amount3, err := keeper.Undelegate(ctx, addrDels[1], addrVals[0], math.LegacyNewDecFromInt(remainingTokens))
require.NoError(err)
require.Equal(amount3, remainingTokens)
// now validator should be deleted from state
validator, err = keeper.GetValidator(ctx, addrVals[0])
require.ErrorIs(err, stakingtypes.ErrNoValidatorFound)
}
func (s *KeeperTestSuite) TestUnbondingAllDelegationFromValidator() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
delTokens := keeper.TokensFromConsensusPower(ctx, 10)
addrDels, addrVals := createValAddrs(2)
// create a validator with a self-delegation
validator := testutil.NewValidator(s.T(), addrVals[0], PKs[0])
require.NoError(keeper.SetValidatorByConsAddr(ctx, validator))
valTokens := keeper.TokensFromConsensusPower(ctx, 10)
validator, issuedShares := validator.AddTokensFromDel(valTokens)
require.Equal(valTokens, issuedShares.RoundInt())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validator = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
require.True(validator.IsBonded())
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
selfDelegation := stakingtypes.NewDelegation(val0AccAddr.String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, selfDelegation))
// create a second delegation to this validator
require.NoError(keeper.DeleteValidatorByPowerIndex(ctx, validator))
validator, issuedShares = validator.AddTokensFromDel(delTokens)
require.Equal(delTokens, issuedShares.RoundInt())
validator = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
require.True(validator.IsBonded())
delegation := stakingtypes.NewDelegation(addrDels[1].String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, delegation))
ctx = ctx.WithBlockHeight(10)
ctx = ctx.WithBlockTime(time.Unix(333, 0))
// unbond the all self-delegation to put validator in unbonding state
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, gomock.Any())
_, amount, err := keeper.Undelegate(ctx, val0AccAddr, addrVals[0], math.LegacyNewDecFromInt(valTokens))
require.NoError(err)
require.Equal(amount, valTokens)
// end block
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, gomock.Any())
s.applyValidatorSetUpdates(ctx, keeper, 1)
// unbond all the remaining delegation
_, amount2, err := keeper.Undelegate(ctx, addrDels[1], addrVals[0], math.LegacyNewDecFromInt(delTokens))
require.NoError(err)
require.Equal(amount2, delTokens)
// validator should still be in state and still be in unbonding state
validator, err = keeper.GetValidator(ctx, addrVals[0])
require.NoError(err)
require.Equal(validator.Status, stakingtypes.Unbonding)
// unbond the validator
ctx = ctx.WithBlockTime(validator.UnbondingTime)
err = keeper.UnbondAllMatureValidators(ctx)
require.NoError(err)
// validator should now be deleted from state
_, err = keeper.GetValidator(ctx, addrVals[0])
require.ErrorIs(err, stakingtypes.ErrNoValidatorFound)
}
// Make sure that that the retrieving the delegations doesn't affect the state
func (s *KeeperTestSuite) TestGetRedelegationsFromSrcValidator() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
addrDels, addrVals := createValAddrs(2)
rd := stakingtypes.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0,
time.Unix(0, 0), math.NewInt(5),
math.LegacyNewDec(5), 0, address.NewBech32Codec("cosmosvaloper"), address.NewBech32Codec("cosmos"))
// set and retrieve a record
err := keeper.SetRedelegation(ctx, rd)
require.NoError(err)
resBond, err := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
require.NoError(err)
// get the redelegations one time
redelegations, err := keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0])
require.NoError(err)
require.Equal(1, len(redelegations))
require.Equal(redelegations[0], resBond)
// get the redelegations a second time, should be exactly the same
redelegations, err = keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0])
require.NoError(err)
require.Equal(1, len(redelegations))
require.Equal(redelegations[0], resBond)
}
// tests Get/Set/Remove/Has UnbondingDelegation
func (s *KeeperTestSuite) TestRedelegation() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
addrDels, addrVals := createValAddrs(2)
rd := stakingtypes.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0,
time.Unix(0, 0).UTC(), math.NewInt(5),
math.LegacyNewDec(5), 0, address.NewBech32Codec("cosmosvaloper"), address.NewBech32Codec("cosmos"))
// test shouldn't have and redelegations
has, err := keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1])
require.NoError(err)
require.False(has)
// set and retrieve a record
err = keeper.SetRedelegation(ctx, rd)
require.NoError(err)
resRed, err := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
require.NoError(err)
redelegations, err := keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0])
require.NoError(err)
require.Equal(1, len(redelegations))
require.Equal(redelegations[0], resRed)
redelegations, err = keeper.GetRedelegations(ctx, addrDels[0], 5)
require.NoError(err)
require.Equal(1, len(redelegations))
require.Equal(redelegations[0], resRed)
redelegations, err = keeper.GetAllRedelegations(ctx, addrDels[0], nil, nil)
require.NoError(err)
require.Equal(1, len(redelegations))
require.Equal(redelegations[0], resRed)
// check if has the redelegation
has, err = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1])
require.NoError(err)
require.True(has)
// modify a records, save, and retrieve
rd.Entries[0].SharesDst = math.LegacyNewDec(21)
err = keeper.SetRedelegation(ctx, rd)
require.NoError(err)
resRed, err = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
require.NoError(err)
require.Equal(rd, resRed)
redelegations, err = keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0])
require.NoError(err)
require.Equal(1, len(redelegations))
require.Equal(redelegations[0], resRed)
redelegations, err = keeper.GetRedelegations(ctx, addrDels[0], 5)
require.NoError(err)
require.Equal(1, len(redelegations))
require.Equal(redelegations[0], resRed)
// delete a record
err = keeper.RemoveRedelegation(ctx, rd)
require.NoError(err)
_, err = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
require.ErrorIs(err, stakingtypes.ErrNoRedelegation)
redelegations, err = keeper.GetRedelegations(ctx, addrDels[0], 5)
require.NoError(err)
require.Equal(0, len(redelegations))
redelegations, err = keeper.GetAllRedelegations(ctx, addrDels[0], nil, nil)
require.NoError(err)
require.Equal(0, len(redelegations))
}
func (s *KeeperTestSuite) TestRedelegateToSameValidator() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
_, addrVals := createValAddrs(1)
valTokens := keeper.TokensFromConsensusPower(ctx, 10)
// create a validator with a self-delegation
validator := testutil.NewValidator(s.T(), addrVals[0], PKs[0])
validator, issuedShares := validator.AddTokensFromDel(valTokens)
require.Equal(valTokens, issuedShares.RoundInt())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validator = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
require.True(validator.IsBonded())
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
selfDelegation := stakingtypes.NewDelegation(val0AccAddr.String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, selfDelegation))
_, err := keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[0], math.LegacyNewDec(5))
require.Error(err)
}
func (s *KeeperTestSuite) TestRedelegationMaxEntries() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
_, addrVals := createValAddrs(2)
// create a validator with a self-delegation
validator := testutil.NewValidator(s.T(), addrVals[0], PKs[0])
valTokens := keeper.TokensFromConsensusPower(ctx, 10)
validator, issuedShares := validator.AddTokensFromDel(valTokens)
require.Equal(valTokens, issuedShares.RoundInt())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
_ = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
selfDelegation := stakingtypes.NewDelegation(val0AccAddr.String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, selfDelegation))
// create a second validator
validator2 := testutil.NewValidator(s.T(), addrVals[1], PKs[1])
validator2, issuedShares = validator2.AddTokensFromDel(valTokens)
require.Equal(valTokens, issuedShares.RoundInt())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validator2 = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator2, true)
require.Equal(stakingtypes.Bonded, validator2.Status)
maxEntries, err := keeper.MaxEntries(ctx)
require.NoError(err)
// redelegations should pass
var completionTime time.Time
for i := uint32(0); i < maxEntries; i++ {
var err error
completionTime, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], math.LegacyNewDec(1))
require.NoError(err)
}
// an additional redelegation should fail due to max entries
_, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], math.LegacyNewDec(1))
require.Error(err)
// mature redelegations
ctx = ctx.WithBlockTime(completionTime)
_, err = keeper.CompleteRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1])
require.NoError(err)
// redelegation should work again
_, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], math.LegacyNewDec(1))
require.NoError(err)
}
func (s *KeeperTestSuite) TestRedelegateSelfDelegation() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
addrDels, addrVals := createValAddrs(2)
// create a validator with a self-delegation
validator := testutil.NewValidator(s.T(), addrVals[0], PKs[0])
require.NoError(keeper.SetValidatorByConsAddr(ctx, validator))
valTokens := keeper.TokensFromConsensusPower(ctx, 10)
validator, issuedShares := validator.AddTokensFromDel(valTokens)
require.Equal(valTokens, issuedShares.RoundInt())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validator = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
val0AccAddr := sdk.AccAddress(addrVals[0])
selfDelegation := stakingtypes.NewDelegation(val0AccAddr.String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, selfDelegation))
// create a second validator
validator2 := testutil.NewValidator(s.T(), addrVals[1], PKs[1])
validator2, issuedShares = validator2.AddTokensFromDel(valTokens)
require.Equal(valTokens, issuedShares.RoundInt())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validator2 = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator2, true)
require.Equal(stakingtypes.Bonded, validator2.Status)
// create a second delegation to validator 1
delTokens := keeper.TokensFromConsensusPower(ctx, 10)
validator, issuedShares = validator.AddTokensFromDel(delTokens)
require.Equal(delTokens, issuedShares.RoundInt())
stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
delegation := stakingtypes.NewDelegation(addrDels[0].String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, delegation))
_, err := keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], math.LegacyNewDecFromInt(delTokens))
require.NoError(err)
// end block
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, gomock.Any())
s.applyValidatorSetUpdates(ctx, keeper, 2)
validator, err = keeper.GetValidator(ctx, addrVals[0])
require.NoError(err)
require.Equal(valTokens, validator.Tokens)
require.Equal(stakingtypes.Unbonding, validator.Status)
}
func (s *KeeperTestSuite) TestRedelegateFromUnbondingValidator() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
addrDels, addrVals := createValAddrs(2)
// create a validator with a self-delegation
validator := testutil.NewValidator(s.T(), addrVals[0], PKs[0])
require.NoError(keeper.SetValidatorByConsAddr(ctx, validator))
valTokens := keeper.TokensFromConsensusPower(ctx, 10)
validator, issuedShares := validator.AddTokensFromDel(valTokens)
require.Equal(valTokens, issuedShares.RoundInt())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validator = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
selfDelegation := stakingtypes.NewDelegation(val0AccAddr.String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, selfDelegation))
// create a second delegation to this validator
require.NoError(keeper.DeleteValidatorByPowerIndex(ctx, validator))
delTokens := keeper.TokensFromConsensusPower(ctx, 10)
validator, issuedShares = validator.AddTokensFromDel(delTokens)
require.Equal(delTokens, issuedShares.RoundInt())
stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
delegation := stakingtypes.NewDelegation(addrDels[1].String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, delegation))
// create a second validator
validator2 := testutil.NewValidator(s.T(), addrVals[1], PKs[1])
validator2, issuedShares = validator2.AddTokensFromDel(valTokens)
require.Equal(valTokens, issuedShares.RoundInt())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
_ = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator2, true)
header := ctx.BlockHeader()
blockHeight := int64(10)
header.Height = blockHeight
blockTime := time.Unix(333, 0)
header.Time = blockTime
ctx = ctx.WithBlockHeader(header)
// unbond the all self-delegation to put validator in unbonding state
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, gomock.Any())
_, amount, err := keeper.Undelegate(ctx, val0AccAddr, addrVals[0], math.LegacyNewDecFromInt(delTokens))
require.NoError(err)
require.Equal(amount, delTokens)
// end block
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, gomock.Any())
s.applyValidatorSetUpdates(ctx, keeper, 1)
validator, err = keeper.GetValidator(ctx, addrVals[0])
require.NoError(err)
require.Equal(blockHeight, validator.UnbondingHeight)
params, err := keeper.GetParams(ctx)
require.NoError(err)
require.True(blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime))
// change the context
header = ctx.BlockHeader()
blockHeight2 := int64(20)
header.Height = blockHeight2
blockTime2 := time.Unix(444, 0)
header.Time = blockTime2
ctx = ctx.WithBlockHeader(header)
// unbond some of the other delegation's shares
redelegateTokens := keeper.TokensFromConsensusPower(ctx, 6)
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
_, err = keeper.BeginRedelegation(ctx, addrDels[1], addrVals[0], addrVals[1], math.LegacyNewDecFromInt(redelegateTokens))
require.NoError(err)
// retrieve the unbonding delegation
ubd, err := keeper.GetRedelegation(ctx, addrDels[1], addrVals[0], addrVals[1])
require.NoError(err)
require.Len(ubd.Entries, 1)
require.Equal(blockHeight, ubd.Entries[0].CreationHeight)
require.True(blockTime.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime))
}
func (s *KeeperTestSuite) TestRedelegateFromUnbondedValidator() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
addrDels, addrVals := createValAddrs(2)
// create a validator with a self-delegation
validator := testutil.NewValidator(s.T(), addrVals[0], PKs[0])
require.NoError(keeper.SetValidatorByConsAddr(ctx, validator))
valTokens := keeper.TokensFromConsensusPower(ctx, 10)
validator, issuedShares := validator.AddTokensFromDel(valTokens)
require.Equal(valTokens, issuedShares.RoundInt())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validator = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
selfDelegation := stakingtypes.NewDelegation(val0AccAddr.String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, selfDelegation))
// create a second delegation to this validator
require.NoError(keeper.DeleteValidatorByPowerIndex(ctx, validator))
delTokens := keeper.TokensFromConsensusPower(ctx, 10)
validator, issuedShares = validator.AddTokensFromDel(delTokens)
require.Equal(delTokens, issuedShares.RoundInt())
stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
delegation := stakingtypes.NewDelegation(addrDels[1].String(), addrVals[0].String(), issuedShares)
require.NoError(keeper.SetDelegation(ctx, delegation))
// create a second validator
validator2 := testutil.NewValidator(s.T(), addrVals[1], PKs[1])
validator2, issuedShares = validator2.AddTokensFromDel(valTokens)
require.Equal(valTokens, issuedShares.RoundInt())
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validator2 = stakingkeeper.TestingUpdateValidator(keeper, ctx, validator2, true)
require.Equal(stakingtypes.Bonded, validator2.Status)
ctx = ctx.WithBlockHeight(10)
ctx = ctx.WithBlockTime(time.Unix(333, 0))
// unbond the all self-delegation to put validator in unbonding state
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, gomock.Any())
_, amount, err := keeper.Undelegate(ctx, val0AccAddr, addrVals[0], math.LegacyNewDecFromInt(delTokens))
require.NoError(err)
require.Equal(amount, delTokens)
// end block
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, gomock.Any())
s.applyValidatorSetUpdates(ctx, keeper, 1)
validator, err = keeper.GetValidator(ctx, addrVals[0])
require.NoError(err)
require.Equal(ctx.BlockHeight(), validator.UnbondingHeight)
params, err := keeper.GetParams(ctx)
require.NoError(err)
require.True(ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingTime))
// unbond the validator
_, err = keeper.UnbondingToUnbonded(ctx, validator)
require.NoError(err)
// redelegate some of the delegation's shares
redelegationTokens := keeper.TokensFromConsensusPower(ctx, 6)
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
_, err = keeper.BeginRedelegation(ctx, addrDels[1], addrVals[0], addrVals[1], math.LegacyNewDecFromInt(redelegationTokens))
require.NoError(err)
// no red should have been found
red, err := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
require.ErrorIs(err, stakingtypes.ErrNoRedelegation, "%v", red)
}
func (s *KeeperTestSuite) TestUnbondingDelegationAddEntry() {
require := s.Require()
delAddrs, valAddrs := createValAddrs(1)
delAddr := delAddrs[0]
valAddr := valAddrs[0]
creationHeight := int64(10)
ubd := stakingtypes.NewUnbondingDelegation(
delAddr,
valAddr,
creationHeight,
time.Unix(0, 0).UTC(),
math.NewInt(10),
0,
address.NewBech32Codec("cosmosvaloper"), address.NewBech32Codec("cosmos"),
)
var initialEntries []stakingtypes.UnbondingDelegationEntry
initialEntries = append(initialEntries, ubd.Entries...)
require.Len(initialEntries, 1)
isNew := ubd.AddEntry(creationHeight, time.Unix(0, 0).UTC(), math.NewInt(5), 1)
require.False(isNew)
require.Len(ubd.Entries, 1) // entry was merged
require.NotEqual(initialEntries, ubd.Entries)
require.Equal(creationHeight, ubd.Entries[0].CreationHeight)
require.Equal(initialEntries[0].UnbondingId, ubd.Entries[0].UnbondingId) // unbondingID remains unchanged
require.Equal(ubd.Entries[0].Balance, math.NewInt(15)) // 10 from previous + 5 from merged
newCreationHeight := int64(11)
isNew = ubd.AddEntry(newCreationHeight, time.Unix(1, 0).UTC(), math.NewInt(5), 2)
require.True(isNew)
require.Len(ubd.Entries, 2) // entry was appended
require.NotEqual(initialEntries, ubd.Entries)
require.Equal(creationHeight, ubd.Entries[0].CreationHeight)
require.Equal(newCreationHeight, ubd.Entries[1].CreationHeight)
require.Equal(ubd.Entries[0].Balance, math.NewInt(15))
require.Equal(ubd.Entries[1].Balance, math.NewInt(5))
require.NotEqual(ubd.Entries[0].UnbondingId, ubd.Entries[1].UnbondingId) // appended entry has a new unbondingID
}
func (s *KeeperTestSuite) TestSetUnbondingDelegationEntry() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
delAddrs, valAddrs := createValAddrs(1)
delAddr := delAddrs[0]
valAddr := valAddrs[0]
creationHeight := int64(0)
ubd := stakingtypes.NewUnbondingDelegation(
delAddr,
valAddr,
creationHeight,
time.Unix(0, 0).UTC(),
math.NewInt(5),
0,
address.NewBech32Codec("cosmosvaloper"), address.NewBech32Codec("cosmos"),
)
// set and retrieve a record
require.NoError(keeper.SetUnbondingDelegation(ctx, ubd))
resUnbond, err := keeper.GetUnbondingDelegation(ctx, delAddr, valAddr)
require.NoError(err)
require.Equal(ubd, resUnbond)
initialEntries := ubd.Entries
require.Len(initialEntries, 1)
require.Equal(initialEntries[0].Balance, math.NewInt(5))
require.Equal(initialEntries[0].UnbondingId, uint64(0)) // initial unbondingID
// set unbonding delegation entry for existing creationHeight
// entries are expected to be merged
_, err = keeper.SetUnbondingDelegationEntry(
ctx,
delAddr,
valAddr,
creationHeight,
time.Unix(0, 0).UTC(),
math.NewInt(5),
)
require.NoError(err)
resUnbonding, err := keeper.GetUnbondingDelegation(ctx, delAddr, valAddr)
require.NoError(err)
require.Len(resUnbonding.Entries, 1)
require.NotEqual(initialEntries, resUnbonding.Entries)
require.Equal(creationHeight, resUnbonding.Entries[0].CreationHeight)
require.Equal(initialEntries[0].UnbondingId, resUnbonding.Entries[0].UnbondingId) // initial unbondingID remains unchanged
require.Equal(resUnbonding.Entries[0].Balance, math.NewInt(10)) // 5 from previous entry + 5 from merged entry
// set unbonding delegation entry for newCreationHeight
// new entry is expected to be appended to the existing entries
newCreationHeight := int64(1)
_, err = keeper.SetUnbondingDelegationEntry(
ctx,
delAddr,
valAddr,
newCreationHeight,
time.Unix(1, 0).UTC(),
math.NewInt(10),
)
require.NoError(err)
resUnbonding, err = keeper.GetUnbondingDelegation(ctx, delAddr, valAddr)
require.NoError(err)
require.Len(resUnbonding.Entries, 2)
require.NotEqual(initialEntries, resUnbonding.Entries)
require.NotEqual(resUnbonding.Entries[0], resUnbonding.Entries[1])
require.Equal(creationHeight, resUnbonding.Entries[0].CreationHeight)
require.Equal(newCreationHeight, resUnbonding.Entries[1].CreationHeight)
// unbondingID is incremented on every call to SetUnbondingDelegationEntry
// unbondingID == 1 was skipped because the entry was merged with the existing entry with unbondingID == 0
// unbondingID comes from a global counter -> gaps in unbondingIDs are OK as long as every unbondingID is unique
require.Equal(uint64(2), resUnbonding.Entries[1].UnbondingId)
}