github.com/Finschia/finschia-sdk@v0.48.1/x/staking/handler_test.go (about)

     1  package staking_test
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  	"time"
     7  
     8  	octypes "github.com/Finschia/ostracon/types"
     9  	"github.com/golang/protobuf/proto"
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  	abci "github.com/tendermint/tendermint/abci/types"
    13  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    14  
    15  	cryptocodec "github.com/Finschia/finschia-sdk/crypto/codec"
    16  	"github.com/Finschia/finschia-sdk/crypto/keys/ed25519"
    17  	"github.com/Finschia/finschia-sdk/crypto/keys/secp256k1"
    18  	cryptotypes "github.com/Finschia/finschia-sdk/crypto/types"
    19  	"github.com/Finschia/finschia-sdk/simapp"
    20  	"github.com/Finschia/finschia-sdk/testutil/testdata"
    21  	sdk "github.com/Finschia/finschia-sdk/types"
    22  	"github.com/Finschia/finschia-sdk/x/staking"
    23  	"github.com/Finschia/finschia-sdk/x/staking/keeper"
    24  	"github.com/Finschia/finschia-sdk/x/staking/teststaking"
    25  	"github.com/Finschia/finschia-sdk/x/staking/types"
    26  )
    27  
    28  func bootstrapHandlerGenesisTest(t *testing.T, power int64, numAddrs int, accAmount sdk.Int) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) {
    29  	_, app, ctx := getBaseSimappWithCustomKeeper()
    30  
    31  	addrDels, addrVals := generateAddresses(app, ctx, numAddrs, accAmount)
    32  
    33  	amt := app.StakingKeeper.TokensFromConsensusPower(ctx, power)
    34  	totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels)))))
    35  
    36  	notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx)
    37  
    38  	// set non bonded pool balance
    39  	app.AccountKeeper.SetModuleAccount(ctx, notBondedPool)
    40  	require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), totalSupply))
    41  	return app, ctx, addrDels, addrVals
    42  }
    43  
    44  func TestValidatorByPowerIndex(t *testing.T) {
    45  	initPower := int64(1000000)
    46  	app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 10, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
    47  	validatorAddr, validatorAddr3 := valAddrs[0], valAddrs[1]
    48  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
    49  
    50  	// create validator
    51  	initBond := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], initPower, true)
    52  
    53  	// must end-block
    54  	updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
    55  	require.NoError(t, err)
    56  	require.Equal(t, 1, len(updates))
    57  
    58  	// verify the self-delegation exists
    59  	bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
    60  	require.True(t, found)
    61  	gotBond := bond.Shares.RoundInt()
    62  	require.Equal(t, initBond, gotBond)
    63  
    64  	// verify that the by power index exists
    65  	validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr)
    66  	require.True(t, found)
    67  	power := types.GetValidatorsByPowerIndexKey(validator, app.StakingKeeper.PowerReduction(ctx))
    68  	require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power))
    69  
    70  	// create a second validator keep it bonded
    71  	tstaking.CreateValidatorWithValPower(validatorAddr3, PKs[2], initPower, true)
    72  
    73  	// must end-block
    74  	updates, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
    75  	require.NoError(t, err)
    76  	require.Equal(t, 1, len(updates))
    77  
    78  	// slash and jail the first validator
    79  	consAddr0 := sdk.ConsAddress(PKs[0].Address())
    80  	app.StakingKeeper.Slash(ctx, consAddr0, 0, initPower, sdk.NewDecWithPrec(5, 1))
    81  	app.StakingKeeper.Jail(ctx, consAddr0)
    82  	app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
    83  
    84  	validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr)
    85  	require.True(t, found)
    86  	require.Equal(t, types.Unbonding, validator.Status)    // ensure is unbonding
    87  	require.Equal(t, initBond.QuoRaw(2), validator.Tokens) // ensure tokens slashed
    88  	app.StakingKeeper.Unjail(ctx, consAddr0)
    89  
    90  	// the old power record should have been deleted as the power changed
    91  	require.False(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power))
    92  
    93  	// but the new power record should have been created
    94  	validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr)
    95  	require.True(t, found)
    96  	power2 := types.GetValidatorsByPowerIndexKey(validator, app.StakingKeeper.PowerReduction(ctx))
    97  	require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power2))
    98  
    99  	// now the new record power index should be the same as the original record
   100  	power3 := types.GetValidatorsByPowerIndexKey(validator, app.StakingKeeper.PowerReduction(ctx))
   101  	require.Equal(t, power2, power3)
   102  
   103  	// unbond self-delegation
   104  	totalBond := validator.TokensFromShares(bond.GetShares()).TruncateInt()
   105  	res := tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, totalBond, true)
   106  
   107  	var resData types.MsgUndelegateResponse
   108  	err = proto.Unmarshal(res.Data, &resData)
   109  	require.NoError(t, err)
   110  
   111  	ctx = ctx.WithBlockTime(resData.CompletionTime)
   112  	staking.EndBlocker(ctx, app.StakingKeeper)
   113  	staking.EndBlocker(ctx, app.StakingKeeper)
   114  
   115  	// verify that by power key nolonger exists
   116  	_, found = app.StakingKeeper.GetValidator(ctx, validatorAddr)
   117  	require.False(t, found)
   118  	require.False(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power3))
   119  }
   120  
   121  func TestDuplicatesMsgCreateValidator(t *testing.T) {
   122  	initPower := int64(1000000)
   123  	app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 10, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   124  
   125  	addr1, addr2 := valAddrs[0], valAddrs[1]
   126  	pk1, pk2 := PKs[0], PKs[1]
   127  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   128  
   129  	valTokens := tstaking.CreateValidatorWithValPower(addr1, pk1, 10, true)
   130  	app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
   131  
   132  	validator := tstaking.CheckValidator(addr1, types.Bonded, false)
   133  	assert.Equal(t, addr1.String(), validator.OperatorAddress)
   134  	consKey, err := validator.OcConsPublicKey()
   135  	require.NoError(t, err)
   136  	tmPk1, err := cryptocodec.ToOcProtoPublicKey(pk1)
   137  	require.NoError(t, err)
   138  	assert.Equal(t, tmPk1, consKey)
   139  	assert.Equal(t, valTokens, validator.BondedTokens())
   140  	assert.Equal(t, valTokens.ToDec(), validator.DelegatorShares)
   141  	assert.Equal(t, types.Description{}, validator.Description)
   142  
   143  	// two validators can't have the same operator address
   144  	tstaking.CreateValidator(addr1, pk2, valTokens, false)
   145  
   146  	// two validators can't have the same pubkey
   147  	tstaking.CreateValidator(addr2, pk1, valTokens, false)
   148  
   149  	// must have different pubkey and operator
   150  	tstaking.CreateValidator(addr2, pk2, valTokens, true)
   151  
   152  	// must end-block
   153  	updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
   154  	require.NoError(t, err)
   155  	require.Equal(t, 1, len(updates))
   156  
   157  	validator = tstaking.CheckValidator(addr2, types.Bonded, false)
   158  	assert.Equal(t, addr2.String(), validator.OperatorAddress)
   159  	consPk, err := validator.OcConsPublicKey()
   160  	require.NoError(t, err)
   161  	tmPk2, err := cryptocodec.ToOcProtoPublicKey(pk2)
   162  	require.NoError(t, err)
   163  	assert.Equal(t, tmPk2, consPk)
   164  	assert.True(sdk.IntEq(t, valTokens, validator.Tokens))
   165  	assert.True(sdk.DecEq(t, valTokens.ToDec(), validator.DelegatorShares))
   166  	assert.Equal(t, types.Description{}, validator.Description)
   167  }
   168  
   169  func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) {
   170  	initPower := int64(1000)
   171  	app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   172  	ctx = ctx.WithConsensusParams(&abci.ConsensusParams{
   173  		Validator: &tmproto.ValidatorParams{PubKeyTypes: []string{octypes.ABCIPubKeyTypeEd25519}},
   174  	})
   175  
   176  	addr := valAddrs[0]
   177  	invalidPk := secp256k1.GenPrivKey().PubKey()
   178  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   179  
   180  	// invalid pukKey type should not be allowed
   181  	tstaking.CreateValidator(addr, invalidPk, sdk.NewInt(10), false)
   182  }
   183  
   184  func TestBothPubKeyTypesMsgCreateValidator(t *testing.T) {
   185  	app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 2, sdk.NewInt(1000))
   186  	ctx = ctx.WithConsensusParams(&abci.ConsensusParams{
   187  		Validator: &tmproto.ValidatorParams{PubKeyTypes: []string{octypes.ABCIPubKeyTypeEd25519, octypes.ABCIPubKeyTypeSecp256k1}},
   188  	})
   189  
   190  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   191  
   192  	testCases := []struct {
   193  		name string
   194  		addr sdk.ValAddress
   195  		pk   cryptotypes.PubKey
   196  	}{
   197  		{
   198  			"can create a validator with ed25519 pubkey",
   199  			valAddrs[0],
   200  			ed25519.GenPrivKey().PubKey(),
   201  		},
   202  		{
   203  			"can create a validator with secp256k1 pubkey",
   204  			valAddrs[1],
   205  			secp256k1.GenPrivKey().PubKey(),
   206  		},
   207  	}
   208  	for _, tc := range testCases {
   209  		t.Run(tc.name, func(*testing.T) {
   210  			tstaking.CreateValidator(tc.addr, tc.pk, sdk.NewInt(10), true)
   211  		})
   212  	}
   213  }
   214  
   215  func TestLegacyValidatorDelegations(t *testing.T) {
   216  	initPower := int64(1000)
   217  	app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   218  
   219  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   220  	valAddr := valAddrs[0]
   221  	valConsPubKey, valConsAddr := PKs[0], sdk.ConsAddress(PKs[0].Address())
   222  	delAddr := delAddrs[1]
   223  
   224  	// create validator
   225  	bondAmount := tstaking.CreateValidatorWithValPower(valAddr, valConsPubKey, 10, true)
   226  
   227  	// must end-block
   228  	updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
   229  	require.NoError(t, err)
   230  	require.Equal(t, 1, len(updates))
   231  
   232  	// verify the validator exists and has the correct attributes
   233  	validator := tstaking.CheckValidator(valAddr, types.Bonded, false)
   234  	require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt())
   235  	require.Equal(t, bondAmount, validator.BondedTokens())
   236  
   237  	// delegate tokens to the validator
   238  	tstaking.Delegate(delAddr, valAddr, bondAmount)
   239  
   240  	// verify validator bonded shares
   241  	validator = tstaking.CheckValidator(valAddr, types.Bonded, false)
   242  	require.Equal(t, bondAmount.MulRaw(2), validator.DelegatorShares.RoundInt())
   243  	require.Equal(t, bondAmount.MulRaw(2), validator.BondedTokens())
   244  
   245  	// unbond validator total self-delegations (which should jail the validator)
   246  	res := tstaking.Undelegate(sdk.AccAddress(valAddr), valAddr, bondAmount, true)
   247  
   248  	var resData types.MsgUndelegateResponse
   249  	err = proto.Unmarshal(res.Data, &resData)
   250  	require.NoError(t, err)
   251  
   252  	ctx = ctx.WithBlockTime(resData.CompletionTime)
   253  	tstaking.Ctx = ctx
   254  	staking.EndBlocker(ctx, app.StakingKeeper)
   255  
   256  	// verify the validator record still exists, is jailed, and has correct tokens
   257  	validator = tstaking.CheckValidator(valAddr, -1, true)
   258  	require.Equal(t, bondAmount, validator.Tokens)
   259  
   260  	// verify delegation still exists
   261  	bond, found := app.StakingKeeper.GetDelegation(ctx, delAddr, valAddr)
   262  	require.True(t, found)
   263  	require.Equal(t, bondAmount, bond.Shares.RoundInt())
   264  	require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt())
   265  
   266  	// verify the validator can still self-delegate
   267  	tstaking.Delegate(sdk.AccAddress(valAddr), valAddr, bondAmount)
   268  
   269  	// verify validator bonded shares
   270  	validator, found = app.StakingKeeper.GetValidator(ctx, valAddr)
   271  	require.True(t, found)
   272  	require.Equal(t, bondAmount.MulRaw(2), validator.DelegatorShares.RoundInt())
   273  	require.Equal(t, bondAmount.MulRaw(2), validator.Tokens)
   274  
   275  	// unjail the validator now that is has non-zero self-delegated shares
   276  	app.StakingKeeper.Unjail(ctx, valConsAddr)
   277  
   278  	// verify the validator can now accept delegations
   279  	tstaking.Delegate(delAddr, valAddr, bondAmount)
   280  
   281  	// verify validator bonded shares
   282  	validator, found = app.StakingKeeper.GetValidator(ctx, valAddr)
   283  	require.True(t, found)
   284  	require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt())
   285  	require.Equal(t, bondAmount.MulRaw(3), validator.Tokens)
   286  
   287  	// verify new delegation
   288  	bond, found = app.StakingKeeper.GetDelegation(ctx, delAddr, valAddr)
   289  	require.True(t, found)
   290  	require.Equal(t, bondAmount.MulRaw(2), bond.Shares.RoundInt())
   291  	require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt())
   292  }
   293  
   294  func TestIncrementsMsgDelegate(t *testing.T) {
   295  	initPower := int64(1000)
   296  	initBond := sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)
   297  	app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   298  
   299  	params := app.StakingKeeper.GetParams(ctx)
   300  	validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1]
   301  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   302  
   303  	// first create validator
   304  	bondAmount := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], 10, true)
   305  
   306  	// apply TM updates
   307  	app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
   308  
   309  	validator := tstaking.CheckValidator(validatorAddr, types.Bonded, false)
   310  	require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt())
   311  	require.Equal(t, bondAmount, validator.BondedTokens(), "validator: %v", validator)
   312  
   313  	tstaking.CheckDelegator(delegatorAddr, validatorAddr, false)
   314  
   315  	bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
   316  	require.True(t, found)
   317  	require.Equal(t, bondAmount, bond.Shares.RoundInt())
   318  
   319  	bondedTokens := app.StakingKeeper.TotalBondedTokens(ctx)
   320  	require.Equal(t, bondAmount, bondedTokens)
   321  
   322  	for i := int64(0); i < 5; i++ {
   323  		ctx = ctx.WithBlockHeight(i)
   324  		tstaking.Ctx = ctx
   325  		tstaking.Delegate(delegatorAddr, validatorAddr, bondAmount)
   326  
   327  		// Check that the accounts and the bond account have the appropriate values
   328  		validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr)
   329  		require.True(t, found)
   330  		bond, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr)
   331  		require.True(t, found)
   332  
   333  		expBond := bondAmount.MulRaw(i + 1)
   334  		expDelegatorShares := bondAmount.MulRaw(i + 2) // (1 self delegation)
   335  		expDelegatorAcc := initBond.Sub(expBond)
   336  
   337  		gotBond := bond.Shares.RoundInt()
   338  		gotDelegatorShares := validator.DelegatorShares.RoundInt()
   339  		gotDelegatorAcc := app.BankKeeper.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount
   340  
   341  		require.Equal(t, expBond, gotBond,
   342  			"i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n",
   343  			i, expBond, gotBond, validator, bond)
   344  		require.Equal(t, expDelegatorShares, gotDelegatorShares,
   345  			"i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n",
   346  			i, expDelegatorShares, gotDelegatorShares, validator, bond)
   347  		require.Equal(t, expDelegatorAcc, gotDelegatorAcc,
   348  			"i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n",
   349  			i, expDelegatorAcc, gotDelegatorAcc, validator, bond)
   350  	}
   351  }
   352  
   353  func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) {
   354  	initPower := int64(100)
   355  	initBond := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction)
   356  	app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   357  
   358  	validatorAddr := valAddrs[0]
   359  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   360  
   361  	// create validator
   362  	msgCreateValidator := tstaking.CreateValidatorMsg(validatorAddr, PKs[0], initBond)
   363  	msgCreateValidator.MinSelfDelegation = sdk.NewInt(2)
   364  	tstaking.Handle(msgCreateValidator, true)
   365  
   366  	// must end-block
   367  	updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
   368  	require.NoError(t, err)
   369  	require.Equal(t, 1, len(updates))
   370  
   371  	// verify the self-delegation exists
   372  	bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
   373  	require.True(t, found)
   374  	gotBond := bond.Shares.RoundInt()
   375  	require.Equal(t, initBond, gotBond,
   376  		"initBond: %v\ngotBond: %v\nbond: %v\n",
   377  		initBond, gotBond, bond)
   378  
   379  	newMinSelfDelegation := sdk.OneInt()
   380  	msgEditValidator := types.NewMsgEditValidator(validatorAddr, types.Description{}, nil, &newMinSelfDelegation)
   381  	tstaking.Handle(msgEditValidator, false)
   382  }
   383  
   384  func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) {
   385  	initPower := int64(100)
   386  	initBond := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction)
   387  
   388  	app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   389  	validatorAddr := valAddrs[0]
   390  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   391  
   392  	// create validator
   393  	msgCreateValidator := tstaking.CreateValidatorMsg(validatorAddr, PKs[0], initBond)
   394  	msgCreateValidator.MinSelfDelegation = sdk.NewInt(2)
   395  	tstaking.Handle(msgCreateValidator, true)
   396  
   397  	// must end-block
   398  	updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
   399  	require.NoError(t, err)
   400  	require.Equal(t, 1, len(updates))
   401  
   402  	// verify the self-delegation exists
   403  	bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
   404  	require.True(t, found)
   405  	gotBond := bond.Shares.RoundInt()
   406  	require.Equal(t, initBond, gotBond,
   407  		"initBond: %v\ngotBond: %v\nbond: %v\n",
   408  		initBond, gotBond, bond)
   409  
   410  	newMinSelfDelegation := initBond.Add(sdk.OneInt())
   411  	msgEditValidator := types.NewMsgEditValidator(validatorAddr, types.Description{}, nil, &newMinSelfDelegation)
   412  	tstaking.Handle(msgEditValidator, false)
   413  }
   414  
   415  func TestIncrementsMsgUnbond(t *testing.T) {
   416  	initPower := int64(1000)
   417  
   418  	app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   419  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   420  	params := app.StakingKeeper.GetParams(ctx)
   421  	denom := params.BondDenom
   422  
   423  	// create validator, delegate
   424  	validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1]
   425  	initBond := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], initPower, true)
   426  
   427  	// initial balance
   428  	amt1 := app.BankKeeper.GetBalance(ctx, delegatorAddr, denom).Amount
   429  
   430  	tstaking.Delegate(delegatorAddr, validatorAddr, initBond)
   431  
   432  	// balance should have been subtracted after delegation
   433  	amt2 := app.BankKeeper.GetBalance(ctx, delegatorAddr, denom).Amount
   434  	require.True(sdk.IntEq(t, amt1.Sub(initBond), amt2))
   435  
   436  	// apply TM updates
   437  	app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
   438  
   439  	validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr)
   440  	require.True(t, found)
   441  	require.Equal(t, initBond.MulRaw(2), validator.DelegatorShares.RoundInt())
   442  	require.Equal(t, initBond.MulRaw(2), validator.BondedTokens())
   443  
   444  	// just send the same msgUnbond multiple times
   445  	// TODO use decimals here
   446  	unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))
   447  	msgUndelegate := types.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt)
   448  	numUnbonds := int64(5)
   449  
   450  	for i := int64(0); i < numUnbonds; i++ {
   451  		res := tstaking.Handle(msgUndelegate, true)
   452  
   453  		var resData types.MsgUndelegateResponse
   454  		err := proto.Unmarshal(res.Data, &resData)
   455  		require.NoError(t, err)
   456  
   457  		ctx = ctx.WithBlockTime(resData.CompletionTime)
   458  		tstaking.Ctx = ctx
   459  		staking.EndBlocker(ctx, app.StakingKeeper)
   460  
   461  		// check that the accounts and the bond account have the appropriate values
   462  		validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr)
   463  		require.True(t, found)
   464  		bond, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr)
   465  		require.True(t, found)
   466  
   467  		expBond := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1)))
   468  		expDelegatorShares := initBond.MulRaw(2).Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1)))
   469  		expDelegatorAcc := initBond.Sub(expBond)
   470  
   471  		gotBond := bond.Shares.RoundInt()
   472  		gotDelegatorShares := validator.DelegatorShares.RoundInt()
   473  		gotDelegatorAcc := app.BankKeeper.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount
   474  
   475  		require.Equal(t, expBond, gotBond,
   476  			"i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n",
   477  			i, expBond, gotBond, validator, bond)
   478  		require.Equal(t, expDelegatorShares, gotDelegatorShares,
   479  			"i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n",
   480  			i, expDelegatorShares, gotDelegatorShares, validator, bond)
   481  		require.Equal(t, expDelegatorAcc, gotDelegatorAcc,
   482  			"i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n",
   483  			i, expDelegatorAcc, gotDelegatorAcc, validator, bond)
   484  	}
   485  
   486  	// these are more than we have bonded now
   487  	errorCases := []sdk.Int{
   488  		// 1<<64 - 1, // more than int64 power
   489  		// 1<<63 + 1, // more than int64 power
   490  		app.StakingKeeper.TokensFromConsensusPower(ctx, 1<<63-1),
   491  		app.StakingKeeper.TokensFromConsensusPower(ctx, 1<<31),
   492  		initBond,
   493  	}
   494  
   495  	for _, c := range errorCases {
   496  		tstaking.Undelegate(delegatorAddr, validatorAddr, c, false)
   497  	}
   498  
   499  	// should be able to unbond remaining
   500  	leftBonded := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(numUnbonds)))
   501  	tstaking.Undelegate(delegatorAddr, validatorAddr, leftBonded, true)
   502  }
   503  
   504  func TestMultipleMsgCreateValidator(t *testing.T) {
   505  	initPower := int64(1000)
   506  	initTokens := sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)
   507  	app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   508  
   509  	params := app.StakingKeeper.GetParams(ctx)
   510  	blockTime := time.Now().UTC()
   511  	ctx = ctx.WithBlockTime(blockTime)
   512  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   513  
   514  	validatorAddrs := []sdk.ValAddress{
   515  		valAddrs[0],
   516  		valAddrs[1],
   517  		valAddrs[2],
   518  	}
   519  	delegatorAddrs := []sdk.AccAddress{
   520  		delAddrs[0],
   521  		delAddrs[1],
   522  		delAddrs[2],
   523  	}
   524  
   525  	// bond them all
   526  	amt := app.StakingKeeper.TokensFromConsensusPower(ctx, 10)
   527  	for i, validatorAddr := range validatorAddrs {
   528  		tstaking.CreateValidator(validatorAddr, PKs[i], amt, true)
   529  		// verify that the account is bonded
   530  		validators := app.StakingKeeper.GetValidators(ctx, 100)
   531  		require.Equal(t, (i + 1), len(validators))
   532  
   533  		val := validators[i]
   534  		balanceExpd := initTokens.Sub(amt)
   535  		balanceGot := app.BankKeeper.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount
   536  
   537  		require.Equal(t, i+1, len(validators), "expected %d validators got %d, validators: %v", i+1, len(validators), validators)
   538  		require.Equal(t, amt, val.DelegatorShares.RoundInt(), "expected %d shares, got %d", amt, val.DelegatorShares)
   539  		require.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot)
   540  	}
   541  
   542  	staking.EndBlocker(ctx, app.StakingKeeper)
   543  
   544  	// unbond them all by removing delegation
   545  	for i, validatorAddr := range validatorAddrs {
   546  		_, found := app.StakingKeeper.GetValidator(ctx, validatorAddr)
   547  		require.True(t, found)
   548  
   549  		res := tstaking.Undelegate(delegatorAddrs[i], validatorAddr, amt, true)
   550  
   551  		var resData types.MsgUndelegateResponse
   552  		err := proto.Unmarshal(res.Data, &resData)
   553  		require.NoError(t, err)
   554  
   555  		// adds validator into unbonding queue
   556  		staking.EndBlocker(ctx, app.StakingKeeper)
   557  
   558  		// removes validator from queue and set
   559  		staking.EndBlocker(ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)), app.StakingKeeper)
   560  
   561  		// Check that the validator is deleted from state
   562  		validators := app.StakingKeeper.GetValidators(ctx, 100)
   563  		require.Equal(t, len(validatorAddrs)-(i+1), len(validators),
   564  			"expected %d validators got %d", len(validatorAddrs)-(i+1), len(validators))
   565  
   566  		_, found = app.StakingKeeper.GetValidator(ctx, validatorAddr)
   567  		require.False(t, found)
   568  
   569  		gotBalance := app.BankKeeper.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount
   570  		require.Equal(t, initTokens, gotBalance, "expected account to have %d, got %d", initTokens, gotBalance)
   571  	}
   572  }
   573  
   574  func TestMultipleMsgDelegate(t *testing.T) {
   575  	initPower := int64(1000)
   576  	app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 50, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   577  	validatorAddr, delegatorAddrs := valAddrs[0], delAddrs[1:]
   578  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   579  	var amount int64 = 10
   580  
   581  	// first make a validator
   582  	tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(amount), true)
   583  
   584  	// delegate multiple parties
   585  	for _, delegatorAddr := range delegatorAddrs {
   586  		tstaking.Delegate(delegatorAddr, validatorAddr, sdk.NewInt(10))
   587  		tstaking.CheckDelegator(delegatorAddr, validatorAddr, true)
   588  	}
   589  
   590  	// unbond them all
   591  	for _, delegatorAddr := range delegatorAddrs {
   592  		res := tstaking.Undelegate(delegatorAddr, validatorAddr, sdk.NewInt(amount), true)
   593  
   594  		var resData types.MsgUndelegateResponse
   595  		err := proto.Unmarshal(res.Data, &resData)
   596  		require.NoError(t, err)
   597  
   598  		ctx = ctx.WithBlockTime(resData.CompletionTime)
   599  		staking.EndBlocker(ctx, app.StakingKeeper)
   600  		tstaking.Ctx = ctx
   601  
   602  		// check that the account is unbonded
   603  		_, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr)
   604  		require.False(t, found)
   605  	}
   606  }
   607  
   608  func TestJailValidator(t *testing.T) {
   609  	initPower := int64(1000)
   610  	app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   611  	validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1]
   612  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   613  	var amt int64 = 10
   614  
   615  	// create the validator and delegate
   616  	tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(amt), true)
   617  	tstaking.Delegate(delegatorAddr, validatorAddr, sdk.NewInt(amt))
   618  
   619  	// unbond the validators bond portion
   620  	unamt := sdk.NewInt(amt)
   621  	res := tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, unamt, true)
   622  
   623  	var resData types.MsgUndelegateResponse
   624  	err := proto.Unmarshal(res.Data, &resData)
   625  	require.NoError(t, err)
   626  
   627  	ctx = ctx.WithBlockTime(resData.CompletionTime)
   628  	staking.EndBlocker(ctx, app.StakingKeeper)
   629  	tstaking.Ctx = ctx
   630  
   631  	tstaking.CheckValidator(validatorAddr, -1, true)
   632  
   633  	// test that the delegator can still withdraw their bonds
   634  	tstaking.Undelegate(delegatorAddr, validatorAddr, unamt, true)
   635  
   636  	err = proto.Unmarshal(res.Data, &resData)
   637  	require.NoError(t, err)
   638  
   639  	ctx = ctx.WithBlockTime(resData.CompletionTime)
   640  	staking.EndBlocker(ctx, app.StakingKeeper)
   641  	tstaking.Ctx = ctx
   642  
   643  	// verify that the pubkey can now be reused
   644  	tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(amt), true)
   645  }
   646  
   647  func TestValidatorQueue(t *testing.T) {
   648  	initPower := int64(1000)
   649  	app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   650  	validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1]
   651  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   652  
   653  	// set the unbonding time
   654  	params := app.StakingKeeper.GetParams(ctx)
   655  	params.UnbondingTime = 7 * time.Second
   656  	app.StakingKeeper.SetParams(ctx, params)
   657  
   658  	// create the validator and make a bond
   659  	amt := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], 10, true)
   660  	tstaking.Delegate(delegatorAddr, validatorAddr, amt)
   661  	staking.EndBlocker(ctx, app.StakingKeeper)
   662  
   663  	// unbond the all self-delegation to put validator in unbonding state
   664  	res := tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, amt, true)
   665  
   666  	var resData types.MsgUndelegateResponse
   667  	err := proto.Unmarshal(res.Data, &resData)
   668  	require.NoError(t, err)
   669  
   670  	finishTime := resData.CompletionTime
   671  
   672  	ctx = tstaking.TurnBlock(finishTime)
   673  	origHeader := ctx.BlockHeader()
   674  
   675  	validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr)
   676  	require.True(t, found)
   677  	require.True(t, validator.IsUnbonding(), "%v", validator)
   678  
   679  	// should still be unbonding at time 6 seconds later
   680  	ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 6))
   681  
   682  	validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr)
   683  	require.True(t, found)
   684  	require.True(t, validator.IsUnbonding(), "%v", validator)
   685  
   686  	// should be in unbonded state at time 7 seconds later
   687  	ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 7))
   688  
   689  	validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr)
   690  	require.True(t, found)
   691  	require.True(t, validator.IsUnbonded(), "%v", validator)
   692  }
   693  
   694  func TestUnbondingPeriod(t *testing.T) {
   695  	initPower := int64(1000)
   696  	app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   697  	validatorAddr := valAddrs[0]
   698  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   699  
   700  	// set the unbonding time
   701  	params := app.StakingKeeper.GetParams(ctx)
   702  	params.UnbondingTime = 7 * time.Second
   703  	app.StakingKeeper.SetParams(ctx, params)
   704  
   705  	// create the validator
   706  	amt := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], 10, true)
   707  	staking.EndBlocker(ctx, app.StakingKeeper)
   708  
   709  	// begin unbonding
   710  	tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, amt, true)
   711  
   712  	origHeader := ctx.BlockHeader()
   713  
   714  	_, found := app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
   715  	require.True(t, found, "should not have unbonded")
   716  
   717  	// cannot complete unbonding at same time
   718  	staking.EndBlocker(ctx, app.StakingKeeper)
   719  	_, found = app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
   720  	require.True(t, found, "should not have unbonded")
   721  
   722  	// cannot complete unbonding at time 6 seconds later
   723  	ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 6))
   724  	_, found = app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
   725  	require.True(t, found, "should not have unbonded")
   726  
   727  	// can complete unbonding at time 7 seconds later
   728  	ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 7))
   729  	_, found = app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
   730  	require.False(t, found, "should have unbonded")
   731  }
   732  
   733  func TestUnbondingFromUnbondingValidator(t *testing.T) {
   734  	initPower := int64(1000)
   735  	app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   736  	validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1]
   737  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   738  
   739  	// create the validator and delegate
   740  	tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(10), true)
   741  	tstaking.Delegate(delegatorAddr, validatorAddr, sdk.NewInt(10))
   742  
   743  	// unbond the validators bond portion
   744  	unbondAmt := sdk.NewInt(10)
   745  	res := tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt, true)
   746  
   747  	// change the ctx to Block Time one second before the validator would have unbonded
   748  	var resData types.MsgUndelegateResponse
   749  	err := proto.Unmarshal(res.Data, &resData)
   750  	require.NoError(t, err)
   751  
   752  	ctx = ctx.WithBlockTime(resData.CompletionTime.Add(time.Second * -1))
   753  
   754  	// unbond the delegator from the validator
   755  	res = tstaking.Undelegate(delegatorAddr, validatorAddr, unbondAmt, true)
   756  
   757  	ctx = tstaking.TurnBlockTimeDiff(app.StakingKeeper.UnbondingTime(ctx))
   758  	tstaking.Ctx = ctx
   759  
   760  	// Check to make sure that the unbonding delegation is no longer in state
   761  	// (meaning it was deleted in the above EndBlocker)
   762  	_, found := app.StakingKeeper.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr)
   763  	require.False(t, found, "should be removed from state")
   764  }
   765  
   766  func TestRedelegationPeriod(t *testing.T) {
   767  	initPower := int64(1000)
   768  	app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   769  	validatorAddr, validatorAddr2 := valAddrs[0], valAddrs[1]
   770  	denom := app.StakingKeeper.GetParams(ctx).BondDenom
   771  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   772  
   773  	// set the unbonding time
   774  	params := app.StakingKeeper.GetParams(ctx)
   775  	params.UnbondingTime = 7 * time.Second
   776  	app.StakingKeeper.SetParams(ctx, params)
   777  	// initial balance
   778  	amt1 := app.BankKeeper.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount
   779  
   780  	// create the validators
   781  	tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(10), true)
   782  
   783  	// balance should have been subtracted after creation
   784  	amt2 := app.BankKeeper.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount
   785  	require.Equal(t, amt1.Sub(sdk.NewInt(10)), amt2, "expected coins to be subtracted")
   786  
   787  	tstaking.CreateValidator(validatorAddr2, PKs[1], sdk.NewInt(10), true)
   788  	bal1 := app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(validatorAddr))
   789  
   790  	// begin redelegate
   791  	redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))
   792  	msgBeginRedelegate := types.NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt)
   793  	tstaking.Handle(msgBeginRedelegate, true)
   794  
   795  	// origin account should not lose tokens as with a regular delegation
   796  	bal2 := app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(validatorAddr))
   797  	require.Equal(t, bal1, bal2)
   798  
   799  	origHeader := ctx.BlockHeader()
   800  
   801  	// cannot complete redelegation at same time
   802  	staking.EndBlocker(ctx, app.StakingKeeper)
   803  	_, found := app.StakingKeeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2)
   804  	require.True(t, found, "should not have unbonded")
   805  
   806  	// cannot complete redelegation at time 6 seconds later
   807  	ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 6))
   808  	_, found = app.StakingKeeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2)
   809  	require.True(t, found, "should not have unbonded")
   810  
   811  	// can complete redelegation at time 7 seconds later
   812  	ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 7))
   813  	_, found = app.StakingKeeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2)
   814  	require.False(t, found, "should have unbonded")
   815  }
   816  
   817  func TestTransitiveRedelegation(t *testing.T) {
   818  	initPower := int64(1000)
   819  	app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   820  
   821  	val1, val2, val3 := valAddrs[0], valAddrs[1], valAddrs[2]
   822  	blockTime := time.Now().UTC()
   823  	ctx = ctx.WithBlockTime(blockTime)
   824  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   825  
   826  	// create the validators
   827  	tstaking.CreateValidator(val1, PKs[0], sdk.NewInt(10), true)
   828  	tstaking.CreateValidator(val2, PKs[1], sdk.NewInt(10), true)
   829  	tstaking.CreateValidator(val3, PKs[2], sdk.NewInt(10), true)
   830  
   831  	// begin redelegate
   832  	redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))
   833  	msgBeginRedelegate := types.NewMsgBeginRedelegate(sdk.AccAddress(val1), val1, val2, redAmt)
   834  	tstaking.Handle(msgBeginRedelegate, true)
   835  
   836  	// cannot redelegation to next validator while first delegation exists
   837  	msgBeginRedelegate = types.NewMsgBeginRedelegate(sdk.AccAddress(val1), val2, val3, redAmt)
   838  	tstaking.Handle(msgBeginRedelegate, false)
   839  
   840  	params := app.StakingKeeper.GetParams(ctx)
   841  	ctx = ctx.WithBlockTime(blockTime.Add(params.UnbondingTime))
   842  	tstaking.Ctx = ctx
   843  
   844  	// complete first redelegation
   845  	staking.EndBlocker(ctx, app.StakingKeeper)
   846  
   847  	// now should be able to redelegate from the second validator to the third
   848  	tstaking.Handle(msgBeginRedelegate, true)
   849  }
   850  
   851  func TestMultipleRedelegationAtSameTime(t *testing.T) {
   852  	initPower := int64(1000)
   853  	app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   854  	valAddr := valAddrs[0]
   855  	valAddr2 := valAddrs[1]
   856  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   857  
   858  	// set the unbonding time
   859  	params := app.StakingKeeper.GetParams(ctx)
   860  	params.UnbondingTime = 1 * time.Second
   861  	app.StakingKeeper.SetParams(ctx, params)
   862  
   863  	// create the validators
   864  	valTokens := tstaking.CreateValidatorWithValPower(valAddr, PKs[0], 10, true)
   865  	tstaking.CreateValidator(valAddr2, PKs[1], valTokens, true)
   866  
   867  	// end block to bond them
   868  	staking.EndBlocker(ctx, app.StakingKeeper)
   869  
   870  	// begin a redelegate
   871  	selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator)
   872  	redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2))
   873  	msgBeginRedelegate := types.NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt)
   874  	tstaking.Handle(msgBeginRedelegate, true)
   875  
   876  	// there should only be one entry in the redelegation object
   877  	rd, found := app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2)
   878  	require.True(t, found)
   879  	require.Len(t, rd.Entries, 1)
   880  
   881  	// start a second redelegation at this same time as the first
   882  	tstaking.Handle(msgBeginRedelegate, true)
   883  
   884  	// now there should be two entries
   885  	rd, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2)
   886  	require.True(t, found)
   887  	require.Len(t, rd.Entries, 2)
   888  
   889  	// move forward in time, should complete both redelegations
   890  	ctx = tstaking.TurnBlockTimeDiff(1 * time.Second)
   891  	rd, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2)
   892  	require.False(t, found)
   893  }
   894  
   895  func TestMultipleRedelegationAtUniqueTimes(t *testing.T) {
   896  	initPower := int64(1000)
   897  	app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   898  	valAddr := valAddrs[0]
   899  	valAddr2 := valAddrs[1]
   900  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   901  
   902  	// set the unbonding time
   903  	params := app.StakingKeeper.GetParams(ctx)
   904  	params.UnbondingTime = 10 * time.Second
   905  	app.StakingKeeper.SetParams(ctx, params)
   906  
   907  	// create the validators
   908  	valTokens := tstaking.CreateValidatorWithValPower(valAddr, PKs[0], 10, true)
   909  	tstaking.CreateValidator(valAddr2, PKs[1], valTokens, true)
   910  
   911  	// end block to bond them
   912  	staking.EndBlocker(ctx, app.StakingKeeper)
   913  
   914  	// begin a redelegate
   915  	selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator)
   916  	redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2))
   917  	msgBeginRedelegate := types.NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt)
   918  	tstaking.Handle(msgBeginRedelegate, true)
   919  
   920  	// move forward in time and start a second redelegation
   921  	ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second))
   922  	tstaking.Ctx = ctx
   923  	tstaking.Handle(msgBeginRedelegate, true)
   924  
   925  	// now there should be two entries
   926  	rd, found := app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2)
   927  	require.True(t, found)
   928  	require.Len(t, rd.Entries, 2)
   929  
   930  	// move forward in time, should complete the first redelegation, but not the second
   931  	ctx = tstaking.TurnBlockTimeDiff(5 * time.Second)
   932  	rd, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2)
   933  	require.True(t, found)
   934  	require.Len(t, rd.Entries, 1)
   935  
   936  	// move forward in time, should complete the second redelegation
   937  	ctx = tstaking.TurnBlockTimeDiff(5 * time.Second)
   938  	rd, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2)
   939  	require.False(t, found)
   940  }
   941  
   942  func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) {
   943  	initPower := int64(1000)
   944  	app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   945  	valAddr := valAddrs[0]
   946  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   947  
   948  	// set the unbonding time
   949  	params := app.StakingKeeper.GetParams(ctx)
   950  	params.UnbondingTime = 1 * time.Second
   951  	app.StakingKeeper.SetParams(ctx, params)
   952  
   953  	// create the validators
   954  	valTokens := tstaking.CreateValidatorWithValPower(valAddr, PKs[0], 10, true)
   955  
   956  	// end block to bond
   957  	staking.EndBlocker(ctx, app.StakingKeeper)
   958  
   959  	// begin an unbonding delegation
   960  	selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator)
   961  	tstaking.Undelegate(selfDelAddr, valAddr, valTokens.QuoRaw(2), true)
   962  
   963  	// there should only be one entry in the ubd object
   964  	ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr)
   965  	require.True(t, found)
   966  	require.Len(t, ubd.Entries, 1)
   967  
   968  	// start a second ubd at this same time as the first
   969  	tstaking.Undelegate(selfDelAddr, valAddr, valTokens.QuoRaw(2), true)
   970  
   971  	// now there should be two entries
   972  	ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr)
   973  	require.True(t, found)
   974  	require.Len(t, ubd.Entries, 2)
   975  
   976  	// move forwaubd in time, should complete both ubds
   977  	ctx = tstaking.TurnBlockTimeDiff(1 * time.Second)
   978  	ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr)
   979  	require.False(t, found)
   980  }
   981  
   982  func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) {
   983  	initPower := int64(1000)
   984  	app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
   985  	valAddr := valAddrs[0]
   986  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   987  
   988  	// set the unbonding time
   989  	params := app.StakingKeeper.GetParams(ctx)
   990  	params.UnbondingTime = 10 * time.Second
   991  	app.StakingKeeper.SetParams(ctx, params)
   992  
   993  	// create the validator
   994  	valTokens := tstaking.CreateValidatorWithValPower(valAddr, PKs[0], 10, true)
   995  
   996  	// end block to bond
   997  	staking.EndBlocker(ctx, app.StakingKeeper)
   998  
   999  	// begin an unbonding delegation
  1000  	selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator)
  1001  	tstaking.Undelegate(selfDelAddr, valAddr, valTokens.QuoRaw(2), true)
  1002  
  1003  	// there should only be one entry in the ubd object
  1004  	ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr)
  1005  	require.True(t, found)
  1006  	require.Len(t, ubd.Entries, 1)
  1007  
  1008  	// move forwaubd in time and start a second redelegation
  1009  	ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second))
  1010  	tstaking.Ctx = ctx
  1011  	tstaking.Undelegate(selfDelAddr, valAddr, valTokens.QuoRaw(2), true)
  1012  
  1013  	// now there should be two entries
  1014  	ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr)
  1015  	require.True(t, found)
  1016  	require.Len(t, ubd.Entries, 2)
  1017  
  1018  	// move forwaubd in time, should complete the first redelegation, but not the second
  1019  	ctx = tstaking.TurnBlockTimeDiff(5 * time.Second)
  1020  	ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr)
  1021  	require.True(t, found)
  1022  	require.Len(t, ubd.Entries, 1)
  1023  
  1024  	// move forwaubd in time, should complete the second redelegation
  1025  	ctx = tstaking.TurnBlockTimeDiff(5 * time.Second)
  1026  	ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr)
  1027  	require.False(t, found)
  1028  }
  1029  
  1030  func TestUnbondingWhenExcessValidators(t *testing.T) {
  1031  	initPower := int64(1000)
  1032  	app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
  1033  	val1 := valAddrs[0]
  1034  	val2 := valAddrs[1]
  1035  	val3 := valAddrs[2]
  1036  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
  1037  
  1038  	// set the unbonding time
  1039  	params := app.StakingKeeper.GetParams(ctx)
  1040  	params.MaxValidators = 2
  1041  	app.StakingKeeper.SetParams(ctx, params)
  1042  
  1043  	// add three validators
  1044  	tstaking.CreateValidatorWithValPower(val1, PKs[0], 50, true)
  1045  	// apply TM updates
  1046  	app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
  1047  	require.Equal(t, 1, len(app.StakingKeeper.GetLastValidators(ctx)))
  1048  
  1049  	valTokens2 := tstaking.CreateValidatorWithValPower(val2, PKs[1], 30, true)
  1050  	app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
  1051  	require.Equal(t, 2, len(app.StakingKeeper.GetLastValidators(ctx)))
  1052  
  1053  	tstaking.CreateValidatorWithValPower(val3, PKs[2], 10, true)
  1054  	app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
  1055  	require.Equal(t, 2, len(app.StakingKeeper.GetLastValidators(ctx)))
  1056  
  1057  	// unbond the validator-2
  1058  	tstaking.Undelegate(sdk.AccAddress(val2), val2, valTokens2, true)
  1059  	// apply TM updates
  1060  	app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
  1061  
  1062  	// because there are extra validators waiting to get in, the queued
  1063  	// validator (aka. validator-1) should make it into the bonded group, thus
  1064  	// the total number of validators should stay the same
  1065  	vals := app.StakingKeeper.GetLastValidators(ctx)
  1066  	require.Equal(t, 2, len(vals), "vals %v", vals)
  1067  	tstaking.CheckValidator(val1, types.Bonded, false)
  1068  }
  1069  
  1070  func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
  1071  	initPower := int64(1000)
  1072  	app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
  1073  	valA, valB, del := valAddrs[0], valAddrs[1], delAddrs[2]
  1074  	consAddr0 := sdk.ConsAddress(PKs[0].Address())
  1075  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
  1076  
  1077  	valTokens := tstaking.CreateValidatorWithValPower(valA, PKs[0], 10, true)
  1078  	tstaking.CreateValidator(valB, PKs[1], valTokens, true)
  1079  
  1080  	// delegate 10 stake
  1081  	tstaking.Delegate(del, valA, valTokens)
  1082  
  1083  	// apply Tendermint updates
  1084  	updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
  1085  	require.NoError(t, err)
  1086  	require.Equal(t, 2, len(updates))
  1087  
  1088  	// a block passes
  1089  	ctx = ctx.WithBlockHeight(1)
  1090  	tstaking.Ctx = ctx
  1091  
  1092  	// begin unbonding 4 stake
  1093  	unbondAmt := app.StakingKeeper.TokensFromConsensusPower(ctx, 4)
  1094  	tstaking.Undelegate(del, valA, unbondAmt, true)
  1095  
  1096  	// begin redelegate 6 stake
  1097  	redAmt := sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 6))
  1098  	msgBeginRedelegate := types.NewMsgBeginRedelegate(del, valA, valB, redAmt)
  1099  	tstaking.Handle(msgBeginRedelegate, true)
  1100  
  1101  	// destination delegation should have 6 shares
  1102  	delegation, found := app.StakingKeeper.GetDelegation(ctx, del, valB)
  1103  	require.True(t, found)
  1104  	require.Equal(t, sdk.NewDecFromInt(redAmt.Amount), delegation.Shares)
  1105  
  1106  	// must apply validator updates
  1107  	updates, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
  1108  	require.NoError(t, err)
  1109  	require.Equal(t, 2, len(updates))
  1110  
  1111  	// slash the validator by half
  1112  	app.StakingKeeper.Slash(ctx, consAddr0, 0, 20, sdk.NewDecWithPrec(5, 1))
  1113  
  1114  	// unbonding delegation should have been slashed by half
  1115  	ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, del, valA)
  1116  	require.True(t, found)
  1117  	require.Len(t, ubd.Entries, 1)
  1118  	require.Equal(t, unbondAmt.QuoRaw(2), ubd.Entries[0].Balance)
  1119  
  1120  	// redelegation should have been slashed by half
  1121  	redelegation, found := app.StakingKeeper.GetRedelegation(ctx, del, valA, valB)
  1122  	require.True(t, found)
  1123  	require.Len(t, redelegation.Entries, 1)
  1124  
  1125  	// destination delegation should have been slashed by half
  1126  	delegation, found = app.StakingKeeper.GetDelegation(ctx, del, valB)
  1127  	require.True(t, found)
  1128  	require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares)
  1129  
  1130  	// validator power should have been reduced by half
  1131  	validator, found := app.StakingKeeper.GetValidator(ctx, valA)
  1132  	require.True(t, found)
  1133  	require.Equal(t, valTokens.QuoRaw(2), validator.GetBondedTokens())
  1134  
  1135  	// slash the validator for an infraction committed after the unbonding and redelegation begin
  1136  	ctx = ctx.WithBlockHeight(3)
  1137  	app.StakingKeeper.Slash(ctx, consAddr0, 2, 10, sdk.NewDecWithPrec(5, 1))
  1138  	tstaking.Ctx = ctx
  1139  
  1140  	// unbonding delegation should be unchanged
  1141  	ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, del, valA)
  1142  	require.True(t, found)
  1143  	require.Len(t, ubd.Entries, 1)
  1144  	require.Equal(t, unbondAmt.QuoRaw(2), ubd.Entries[0].Balance)
  1145  
  1146  	// redelegation should be unchanged
  1147  	redelegation, found = app.StakingKeeper.GetRedelegation(ctx, del, valA, valB)
  1148  	require.True(t, found)
  1149  	require.Len(t, redelegation.Entries, 1)
  1150  
  1151  	// destination delegation should be unchanged
  1152  	delegation, found = app.StakingKeeper.GetDelegation(ctx, del, valB)
  1153  	require.True(t, found)
  1154  	require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares)
  1155  
  1156  	// end blocker
  1157  	staking.EndBlocker(ctx, app.StakingKeeper)
  1158  
  1159  	// validator power should have been reduced to zero
  1160  	// validator should be in unbonding state
  1161  	validator, _ = app.StakingKeeper.GetValidator(ctx, valA)
  1162  	require.Equal(t, validator.GetStatus(), types.Unbonding)
  1163  }
  1164  
  1165  func TestInvalidMsg(t *testing.T) {
  1166  	k := keeper.Keeper{}
  1167  	h := staking.NewHandler(k)
  1168  
  1169  	res, err := h(sdk.NewContext(nil, tmproto.Header{}, false, nil), testdata.NewTestMsg())
  1170  	require.Error(t, err)
  1171  	require.Nil(t, res)
  1172  	require.True(t, strings.Contains(err.Error(), "unrecognized staking message type"))
  1173  }
  1174  
  1175  func TestInvalidCoinDenom(t *testing.T) {
  1176  	initPower := int64(1000)
  1177  	app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction))
  1178  	valA, valB, delAddr := valAddrs[0], valAddrs[1], delAddrs[2]
  1179  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
  1180  
  1181  	valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 100)
  1182  	invalidCoin := sdk.NewCoin("churros", valTokens)
  1183  	validCoin := sdk.NewCoin(sdk.DefaultBondDenom, valTokens)
  1184  	oneCoin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt())
  1185  
  1186  	commission := types.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.ZeroDec())
  1187  	msgCreate, err := types.NewMsgCreateValidator(valA, PKs[0], invalidCoin, types.Description{}, commission, sdk.OneInt())
  1188  	require.NoError(t, err)
  1189  	tstaking.Handle(msgCreate, false)
  1190  
  1191  	msgCreate, err = types.NewMsgCreateValidator(valA, PKs[0], validCoin, types.Description{}, commission, sdk.OneInt())
  1192  	require.NoError(t, err)
  1193  	tstaking.Handle(msgCreate, true)
  1194  
  1195  	msgCreate, err = types.NewMsgCreateValidator(valB, PKs[1], validCoin, types.Description{}, commission, sdk.OneInt())
  1196  	require.NoError(t, err)
  1197  	tstaking.Handle(msgCreate, true)
  1198  
  1199  	msgDelegate := types.NewMsgDelegate(delAddr, valA, invalidCoin)
  1200  	tstaking.Handle(msgDelegate, false)
  1201  
  1202  	msgDelegate = types.NewMsgDelegate(delAddr, valA, validCoin)
  1203  	tstaking.Handle(msgDelegate, true)
  1204  
  1205  	msgUndelegate := types.NewMsgUndelegate(delAddr, valA, invalidCoin)
  1206  	tstaking.Handle(msgUndelegate, false)
  1207  
  1208  	msgUndelegate = types.NewMsgUndelegate(delAddr, valA, oneCoin)
  1209  	tstaking.Handle(msgUndelegate, true)
  1210  
  1211  	msgRedelegate := types.NewMsgBeginRedelegate(delAddr, valA, valB, invalidCoin)
  1212  	tstaking.Handle(msgRedelegate, false)
  1213  
  1214  	msgRedelegate = types.NewMsgBeginRedelegate(delAddr, valA, valB, oneCoin)
  1215  	tstaking.Handle(msgRedelegate, true)
  1216  }