Merge PR #2394: Split up UpdateValidator into distinct state transitions applied only in EndBlock
This commit is contained in:
parent
a7fabbea16
commit
324bdaf55d
16
Gopkg.lock
generated
16
Gopkg.lock
generated
@ -239,12 +239,12 @@
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:645110e089152bd0f4a011a2648fbb0e4df5977be73ca605781157ac297f50c4"
|
||||
digest = "1:e32dfc6abff6a3633ef4d9a1022fd707c8ef26f1e1e8f855dc58dc415ce7c8f3"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "fa473d140ef3c6adf42d6b391fe76707f1f243c8"
|
||||
version = "v1.0.0"
|
||||
revision = "fe40af7a9c397fa3ddba203c38a5042c5d0475ad"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e"
|
||||
@ -536,7 +536,7 @@
|
||||
"salsa20/salsa",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "0e37d006457bf46f9e6692014ba72ef82c33022c"
|
||||
revision = "e3636079e1a4c1f337f212cc5cd2aca108f6c900"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d36f55a999540d29b6ea3c2ea29d71c76b1d9853fdcd3e5c5cb4836f2ba118f1"
|
||||
@ -556,14 +556,14 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:68023dc297a659d5eb2dafd62eda811456b338c5b3ec3c27da79e8a47d3f456a"
|
||||
digest = "1:8bc8ecef1d63576cfab4d08b44a1f255dd67e5b019b7a44837d62380f266a91c"
|
||||
name = "golang.org/x/sys"
|
||||
packages = [
|
||||
"cpu",
|
||||
"unix",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "2f1df4e56cdeb503a08d8577e6f1a7eb12efab82"
|
||||
revision = "e4b3c5e9061176387e7cea65e4dc5853801f3fb7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
|
||||
@ -590,11 +590,11 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:56b0bca90b7e5d1facf5fbdacba23e4e0ce069d25381b8e2f70ef1e7ebfb9c1a"
|
||||
digest = "1:1e6b0176e8c5dd8ff551af65c76f8b73a99bcf4d812cedff1b91711b7df4804c"
|
||||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/rpc/status"]
|
||||
pruneopts = "UT"
|
||||
revision = "0e822944c569bf5c9afd034adaa56208bd2906ac"
|
||||
revision = "c7e5094acea1ca1b899e2259d80a6b0f882f81f8"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2dab32a43451e320e49608ff4542fdfc653c95dcc35d0065ec9c6c3dd540ed74"
|
||||
|
||||
@ -64,6 +64,7 @@ BREAKING CHANGES
|
||||
* [x/auth] \#2377 auth.StdSignMsg -> txbuilder.StdSignMsg
|
||||
* [x/staking] \#2244 staking now holds a consensus-address-index instead of a consensus-pubkey-index
|
||||
* [x/staking] \#2236 more distribution hooks for distribution
|
||||
* [x/stake] \#2394 Split up UpdateValidator into distinct state transitions applied only in EndBlock
|
||||
|
||||
* Tendermint
|
||||
|
||||
|
||||
@ -45,6 +45,7 @@ func TestTallyNoOneVotes(t *testing.T) {
|
||||
}
|
||||
|
||||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 5})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
proposalID := proposal.GetProposalID()
|
||||
@ -69,6 +70,7 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) {
|
||||
}
|
||||
|
||||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 5})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
proposalID := proposal.GetProposalID()
|
||||
@ -98,6 +100,7 @@ func TestTallyOnlyValidators51No(t *testing.T) {
|
||||
}
|
||||
|
||||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
proposalID := proposal.GetProposalID()
|
||||
@ -126,6 +129,7 @@ func TestTallyOnlyValidators51Yes(t *testing.T) {
|
||||
}
|
||||
|
||||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
proposalID := proposal.GetProposalID()
|
||||
@ -157,6 +161,7 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) {
|
||||
}
|
||||
|
||||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
proposalID := proposal.GetProposalID()
|
||||
@ -188,6 +193,7 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) {
|
||||
}
|
||||
|
||||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
proposalID := proposal.GetProposalID()
|
||||
@ -219,6 +225,7 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) {
|
||||
}
|
||||
|
||||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
proposalID := proposal.GetProposalID()
|
||||
@ -250,6 +257,7 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) {
|
||||
}
|
||||
|
||||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
proposalID := proposal.GetProposalID()
|
||||
@ -279,6 +287,7 @@ func TestTallyDelgatorOverride(t *testing.T) {
|
||||
}
|
||||
|
||||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 30))
|
||||
stakeHandler(ctx, delegator1Msg)
|
||||
@ -315,6 +324,7 @@ func TestTallyDelgatorInherit(t *testing.T) {
|
||||
}
|
||||
|
||||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 30))
|
||||
stakeHandler(ctx, delegator1Msg)
|
||||
@ -349,6 +359,7 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) {
|
||||
}
|
||||
|
||||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10))
|
||||
stakeHandler(ctx, delegator1Msg)
|
||||
@ -402,6 +413,8 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) {
|
||||
delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin("steak", 10))
|
||||
stakeHandler(ctx, delegator1Msg2)
|
||||
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
proposalID := proposal.GetProposalID()
|
||||
proposal.SetStatus(StatusVotingPeriod)
|
||||
@ -432,6 +445,7 @@ func TestTallyJailedValidator(t *testing.T) {
|
||||
}
|
||||
|
||||
createValidators(t, stakeHandler, ctx, valAddrs, []int64{25, 6, 7})
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10))
|
||||
stakeHandler(ctx, delegator1Msg)
|
||||
@ -443,6 +457,8 @@ func TestTallyJailedValidator(t *testing.T) {
|
||||
require.True(t, found)
|
||||
sk.Jail(ctx, sdk.ConsAddress(val2.ConsPubKey.Address()))
|
||||
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
proposalID := proposal.GetProposalID()
|
||||
proposal.SetStatus(StatusVotingPeriod)
|
||||
|
||||
@ -36,12 +36,8 @@ func initChain(r *rand.Rand, accounts []Account, setups []RandSetup, app *baseap
|
||||
res := app.InitChain(abci.RequestInitChain{AppStateBytes: appStateFn(r, accounts)})
|
||||
validators = make(map[string]mockValidator)
|
||||
for _, validator := range res.Validators {
|
||||
pubkey, err := tmtypes.PB2TM.PubKey(validator.PubKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
address := pubkey.Address()
|
||||
validators[string(address)] = mockValidator{validator, GetMemberOfInitialState(r, initialLivenessWeightings)}
|
||||
str := fmt.Sprintf("%v", validator.PubKey)
|
||||
validators[str] = mockValidator{validator, GetMemberOfInitialState(r, initialLivenessWeightings)}
|
||||
}
|
||||
|
||||
for i := 0; i < len(setups); i++ {
|
||||
@ -400,22 +396,23 @@ func RandomRequestBeginBlock(r *rand.Rand, validators map[string]mockValidator,
|
||||
func updateValidators(tb testing.TB, r *rand.Rand, current map[string]mockValidator, updates []abci.ValidatorUpdate, event func(string)) map[string]mockValidator {
|
||||
|
||||
for _, update := range updates {
|
||||
str := fmt.Sprintf("%v", update.PubKey)
|
||||
switch {
|
||||
case update.Power == 0:
|
||||
if _, ok := current[string(update.PubKey.Data)]; !ok {
|
||||
if _, ok := current[str]; !ok {
|
||||
tb.Fatalf("tried to delete a nonexistent validator")
|
||||
}
|
||||
|
||||
event("endblock/validatorupdates/kicked")
|
||||
delete(current, string(update.PubKey.Data))
|
||||
delete(current, str)
|
||||
default:
|
||||
// Does validator already exist?
|
||||
if mVal, ok := current[string(update.PubKey.Data)]; ok {
|
||||
if mVal, ok := current[str]; ok {
|
||||
mVal.val = update
|
||||
event("endblock/validatorupdates/updated")
|
||||
} else {
|
||||
// Set this new validator
|
||||
current[string(update.PubKey.Data)] = mockValidator{update, GetMemberOfInitialState(r, initialLivenessWeightings)}
|
||||
current[str] = mockValidator{update, GetMemberOfInitialState(r, initialLivenessWeightings)}
|
||||
event("endblock/validatorupdates/added")
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,6 +45,9 @@ func TestJailedValidatorDelegations(t *testing.T) {
|
||||
got := stake.NewHandler(stakeKeeper)(ctx, msgCreateVal)
|
||||
require.True(t, got.IsOK(), "expected create validator msg to be ok, got: %v", got)
|
||||
|
||||
// end block
|
||||
stake.EndBlocker(ctx, stakeKeeper)
|
||||
|
||||
// set dummy signing info
|
||||
newInfo := ValidatorSigningInfo{
|
||||
StartHeight: int64(0),
|
||||
|
||||
@ -85,13 +85,16 @@ func TestSlashingPeriodCap(t *testing.T) {
|
||||
|
||||
// double sign less than max age
|
||||
keeper.handleDoubleSign(ctx, valConsPubKey.Address(), 0, time.Unix(0, 0), amtInt)
|
||||
|
||||
// should be jailed
|
||||
require.True(t, sk.Validator(ctx, addr).GetJailed())
|
||||
// end block
|
||||
stake.EndBlocker(ctx, sk)
|
||||
// update block height
|
||||
ctx = ctx.WithBlockHeight(int64(1))
|
||||
// unjail to measure power
|
||||
sk.Unjail(ctx, valConsAddr)
|
||||
// end block
|
||||
stake.EndBlocker(ctx, sk)
|
||||
// power should be reduced
|
||||
expectedPower := sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20)))
|
||||
require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower())
|
||||
@ -100,10 +103,14 @@ func TestSlashingPeriodCap(t *testing.T) {
|
||||
keeper.handleDoubleSign(ctx, valConsPubKey.Address(), 0, time.Unix(0, 0), amtInt)
|
||||
// should be jailed
|
||||
require.True(t, sk.Validator(ctx, addr).GetJailed())
|
||||
// end block
|
||||
stake.EndBlocker(ctx, sk)
|
||||
// update block height
|
||||
ctx = ctx.WithBlockHeight(int64(2))
|
||||
// unjail to measure power
|
||||
sk.Unjail(ctx, valConsAddr)
|
||||
// end block
|
||||
stake.EndBlocker(ctx, sk)
|
||||
// power should be equal, no more should have been slashed
|
||||
expectedPower = sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20)))
|
||||
require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower())
|
||||
@ -114,6 +121,8 @@ func TestSlashingPeriodCap(t *testing.T) {
|
||||
require.True(t, sk.Validator(ctx, addr).GetJailed())
|
||||
// unjail to measure power
|
||||
sk.Unjail(ctx, valConsAddr)
|
||||
// end block
|
||||
stake.EndBlocker(ctx, sk)
|
||||
// power should be reduced
|
||||
expectedPower = sdk.NewDecFromInt(amt).Mul(sdk.NewDec(18).Quo(sdk.NewDec(20)))
|
||||
require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower())
|
||||
@ -180,6 +189,9 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||
require.Equal(t, int64(0), info.StartHeight)
|
||||
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-1, info.SignedBlocksCounter)
|
||||
|
||||
// end block
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
// validator should have been jailed
|
||||
validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val))
|
||||
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
||||
@ -193,6 +205,9 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||
got = slh(ctx, NewMsgUnjail(addr))
|
||||
require.True(t, got.IsOK())
|
||||
|
||||
// end block
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
// validator should be rebonded now
|
||||
validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val))
|
||||
require.Equal(t, sdk.Bonded, validator.GetStatus())
|
||||
@ -222,12 +237,19 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
|
||||
}
|
||||
|
||||
// end block
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
// validator should be jailed again after 500 unsigned blocks
|
||||
nextHeight = height + keeper.MinSignedPerWindow(ctx) + 1
|
||||
for ; height <= nextHeight; height++ {
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
|
||||
}
|
||||
|
||||
// end block
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val))
|
||||
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
||||
}
|
||||
@ -296,6 +318,9 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
|
||||
}
|
||||
|
||||
// end block
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
// validator should have been jailed and slashed
|
||||
validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val))
|
||||
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
||||
|
||||
@ -77,6 +77,9 @@ func TestBeginBlocker(t *testing.T) {
|
||||
BeginBlocker(ctx, req, keeper)
|
||||
}
|
||||
|
||||
// end block
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
// validator should be jailed
|
||||
validator, found := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(pk))
|
||||
require.True(t, found)
|
||||
|
||||
@ -17,7 +17,7 @@ import (
|
||||
// Returns final validator set after applying all declaration and delegations
|
||||
func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res []abci.ValidatorUpdate, err error) {
|
||||
keeper.SetPool(ctx, data.Pool)
|
||||
keeper.SetNewParams(ctx, data.Params)
|
||||
keeper.SetParams(ctx, data.Params)
|
||||
keeper.InitIntraTxCounter(ctx)
|
||||
|
||||
for i, validator := range data.Validators {
|
||||
@ -31,26 +31,16 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [
|
||||
return res, errors.Errorf("genesis validator cannot have zero delegator shares, validator: %v", validator)
|
||||
}
|
||||
|
||||
// Manually set indexes for the first time
|
||||
// Manually set indices for the first time
|
||||
keeper.SetValidatorByConsAddr(ctx, validator)
|
||||
keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool)
|
||||
|
||||
if validator.Status == sdk.Bonded {
|
||||
keeper.SetValidatorBondedIndex(ctx, validator)
|
||||
}
|
||||
}
|
||||
|
||||
for _, bond := range data.Bonds {
|
||||
keeper.SetDelegation(ctx, bond)
|
||||
}
|
||||
|
||||
keeper.UpdateBondedValidatorsFull(ctx)
|
||||
|
||||
vals := keeper.GetValidatorsBonded(ctx)
|
||||
res = make([]abci.ValidatorUpdate, len(vals))
|
||||
for i, val := range vals {
|
||||
res[i] = val.ABCIValidatorUpdate()
|
||||
}
|
||||
res = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -52,7 +52,7 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.Valid
|
||||
k.SetIntraTxCounter(ctx, 0)
|
||||
|
||||
// calculate validator set changes
|
||||
ValidatorUpdates = k.GetTendermintUpdates(ctx)
|
||||
ValidatorUpdates = k.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
@ -82,7 +82,6 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k
|
||||
msg.Commission.Rate, msg.Commission.MaxChangeRate,
|
||||
msg.Commission.MaxChangeRate, ctx.BlockHeader().Time,
|
||||
)
|
||||
|
||||
validator, err := validator.SetInitialCommission(commission)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
@ -90,6 +89,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k
|
||||
|
||||
k.SetValidator(ctx, validator)
|
||||
k.SetValidatorByConsAddr(ctx, validator)
|
||||
k.SetNewValidatorByPowerIndex(ctx, validator)
|
||||
|
||||
// move coins from the msg.Address account to a (self-delegation) delegator account
|
||||
// the validator account and global shares are updated within here
|
||||
@ -130,13 +130,13 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe
|
||||
validator.Description = description
|
||||
|
||||
if msg.CommissionRate != nil {
|
||||
if err := k.UpdateValidatorCommission(ctx, validator, *msg.CommissionRate); err != nil {
|
||||
commission, err := k.UpdateValidatorCommission(ctx, validator, *msg.CommissionRate)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
validator.Commission = commission
|
||||
}
|
||||
|
||||
// We don't need to run through all the power update logic within k.UpdateValidator
|
||||
// We just need to override the entry in state, since only the description has changed.
|
||||
k.SetValidator(ctx, validator)
|
||||
|
||||
tags := sdk.NewTags(
|
||||
|
||||
@ -63,6 +63,10 @@ func TestValidatorByPowerIndex(t *testing.T) {
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got)
|
||||
|
||||
// must end-block
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
|
||||
// verify the self-delegation exists
|
||||
bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
|
||||
require.True(t, found)
|
||||
@ -83,14 +87,20 @@ func TestValidatorByPowerIndex(t *testing.T) {
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got)
|
||||
|
||||
// must end-block
|
||||
updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
|
||||
// slash and jail the first validator
|
||||
consAddr0 := sdk.ConsAddress(keep.PKs[0].Address())
|
||||
keeper.Slash(ctx, consAddr0, 0, initBond, sdk.NewDecWithPrec(5, 1))
|
||||
keeper.Jail(ctx, consAddr0)
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
validator, found = keeper.GetValidator(ctx, validatorAddr)
|
||||
require.True(t, found)
|
||||
require.Equal(t, sdk.Unbonding, validator.Status) // ensure is unbonding
|
||||
require.Equal(t, int64(500000), validator.Tokens.RoundInt64()) // ensure tokens slashed
|
||||
keeper.Unjail(ctx, consAddr0)
|
||||
|
||||
// the old power record should have been deleted as the power changed
|
||||
require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power))
|
||||
@ -121,6 +131,8 @@ func TestValidatorByPowerIndex(t *testing.T) {
|
||||
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
// verify that by power key nolonger exists
|
||||
_, found = keeper.GetValidator(ctx, validatorAddr)
|
||||
require.False(t, found)
|
||||
@ -136,8 +148,10 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) {
|
||||
msgCreateValidator1 := newTestMsgCreateValidator(addr1, pk1, 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator1, keeper)
|
||||
require.True(t, got.IsOK(), "%v", got)
|
||||
validator, found := keeper.GetValidator(ctx, addr1)
|
||||
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, addr1)
|
||||
require.True(t, found)
|
||||
assert.Equal(t, sdk.Bonded, validator.Status)
|
||||
assert.Equal(t, addr1, validator.OperatorAddr)
|
||||
@ -160,6 +174,11 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) {
|
||||
msgCreateValidator4 := newTestMsgCreateValidator(addr2, pk2, 10)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator4, keeper)
|
||||
require.True(t, got.IsOK(), "%v", got)
|
||||
|
||||
// must end-block
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
|
||||
validator, found = keeper.GetValidator(ctx, addr2)
|
||||
|
||||
require.True(t, found)
|
||||
@ -180,6 +199,11 @@ func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) {
|
||||
msgCreateValidatorOnBehalfOf := newTestMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper)
|
||||
require.True(t, got.IsOK(), "%v", got)
|
||||
|
||||
// must end-block
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, validatorAddr)
|
||||
|
||||
require.True(t, found)
|
||||
@ -211,6 +235,10 @@ func TestLegacyValidatorDelegations(t *testing.T) {
|
||||
got := handleMsgCreateValidator(ctx, msgCreateVal, keeper)
|
||||
require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got)
|
||||
|
||||
// must end-block
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
|
||||
// verify the validator exists and has the correct attributes
|
||||
validator, found := keeper.GetValidator(ctx, valAddr)
|
||||
require.True(t, found)
|
||||
@ -302,6 +330,9 @@ func TestIncrementsMsgDelegate(t *testing.T) {
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got)
|
||||
|
||||
// apply TM updates
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, validatorAddr)
|
||||
require.True(t, found)
|
||||
require.Equal(t, sdk.Bonded, validator.Status)
|
||||
@ -384,6 +415,9 @@ func TestIncrementsMsgUnbond(t *testing.T) {
|
||||
amt2 := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(denom)
|
||||
require.Equal(t, amt1.Sub(sdk.NewInt(initBond)).Int64(), amt2.Int64(), "expected coins to be subtracted")
|
||||
|
||||
// apply TM updates
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, validatorAddr)
|
||||
require.True(t, found)
|
||||
require.Equal(t, initBond*2, validator.DelegatorShares.RoundInt64())
|
||||
@ -533,11 +567,8 @@ func TestMultipleMsgDelegate(t *testing.T) {
|
||||
// unbond them all
|
||||
for i, delegatorAddr := range delegatorAddrs {
|
||||
msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10))
|
||||
msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr)
|
||||
got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
||||
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
||||
|
||||
//Check that the account is unbonded
|
||||
_, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr)
|
||||
@ -564,11 +595,8 @@ func TestJailValidator(t *testing.T) {
|
||||
|
||||
// unbond the validators bond portion
|
||||
msgBeginUnbondingValidator := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(10))
|
||||
msgCompleteUnbondingValidator := NewMsgCompleteUnbonding(sdk.AccAddress(validatorAddr), validatorAddr)
|
||||
got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbondingValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
require.True(t, got.IsOK(), "expected no error: %v", got)
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, validatorAddr)
|
||||
require.True(t, found)
|
||||
@ -750,16 +778,22 @@ func TestUnbondingWhenExcessValidators(t *testing.T) {
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr1, keep.PKs[0], 50)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
// apply TM updates
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(keeper.GetValidatorsBonded(ctx)))
|
||||
|
||||
msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 30)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
// apply TM updates
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx)))
|
||||
|
||||
msgCreateValidator = newTestMsgCreateValidator(validatorAddr3, keep.PKs[2], 10)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
// apply TM updates
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx)))
|
||||
|
||||
// unbond the valdator-2
|
||||
@ -767,6 +801,9 @@ func TestUnbondingWhenExcessValidators(t *testing.T) {
|
||||
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding")
|
||||
|
||||
// apply TM updates
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// because there are extra validators waiting to get in, the queued
|
||||
// validator (aka. validator-1) should make it into the bonded group, thus
|
||||
// the total number of validators should stay the same
|
||||
@ -777,142 +814,6 @@ func TestUnbondingWhenExcessValidators(t *testing.T) {
|
||||
require.Equal(t, sdk.Bonded, val1.Status, "%v", val1)
|
||||
}
|
||||
|
||||
func TestJoiningAsCliffValidator(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
validatorAddr1, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1])
|
||||
|
||||
// make sure that the cliff validator is nil to begin with
|
||||
cliffVal := keeper.GetCliffValidator(ctx)
|
||||
require.Equal(t, []byte(nil), cliffVal)
|
||||
|
||||
// set the unbonding time
|
||||
params := keeper.GetParams(ctx)
|
||||
params.UnbondingTime = 0
|
||||
params.MaxValidators = 2
|
||||
keeper.SetParams(ctx, params)
|
||||
|
||||
// add the first validator
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr1, keep.PKs[0], 50)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
// cliff validator should still be nil
|
||||
cliffVal = keeper.GetCliffValidator(ctx)
|
||||
require.Equal(t, []byte(nil), cliffVal)
|
||||
|
||||
// Add the second validator
|
||||
msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 30)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
// now that we've reached maximum validators, the val-2 should be added to the cliff (top)
|
||||
cliffVal = keeper.GetCliffValidator(ctx)
|
||||
require.Equal(t, validatorAddr2.Bytes(), cliffVal)
|
||||
}
|
||||
|
||||
func TestJoiningToCreateFirstCliffValidator(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
validatorAddr1, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1])
|
||||
|
||||
// make sure that the cliff validator is nil to begin with
|
||||
cliffVal := keeper.GetCliffValidator(ctx)
|
||||
require.Equal(t, []byte(nil), cliffVal)
|
||||
|
||||
// set the unbonding time
|
||||
params := keeper.GetParams(ctx)
|
||||
params.UnbondingTime = 0
|
||||
params.MaxValidators = 2
|
||||
keeper.SetParams(ctx, params)
|
||||
|
||||
// add the first validator
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr1, keep.PKs[0], 50)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
// cliff validator should still be nil
|
||||
cliffVal = keeper.GetCliffValidator(ctx)
|
||||
require.Equal(t, []byte(nil), cliffVal)
|
||||
|
||||
// Add the second validator
|
||||
msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 60)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
// now that we've reached maximum validators, validator-1 should be added to the cliff (top)
|
||||
cliffVal = keeper.GetCliffValidator(ctx)
|
||||
require.Equal(t, validatorAddr1.Bytes(), cliffVal)
|
||||
}
|
||||
|
||||
func TestCliffValidator(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
validatorAddr1 := sdk.ValAddress(keep.Addrs[0])
|
||||
validatorAddr2 := sdk.ValAddress(keep.Addrs[1])
|
||||
validatorAddr3 := sdk.ValAddress(keep.Addrs[2])
|
||||
|
||||
// make sure that the cliff validator is nil to begin with
|
||||
cliffVal := keeper.GetCliffValidator(ctx)
|
||||
require.Equal(t, []byte(nil), cliffVal)
|
||||
|
||||
// set the unbonding time
|
||||
params := keeper.GetParams(ctx)
|
||||
params.UnbondingTime = 0
|
||||
params.MaxValidators = 2
|
||||
keeper.SetParams(ctx, params)
|
||||
|
||||
// add the first validator
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr1, keep.PKs[0], 50)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
// cliff validator should still be nil
|
||||
cliffVal = keeper.GetCliffValidator(ctx)
|
||||
require.Equal(t, []byte(nil), cliffVal)
|
||||
|
||||
// Add the second validator
|
||||
msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 30)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
// now that we've reached maximum validators, validator-2 should be added to the cliff (top)
|
||||
cliffVal = keeper.GetCliffValidator(ctx)
|
||||
require.Equal(t, validatorAddr2.Bytes(), cliffVal)
|
||||
|
||||
// add the third validator, which should not make it to being bonded,
|
||||
// so the cliff validator should not change because nobody has been kicked out
|
||||
msgCreateValidator = newTestMsgCreateValidator(validatorAddr3, keep.PKs[2], 10)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
cliffVal = keeper.GetCliffValidator(ctx)
|
||||
require.Equal(t, validatorAddr2.Bytes(), cliffVal)
|
||||
|
||||
// unbond valdator-2
|
||||
msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr2), validatorAddr2, sdk.NewDec(30))
|
||||
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding")
|
||||
|
||||
vals := keeper.GetValidatorsBonded(ctx)
|
||||
require.Equal(t, 2, len(vals))
|
||||
|
||||
// now the validator set should be updated,
|
||||
// where val-3 enters the validator set on the cliff
|
||||
cliffVal = keeper.GetCliffValidator(ctx)
|
||||
require.Equal(t, validatorAddr3.Bytes(), cliffVal)
|
||||
|
||||
// unbond valdator-1
|
||||
msgBeginUnbonding = NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr1), validatorAddr1, sdk.NewDec(50))
|
||||
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding")
|
||||
|
||||
// get bonded validators - should just be one
|
||||
vals = keeper.GetValidatorsBonded(ctx)
|
||||
require.Equal(t, 1, len(vals))
|
||||
|
||||
// cliff now should be empty
|
||||
cliffVal = keeper.GetCliffValidator(ctx)
|
||||
require.Equal(t, []byte(nil), cliffVal)
|
||||
}
|
||||
|
||||
func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
valA, valB, del := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2]
|
||||
@ -931,6 +832,10 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
|
||||
got = handleMsgDelegate(ctx, msgDelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgDelegate")
|
||||
|
||||
// apply Tendermint updates
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 2, len(updates))
|
||||
|
||||
// a block passes
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
|
||||
@ -949,6 +854,10 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
|
||||
require.True(t, found)
|
||||
require.Equal(t, sdk.NewDec(6), delegation.Shares)
|
||||
|
||||
// must apply validator updates
|
||||
updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 2, len(updates))
|
||||
|
||||
// slash the validator by half
|
||||
keeper.Slash(ctx, consAddr0, 0, 20, sdk.NewDecWithPrec(5, 1))
|
||||
|
||||
@ -991,6 +900,9 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
|
||||
require.True(t, found)
|
||||
require.Equal(t, sdk.NewDec(3), delegation.Shares)
|
||||
|
||||
// end blocker
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
// validator power should have been reduced to zero
|
||||
// ergo validator should have been removed from the store
|
||||
_, found = keeper.GetValidator(ctx, valA)
|
||||
|
||||
@ -41,9 +41,3 @@ prefixed areas of the staking store which are accessed in `x/stake/keeper.go`.
|
||||
|
||||
The transient store persists between transations but not between blocks
|
||||
|
||||
## Tendermint Updates
|
||||
- Prefix Key Space: TendermintUpdatesTKey
|
||||
- Key/Sort: Validator Operator Address
|
||||
- Value: Tendermint ABCI Validator
|
||||
- Contains: Validators are queued to affect the consensus validation set in Tendermint
|
||||
- Used For: Informing Tendermint of the validator set updates
|
||||
|
||||
@ -265,18 +265,13 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Co
|
||||
}
|
||||
}
|
||||
|
||||
pool := k.GetPool(ctx)
|
||||
validator, pool, newShares = validator.AddTokensFromDel(pool, bondAmt.Amount)
|
||||
validator, newShares = k.AddValidatorTokensAndShares(ctx, validator, bondAmt.Amount)
|
||||
|
||||
// Update delegation
|
||||
delegation.Shares = delegation.Shares.Add(newShares)
|
||||
|
||||
// Update delegation height
|
||||
delegation.Height = ctx.BlockHeight()
|
||||
|
||||
k.SetPool(ctx, pool)
|
||||
k.SetDelegation(ctx, delegation)
|
||||
k.UpdateValidator(ctx, validator)
|
||||
|
||||
return
|
||||
return newShares, nil
|
||||
}
|
||||
|
||||
// unbond the the delegation return
|
||||
@ -313,8 +308,9 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
|
||||
|
||||
// if the delegation is the operator of the validator then
|
||||
// trigger a jail validator
|
||||
if bytes.Equal(delegation.DelegatorAddr, validator.OperatorAddr) && validator.Jailed == false {
|
||||
validator.Jailed = true
|
||||
if bytes.Equal(delegation.DelegatorAddr, validator.OperatorAddr) && !validator.Jailed {
|
||||
k.jailValidator(ctx, validator)
|
||||
validator = k.mustGetValidator(ctx, validator.OperatorAddr)
|
||||
}
|
||||
|
||||
k.RemoveDelegation(ctx, delegation)
|
||||
@ -325,14 +321,10 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
|
||||
}
|
||||
|
||||
// remove the coins from the validator
|
||||
pool := k.GetPool(ctx)
|
||||
validator, pool, amount = validator.RemoveDelShares(pool, shares)
|
||||
validator, amount = k.RemoveValidatorTokensAndShares(ctx, validator, shares)
|
||||
|
||||
k.SetPool(ctx, pool)
|
||||
|
||||
// update then remove validator if necessary
|
||||
validator = k.UpdateValidator(ctx, validator)
|
||||
if validator.DelegatorShares.IsZero() {
|
||||
if validator.DelegatorShares.IsZero() && validator.Status != sdk.Bonded {
|
||||
// if bonded, we must remove in EndBlocker instead
|
||||
k.RemoveValidator(ctx, validator.OperatorAddr)
|
||||
}
|
||||
|
||||
@ -368,7 +360,7 @@ func (k Keeper) getBeginInfo(ctx sdk.Context, params types.Params, valSrcAddr sd
|
||||
}
|
||||
}
|
||||
|
||||
// complete unbonding an unbonding record
|
||||
// begin unbonding an unbonding record
|
||||
func (k Keeper) BeginUnbonding(ctx sdk.Context,
|
||||
delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec) sdk.Error {
|
||||
|
||||
|
||||
@ -25,9 +25,9 @@ func TestDelegation(t *testing.T) {
|
||||
}
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
validators[2] = keeper.UpdateValidator(ctx, validators[2])
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[2] = testingUpdateValidator(keeper, ctx, validators[2])
|
||||
|
||||
// first add a validators[0] to delegate too
|
||||
|
||||
@ -184,7 +184,7 @@ func TestUnbondDelegation(t *testing.T) {
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
|
||||
pool = keeper.GetPool(ctx)
|
||||
require.Equal(t, int64(10), pool.BondedTokens.RoundInt64())
|
||||
@ -226,7 +226,7 @@ func TestUndelegateSelfDelegation(t *testing.T) {
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
selfDelegation := types.Delegation{
|
||||
DelegatorAddr: sdk.AccAddress(addrVals[0].Bytes()),
|
||||
@ -236,10 +236,11 @@ func TestUndelegateSelfDelegation(t *testing.T) {
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
||||
// create a second delegation to this validator
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validator, pool)
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
@ -252,6 +253,10 @@ func TestUndelegateSelfDelegation(t *testing.T) {
|
||||
err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
require.Equal(t, int64(10), validator.Tokens.RoundInt64())
|
||||
@ -269,7 +274,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) {
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
selfDelegation := types.Delegation{
|
||||
DelegatorAddr: sdk.AccAddress(addrVals[0].Bytes()),
|
||||
@ -279,10 +284,11 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) {
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
||||
// create a second delegation to this validator
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validator, pool)
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
@ -303,6 +309,10 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) {
|
||||
err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
require.Equal(t, blockHeight, validator.UnbondingHeight)
|
||||
@ -340,7 +350,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.Delegation{
|
||||
@ -351,10 +361,11 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
||||
// create a second delegation to this validator
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validator, pool)
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
@ -374,6 +385,10 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
|
||||
err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
require.Equal(t, blockHeight, validator.UnbondingHeight)
|
||||
@ -506,7 +521,7 @@ func TestRedelegateSelfDelegation(t *testing.T) {
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.Delegation{
|
||||
@ -520,14 +535,16 @@ func TestRedelegateSelfDelegation(t *testing.T) {
|
||||
validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{})
|
||||
validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(10))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator2 = keeper.UpdateValidator(ctx, validator2)
|
||||
validator2 = testingUpdateValidator(keeper, ctx, validator2)
|
||||
require.Equal(t, sdk.Bonded, validator2.Status)
|
||||
|
||||
// create a second delegation to this validator
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
@ -539,6 +556,10 @@ func TestRedelegateSelfDelegation(t *testing.T) {
|
||||
err := keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 2, len(updates))
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
require.Equal(t, int64(10), validator.Tokens.RoundInt64())
|
||||
@ -552,11 +573,12 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) {
|
||||
|
||||
//create a validator with a self-delegation
|
||||
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
|
||||
validator.BondIntraTxCounter = 1
|
||||
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.Delegation{
|
||||
@ -567,10 +589,11 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) {
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
||||
// create a second delegation to this validator
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validator, pool)
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
@ -581,10 +604,11 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) {
|
||||
|
||||
// create a second validator
|
||||
validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{})
|
||||
validator2.BondIntraTxCounter = 2
|
||||
validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator2 = keeper.UpdateValidator(ctx, validator2)
|
||||
validator2 = testingUpdateValidator(keeper, ctx, validator2)
|
||||
|
||||
header := ctx.BlockHeader()
|
||||
blockHeight := int64(10)
|
||||
@ -597,6 +621,10 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) {
|
||||
err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
require.Equal(t, blockHeight, validator.UnbondingHeight)
|
||||
@ -634,7 +662,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.Delegation{
|
||||
@ -645,10 +673,12 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
||||
// create a second delegation to this validator
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validator, pool)
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
validator.BondIntraTxCounter = 1
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
@ -659,10 +689,12 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
|
||||
|
||||
// create a second validator
|
||||
validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{})
|
||||
validator2.BondIntraTxCounter = 2
|
||||
validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator2 = keeper.UpdateValidator(ctx, validator2)
|
||||
validator2 = testingUpdateValidator(keeper, ctx, validator2)
|
||||
require.Equal(t, sdk.Bonded, validator2.Status)
|
||||
|
||||
header := ctx.BlockHeader()
|
||||
blockHeight := int64(10)
|
||||
@ -675,6 +707,10 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
|
||||
err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
require.Equal(t, blockHeight, validator.UnbondingHeight)
|
||||
|
||||
@ -64,25 +64,9 @@ func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
|
||||
return
|
||||
}
|
||||
|
||||
// Need a distinct function because setParams depends on an existing previous
|
||||
// record of params to exist (to check if maxValidators has changed) - and we
|
||||
// panic on retrieval if it doesn't exist - hence if we use setParams for the very
|
||||
// first params set it will panic.
|
||||
func (k Keeper) SetNewParams(ctx sdk.Context, params types.Params) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
b := k.cdc.MustMarshalBinary(params)
|
||||
store.Set(ParamKey, b)
|
||||
}
|
||||
|
||||
// set the params
|
||||
func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
exParams := k.GetParams(ctx)
|
||||
|
||||
// if max validator count changes, must recalculate validator set
|
||||
if exParams.MaxValidators != params.MaxValidators {
|
||||
k.UpdateBondedValidatorsFull(ctx)
|
||||
}
|
||||
b := k.cdc.MustMarshalBinary(params)
|
||||
store.Set(ParamKey, b)
|
||||
}
|
||||
|
||||
@ -18,18 +18,13 @@ var (
|
||||
ValidatorsByConsAddrKey = []byte{0x03} // prefix for each key to a validator index, by pubkey
|
||||
ValidatorsBondedIndexKey = []byte{0x04} // prefix for each key to a validator index, for bonded validators
|
||||
ValidatorsByPowerIndexKey = []byte{0x05} // prefix for each key to a validator index, sorted by power
|
||||
ValidatorCliffIndexKey = []byte{0x06} // key for the validator index of the cliff validator
|
||||
ValidatorPowerCliffKey = []byte{0x07} // key for the power of the validator on the cliff
|
||||
IntraTxCounterKey = []byte{0x08} // key for intra-block tx index
|
||||
DelegationKey = []byte{0x09} // key for a delegation
|
||||
UnbondingDelegationKey = []byte{0x0A} // key for an unbonding-delegation
|
||||
UnbondingDelegationByValIndexKey = []byte{0x0B} // prefix for each key for an unbonding-delegation, by validator operator
|
||||
RedelegationKey = []byte{0x0C} // key for a redelegation
|
||||
RedelegationByValSrcIndexKey = []byte{0x0D} // prefix for each key for an redelegation, by source validator operator
|
||||
RedelegationByValDstIndexKey = []byte{0x0E} // prefix for each key for an redelegation, by destination validator operator
|
||||
|
||||
// Keys for store prefixes (transient)
|
||||
TendermintUpdatesTKey = []byte{0x00} // prefix for each key to a validator which is being updated
|
||||
IntraTxCounterKey = []byte{0x06} // key for intra-block tx index
|
||||
DelegationKey = []byte{0x07} // key for a delegation
|
||||
UnbondingDelegationKey = []byte{0x08} // key for an unbonding-delegation
|
||||
UnbondingDelegationByValIndexKey = []byte{0x09} // prefix for each key for an unbonding-delegation, by validator operator
|
||||
RedelegationKey = []byte{0x0A} // key for a redelegation
|
||||
RedelegationByValSrcIndexKey = []byte{0x0B} // prefix for each key for an redelegation, by source validator operator
|
||||
RedelegationByValDstIndexKey = []byte{0x0C} // prefix for each key for an redelegation, by destination validator operator
|
||||
)
|
||||
|
||||
const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
|
||||
@ -46,12 +41,6 @@ func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte {
|
||||
return append(ValidatorsByConsAddrKey, addr.Bytes()...)
|
||||
}
|
||||
|
||||
// gets the key for the current validator group
|
||||
// VALUE: none (key rearrangement with GetValKeyFromValBondedIndexKey)
|
||||
func GetValidatorsBondedIndexKey(operatorAddr sdk.ValAddress) []byte {
|
||||
return append(ValidatorsBondedIndexKey, operatorAddr.Bytes()...)
|
||||
}
|
||||
|
||||
// Get the validator operator address from ValBondedIndexKey
|
||||
func GetAddressFromValBondedIndexKey(IndexKey []byte) []byte {
|
||||
return IndexKey[1:] // remove prefix bytes
|
||||
@ -66,6 +55,11 @@ func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []
|
||||
return getValidatorPowerRank(validator, pool)
|
||||
}
|
||||
|
||||
// get the bonded validator index key for an operator address
|
||||
func GetBondedValidatorIndexKey(operator sdk.ValAddress) []byte {
|
||||
return append(ValidatorsBondedIndexKey, operator...)
|
||||
}
|
||||
|
||||
// get the power ranking of a validator
|
||||
// NOTE the larger values are of higher value
|
||||
// nolint: unparam
|
||||
@ -74,34 +68,19 @@ func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte {
|
||||
potentialPower := validator.Tokens
|
||||
powerBytes := []byte(potentialPower.ToLeftPadded(maxDigitsForAccount)) // power big-endian (more powerful validators first)
|
||||
|
||||
jailedBytes := make([]byte, 1)
|
||||
if validator.Jailed {
|
||||
jailedBytes[0] = byte(0x00)
|
||||
} else {
|
||||
jailedBytes[0] = byte(0x01)
|
||||
}
|
||||
|
||||
// heightBytes and counterBytes represent strings like powerBytes does
|
||||
heightBytes := make([]byte, binary.MaxVarintLen64)
|
||||
binary.BigEndian.PutUint64(heightBytes, ^uint64(validator.BondHeight)) // invert height (older validators first)
|
||||
counterBytes := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(counterBytes, ^uint16(validator.BondIntraTxCounter)) // invert counter (first txns have priority)
|
||||
|
||||
return append(append(append(append(
|
||||
return append(append(append(
|
||||
ValidatorsByPowerIndexKey,
|
||||
jailedBytes...),
|
||||
powerBytes...),
|
||||
heightBytes...),
|
||||
counterBytes...)
|
||||
}
|
||||
|
||||
// get the key for the accumulated update validators
|
||||
// VALUE: abci.Validator
|
||||
// note records using these keys should never persist between blocks
|
||||
func GetTendermintUpdatesTKey(operatorAddr sdk.ValAddress) []byte {
|
||||
return append(TendermintUpdatesTKey, operatorAddr.Bytes()...)
|
||||
}
|
||||
|
||||
//______________________________________________________________________________
|
||||
|
||||
// gets the key for delegator bond with validator
|
||||
|
||||
@ -95,20 +95,18 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot decrease balance below zero
|
||||
// cannot decrease balance below zero
|
||||
tokensToBurn := sdk.MinDec(remainingSlashAmount, validator.Tokens)
|
||||
|
||||
// burn validator's tokens
|
||||
// burn validator's tokens and update the validator
|
||||
validator = k.RemoveValidatorTokens(ctx, validator, tokensToBurn)
|
||||
pool := k.GetPool(ctx)
|
||||
validator, pool = validator.RemoveTokens(pool, tokensToBurn)
|
||||
pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn)
|
||||
k.SetPool(ctx, pool)
|
||||
|
||||
// update the validator, possibly kicking it out
|
||||
validator = k.UpdateValidator(ctx, validator)
|
||||
|
||||
// remove validator if it has no more tokens
|
||||
if validator.Tokens.IsZero() {
|
||||
if validator.Tokens.IsZero() && validator.Status != sdk.Bonded {
|
||||
// if bonded, we must remove in ApplyAndReturnValidatorSetUpdates instead
|
||||
k.RemoveValidator(ctx, validator.OperatorAddr)
|
||||
}
|
||||
|
||||
@ -123,7 +121,8 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh
|
||||
|
||||
// jail a validator
|
||||
func (k Keeper) Jail(ctx sdk.Context, consAddr sdk.ConsAddress) {
|
||||
k.setJailed(ctx, consAddr, true)
|
||||
validator := k.mustGetValidatorByConsAddr(ctx, consAddr)
|
||||
k.jailValidator(ctx, validator)
|
||||
logger := ctx.Logger().With("module", "x/stake")
|
||||
logger.Info(fmt.Sprintf("validator %s jailed", consAddr))
|
||||
// TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803
|
||||
@ -132,24 +131,14 @@ func (k Keeper) Jail(ctx sdk.Context, consAddr sdk.ConsAddress) {
|
||||
|
||||
// unjail a validator
|
||||
func (k Keeper) Unjail(ctx sdk.Context, consAddr sdk.ConsAddress) {
|
||||
k.setJailed(ctx, consAddr, false)
|
||||
validator := k.mustGetValidatorByConsAddr(ctx, consAddr)
|
||||
k.unjailValidator(ctx, validator)
|
||||
logger := ctx.Logger().With("module", "x/stake")
|
||||
logger.Info(fmt.Sprintf("validator %s unjailed", consAddr))
|
||||
// TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803
|
||||
return
|
||||
}
|
||||
|
||||
// set the jailed flag on a validator
|
||||
func (k Keeper) setJailed(ctx sdk.Context, consAddr sdk.ConsAddress, isJailed bool) {
|
||||
validator, found := k.GetValidatorByConsAddr(ctx, consAddr)
|
||||
if !found {
|
||||
panic(fmt.Errorf("validator with consensus-Address %s not found, cannot set jailed to %v", consAddr, isJailed))
|
||||
}
|
||||
validator.Jailed = isJailed
|
||||
k.UpdateValidator(ctx, validator) // update validator, possibly unbonding or bonding it
|
||||
return
|
||||
}
|
||||
|
||||
// slash an unbonding delegation and update the pool
|
||||
// return the amount that would have been slashed assuming
|
||||
// the unbonding delegation had enough stake to slash
|
||||
|
||||
@ -26,8 +26,10 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) {
|
||||
for i := 0; i < numVals; i++ {
|
||||
validator := types.NewValidator(addrVals[i], PKs[i], types.Description{})
|
||||
validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
validator.BondIntraTxCounter = int16(i)
|
||||
pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(amt))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
keeper.SetValidatorByConsAddr(ctx, validator)
|
||||
}
|
||||
pool = keeper.GetPool(ctx)
|
||||
@ -161,6 +163,10 @@ func TestSlashRedelegation(t *testing.T) {
|
||||
rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
|
||||
require.True(t, found)
|
||||
|
||||
// end block
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
|
||||
// initialbalance unchanged
|
||||
require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 10), rd.InitialBalance)
|
||||
|
||||
@ -201,6 +207,11 @@ func TestSlashValidatorAtCurrentHeight(t *testing.T) {
|
||||
require.True(t, found)
|
||||
newPool := keeper.GetPool(ctx)
|
||||
|
||||
// end block
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates), "cons addr: %v, updates: %v", []byte(consAddr), updates)
|
||||
|
||||
validator = keeper.mustGetValidator(ctx, validator.OperatorAddr)
|
||||
// power decreased
|
||||
require.Equal(t, sdk.NewDec(5), validator.GetPower())
|
||||
// pool bonded shares decreased
|
||||
@ -232,6 +243,10 @@ func TestSlashWithUnbondingDelegation(t *testing.T) {
|
||||
require.True(t, found)
|
||||
keeper.Slash(ctx, consAddr, 10, 10, fraction)
|
||||
|
||||
// end block
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
|
||||
// read updating unbonding delegation
|
||||
ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0])
|
||||
require.True(t, found)
|
||||
@ -301,6 +316,8 @@ func TestSlashWithUnbondingDelegation(t *testing.T) {
|
||||
newPool = keeper.GetPool(ctx)
|
||||
// just 1 bonded token burned again since that's all the validator now has
|
||||
require.Equal(t, int64(10), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64())
|
||||
// apply TM updates
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
// read updated validator
|
||||
// power decreased by 1 again, validator is out of stake
|
||||
// ergo validator should have been removed from the store
|
||||
@ -402,6 +419,8 @@ func TestSlashWithRedelegation(t *testing.T) {
|
||||
newPool = keeper.GetPool(ctx)
|
||||
// four more bonded tokens burned
|
||||
require.Equal(t, int64(16), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64())
|
||||
// apply TM updates
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
// read updated validator
|
||||
// validator decreased to zero power, should have been removed from the store
|
||||
_, found = keeper.GetValidatorByConsAddr(ctx, consAddr)
|
||||
|
||||
@ -111,7 +111,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context
|
||||
ck := bank.NewBaseKeeper(accountMapper)
|
||||
keeper := NewKeeper(cdc, keyStake, tkeyStake, ck, types.DefaultCodespace)
|
||||
keeper.SetPool(ctx, types.InitialPool())
|
||||
keeper.SetNewParams(ctx, types.DefaultParams())
|
||||
keeper.SetParams(ctx, types.DefaultParams())
|
||||
keeper.InitIntraTxCounter(ctx)
|
||||
|
||||
// fill all the addresses with some coins, set the loose pool tokens simultaneously
|
||||
@ -202,5 +202,22 @@ func createTestPubKeys(numPubKeys int) []crypto.PubKey {
|
||||
// does a certain by-power index record exist
|
||||
func ValidatorByPowerIndexExists(ctx sdk.Context, keeper Keeper, power []byte) bool {
|
||||
store := ctx.KVStore(keeper.storeKey)
|
||||
return store.Get(power) != nil
|
||||
return store.Has(power)
|
||||
}
|
||||
|
||||
func testingUpdateValidator(keeper Keeper, ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
pool := keeper.GetPool(ctx)
|
||||
keeper.SetValidator(ctx, validator)
|
||||
keeper.SetValidatorByPowerIndex(ctx, validator, pool)
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
validator, found := keeper.GetValidator(ctx, validator.OperatorAddr)
|
||||
if !found {
|
||||
panic("validator expected but not found")
|
||||
}
|
||||
return validator
|
||||
}
|
||||
|
||||
func validatorByPowerIndexExists(k Keeper, ctx sdk.Context, power []byte) bool {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
return store.Has(power)
|
||||
}
|
||||
|
||||
268
x/stake/keeper/val_state_change.go
Normal file
268
x/stake/keeper/val_state_change.go
Normal file
@ -0,0 +1,268 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
// Apply and return accumulated updates to the bonded validator set
|
||||
//
|
||||
// CONTRACT: Only validators with non-zero power or zero-power that were bonded
|
||||
// at the previous block height or were removed from the validator set entirely
|
||||
// are returned to Tendermint.
|
||||
func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate) {
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
maxValidators := k.GetParams(ctx).MaxValidators
|
||||
|
||||
// retrieve last validator set
|
||||
last := k.retrieveLastValidatorSet(ctx)
|
||||
|
||||
// iterate over validators, highest power to lowest
|
||||
iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey)
|
||||
count := 0
|
||||
for ; iterator.Valid() && count < int(maxValidators); iterator.Next() {
|
||||
|
||||
// fetch the validator
|
||||
operator := sdk.ValAddress(iterator.Value())
|
||||
validator := k.mustGetValidator(ctx, operator)
|
||||
|
||||
if validator.Jailed {
|
||||
panic("should never retrieve a jailed validator from the power store")
|
||||
}
|
||||
|
||||
// if we get to a zero-power validator (which we don't bond),
|
||||
// there are no more possible bonded validators
|
||||
// note: we must check the ABCI power, since we round before sending to Tendermint
|
||||
if validator.Tokens.RoundInt64() == int64(0) {
|
||||
break
|
||||
}
|
||||
|
||||
// apply the appropriate state change if necessary
|
||||
switch validator.Status {
|
||||
case sdk.Unbonded:
|
||||
validator = k.unbondedToBonded(ctx, validator)
|
||||
case sdk.Unbonding:
|
||||
validator = k.unbondingToBonded(ctx, validator)
|
||||
case sdk.Bonded:
|
||||
// no state change
|
||||
default:
|
||||
panic("unexpected validator status")
|
||||
}
|
||||
|
||||
// fetch the old power bytes
|
||||
var operatorBytes [sdk.AddrLen]byte
|
||||
copy(operatorBytes[:], operator[:])
|
||||
oldPowerBytes, found := last[operatorBytes]
|
||||
|
||||
// calculate the new power bytes
|
||||
newPowerBytes := validator.ABCIValidatorPowerBytes(k.cdc)
|
||||
|
||||
// update the validator set if power has changed
|
||||
if !found || !bytes.Equal(oldPowerBytes, newPowerBytes) {
|
||||
updates = append(updates, validator.ABCIValidatorUpdate())
|
||||
}
|
||||
|
||||
// validator still in the validator set, so delete from the copy
|
||||
delete(last, operatorBytes)
|
||||
|
||||
// set the bonded validator index
|
||||
store.Set(GetBondedValidatorIndexKey(operator), newPowerBytes)
|
||||
|
||||
// keep count
|
||||
count++
|
||||
|
||||
}
|
||||
|
||||
// sort the no-longer-bonded validators
|
||||
noLongerBonded := k.sortNoLongerBonded(last)
|
||||
|
||||
// iterate through the sorted no-longer-bonded validators
|
||||
for _, operator := range noLongerBonded {
|
||||
|
||||
// fetch the validator
|
||||
validator := k.mustGetValidator(ctx, sdk.ValAddress(operator))
|
||||
|
||||
// bonded to unbonding
|
||||
k.bondedToUnbonding(ctx, validator)
|
||||
|
||||
// remove validator if it has no more tokens
|
||||
if validator.Tokens.IsZero() {
|
||||
k.RemoveValidator(ctx, validator.OperatorAddr)
|
||||
}
|
||||
|
||||
// delete from the bonded validator index
|
||||
store.Delete(GetBondedValidatorIndexKey(operator))
|
||||
|
||||
// update the validator set
|
||||
updates = append(updates, validator.ABCIValidatorUpdateZero())
|
||||
|
||||
}
|
||||
|
||||
return updates
|
||||
}
|
||||
|
||||
// Validator state transitions
|
||||
|
||||
func (k Keeper) bondedToUnbonding(ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
if validator.Status != sdk.Bonded {
|
||||
panic(fmt.Sprintf("bad state transition bondedToUnbonding, validator: %v\n", validator))
|
||||
}
|
||||
return k.beginUnbondingValidator(ctx, validator)
|
||||
}
|
||||
|
||||
func (k Keeper) unbondingToBonded(ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
if validator.Status != sdk.Unbonding {
|
||||
panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator))
|
||||
}
|
||||
return k.bondValidator(ctx, validator)
|
||||
}
|
||||
|
||||
func (k Keeper) unbondedToBonded(ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
if validator.Status != sdk.Unbonded {
|
||||
panic(fmt.Sprintf("bad state transition unbondedToBonded, validator: %v\n", validator))
|
||||
}
|
||||
return k.bondValidator(ctx, validator)
|
||||
}
|
||||
|
||||
func (k Keeper) unbondingToUnbonded(ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
if validator.Status != sdk.Unbonded {
|
||||
panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator))
|
||||
}
|
||||
return k.completeUnbondingValidator(ctx, validator)
|
||||
}
|
||||
|
||||
// send a validator to jail
|
||||
func (k Keeper) jailValidator(ctx sdk.Context, validator types.Validator) {
|
||||
if validator.Jailed {
|
||||
panic(fmt.Sprintf("cannot jail already jailed validator, validator: %v\n", validator))
|
||||
}
|
||||
|
||||
pool := k.GetPool(ctx)
|
||||
validator.Jailed = true
|
||||
k.SetValidator(ctx, validator)
|
||||
k.DeleteValidatorByPowerIndex(ctx, validator, pool)
|
||||
}
|
||||
|
||||
// remove a validator from jail
|
||||
func (k Keeper) unjailValidator(ctx sdk.Context, validator types.Validator) {
|
||||
if !validator.Jailed {
|
||||
panic(fmt.Sprintf("cannot unjail already unjailed validator, validator: %v\n", validator))
|
||||
}
|
||||
|
||||
pool := k.GetPool(ctx)
|
||||
validator.Jailed = false
|
||||
k.SetValidator(ctx, validator)
|
||||
k.SetValidatorByPowerIndex(ctx, validator, pool)
|
||||
}
|
||||
|
||||
// perform all the store operations for when a validator status becomes bonded
|
||||
func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
|
||||
pool := k.GetPool(ctx)
|
||||
|
||||
k.DeleteValidatorByPowerIndex(ctx, validator, pool)
|
||||
|
||||
validator.BondHeight = ctx.BlockHeight()
|
||||
|
||||
// set the status
|
||||
validator, pool = validator.UpdateStatus(pool, sdk.Bonded)
|
||||
k.SetPool(ctx, pool)
|
||||
|
||||
// save the now bonded validator record to the three referenced stores
|
||||
k.SetValidator(ctx, validator)
|
||||
|
||||
k.SetValidatorByPowerIndex(ctx, validator, pool)
|
||||
|
||||
// call the bond hook if present
|
||||
if k.hooks != nil {
|
||||
k.hooks.OnValidatorBonded(ctx, validator.ConsAddress())
|
||||
}
|
||||
|
||||
return validator
|
||||
}
|
||||
|
||||
// perform all the store operations for when a validator status begins unbonding
|
||||
func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
|
||||
pool := k.GetPool(ctx)
|
||||
params := k.GetParams(ctx)
|
||||
|
||||
k.DeleteValidatorByPowerIndex(ctx, validator, pool)
|
||||
|
||||
// sanity check
|
||||
if validator.Status != sdk.Bonded {
|
||||
panic(fmt.Sprintf("should not already be unbonded or unbonding, validator: %v\n", validator))
|
||||
}
|
||||
|
||||
// set the status
|
||||
validator, pool = validator.UpdateStatus(pool, sdk.Unbonding)
|
||||
k.SetPool(ctx, pool)
|
||||
|
||||
validator.UnbondingMinTime = ctx.BlockHeader().Time.Add(params.UnbondingTime)
|
||||
validator.UnbondingHeight = ctx.BlockHeader().Height
|
||||
|
||||
// save the now unbonded validator record
|
||||
k.SetValidator(ctx, validator)
|
||||
|
||||
k.SetValidatorByPowerIndex(ctx, validator, pool)
|
||||
|
||||
// call the unbond hook if present
|
||||
if k.hooks != nil {
|
||||
k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress())
|
||||
}
|
||||
|
||||
return validator
|
||||
}
|
||||
|
||||
// perform all the store operations for when a validator status becomes unbonded
|
||||
func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
pool := k.GetPool(ctx)
|
||||
validator, pool = validator.UpdateStatus(pool, sdk.Unbonded)
|
||||
k.SetPool(ctx, pool)
|
||||
k.SetValidator(ctx, validator)
|
||||
return validator
|
||||
}
|
||||
|
||||
// map of operator addresses to serialized power
|
||||
type validatorsByAddr map[[sdk.AddrLen]byte][]byte
|
||||
|
||||
// retrieve the last validator set
|
||||
func (k Keeper) retrieveLastValidatorSet(ctx sdk.Context) validatorsByAddr {
|
||||
last := make(validatorsByAddr)
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
var operator [sdk.AddrLen]byte
|
||||
copy(operator[:], iterator.Key()[1:])
|
||||
powerBytes := iterator.Value()
|
||||
last[operator] = make([]byte, len(powerBytes))
|
||||
copy(last[operator][:], powerBytes[:])
|
||||
}
|
||||
return last
|
||||
}
|
||||
|
||||
// given a map of remaining validators to previous bonded power
|
||||
// returns the list of validators to be unbonded, sorted by operator address
|
||||
func (k Keeper) sortNoLongerBonded(last validatorsByAddr) [][]byte {
|
||||
// sort the map keys for determinism
|
||||
noLongerBonded := make([][]byte, len(last))
|
||||
index := 0
|
||||
for operatorBytes := range last {
|
||||
operator := make([]byte, sdk.AddrLen)
|
||||
copy(operator[:], operatorBytes[:])
|
||||
noLongerBonded[index] = operator
|
||||
index++
|
||||
}
|
||||
// sorted by address - order doesn't matter
|
||||
sort.SliceStable(noLongerBonded, func(i, j int) bool {
|
||||
return bytes.Compare(noLongerBonded[i], noLongerBonded[j]) == -1
|
||||
})
|
||||
return noLongerBonded
|
||||
}
|
||||
@ -1,13 +1,9 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"container/list"
|
||||
"fmt"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
@ -58,6 +54,14 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator ty
|
||||
return validator, true
|
||||
}
|
||||
|
||||
func (k Keeper) mustGetValidator(ctx sdk.Context, addr sdk.ValAddress) types.Validator {
|
||||
validator, found := k.GetValidator(ctx, addr)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("validator record not found for address: %X\n", addr))
|
||||
}
|
||||
return validator
|
||||
}
|
||||
|
||||
// get a single validator by consensus address
|
||||
func (k Keeper) GetValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) (validator types.Validator, found bool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
@ -68,6 +72,16 @@ func (k Keeper) GetValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress
|
||||
return k.GetValidator(ctx, opAddr)
|
||||
}
|
||||
|
||||
func (k Keeper) mustGetValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) types.Validator {
|
||||
validator, found := k.GetValidatorByConsAddr(ctx, consAddr)
|
||||
if !found {
|
||||
panic(fmt.Errorf("validator with consensus-Address %s not found", consAddr))
|
||||
}
|
||||
return validator
|
||||
}
|
||||
|
||||
//___________________________________________________________________________
|
||||
|
||||
// set the main record holding validator details
|
||||
func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
@ -84,23 +98,110 @@ func (k Keeper) SetValidatorByConsAddr(ctx sdk.Context, validator types.Validato
|
||||
|
||||
// validator index
|
||||
func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Validator, pool types.Pool) {
|
||||
// jailed validators are not kept in the power index
|
||||
if validator.Jailed {
|
||||
return
|
||||
}
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
store.Set(GetValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr)
|
||||
}
|
||||
|
||||
// validator index
|
||||
func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validator) {
|
||||
func (k Keeper) DeleteValidatorByPowerIndex(ctx sdk.Context, validator types.Validator, pool types.Pool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
store.Set(GetValidatorsBondedIndexKey(validator.OperatorAddr), []byte{})
|
||||
store.Delete(GetValidatorsByPowerIndexKey(validator, pool))
|
||||
}
|
||||
|
||||
// used in testing
|
||||
func (k Keeper) validatorByPowerIndexExists(ctx sdk.Context, power []byte) bool {
|
||||
// validator index
|
||||
func (k Keeper) SetNewValidatorByPowerIndex(ctx sdk.Context, validator types.Validator) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
return store.Get(power) != nil
|
||||
pool := k.GetPool(ctx)
|
||||
store.Set(GetValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr)
|
||||
}
|
||||
|
||||
// Get the set of all validators with no limits, used during genesis dump
|
||||
//___________________________________________________________________________
|
||||
|
||||
// Update the tokens of an existing validator, update the validators power index key
|
||||
func (k Keeper) AddValidatorTokensAndShares(ctx sdk.Context, validator types.Validator,
|
||||
tokensToAdd sdk.Int) (valOut types.Validator, addedShares sdk.Dec) {
|
||||
|
||||
pool := k.GetPool(ctx)
|
||||
k.DeleteValidatorByPowerIndex(ctx, validator, pool)
|
||||
validator, pool, addedShares = validator.AddTokensFromDel(pool, tokensToAdd)
|
||||
// increment the intra-tx counter
|
||||
// in case of a conflict, the validator which least recently changed power takes precedence
|
||||
counter := k.GetIntraTxCounter(ctx)
|
||||
validator.BondIntraTxCounter = counter
|
||||
k.SetIntraTxCounter(ctx, counter+1)
|
||||
k.SetValidator(ctx, validator)
|
||||
k.SetPool(ctx, pool)
|
||||
k.SetValidatorByPowerIndex(ctx, validator, pool)
|
||||
return validator, addedShares
|
||||
}
|
||||
|
||||
// Update the tokens of an existing validator, update the validators power index key
|
||||
func (k Keeper) RemoveValidatorTokensAndShares(ctx sdk.Context, validator types.Validator,
|
||||
sharesToRemove sdk.Dec) (valOut types.Validator, removedTokens sdk.Dec) {
|
||||
|
||||
pool := k.GetPool(ctx)
|
||||
k.DeleteValidatorByPowerIndex(ctx, validator, pool)
|
||||
validator, pool, removedTokens = validator.RemoveDelShares(pool, sharesToRemove)
|
||||
k.SetValidator(ctx, validator)
|
||||
k.SetPool(ctx, pool)
|
||||
k.SetValidatorByPowerIndex(ctx, validator, pool)
|
||||
return validator, removedTokens
|
||||
}
|
||||
|
||||
// Update the tokens of an existing validator, update the validators power index key
|
||||
func (k Keeper) RemoveValidatorTokens(ctx sdk.Context, validator types.Validator, tokensToRemove sdk.Dec) types.Validator {
|
||||
pool := k.GetPool(ctx)
|
||||
k.DeleteValidatorByPowerIndex(ctx, validator, pool)
|
||||
validator, pool = validator.RemoveTokens(pool, tokensToRemove)
|
||||
k.SetValidator(ctx, validator)
|
||||
k.SetPool(ctx, pool)
|
||||
k.SetValidatorByPowerIndex(ctx, validator, pool)
|
||||
return validator
|
||||
}
|
||||
|
||||
// UpdateValidatorCommission attempts to update a validator's commission rate.
|
||||
// An error is returned if the new commission rate is invalid.
|
||||
func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, validator types.Validator, newRate sdk.Dec) (types.Commission, sdk.Error) {
|
||||
commission := validator.Commission
|
||||
blockTime := ctx.BlockHeader().Time
|
||||
|
||||
if err := commission.ValidateNewRate(newRate, blockTime); err != nil {
|
||||
return commission, err
|
||||
}
|
||||
|
||||
commission.Rate = newRate
|
||||
commission.UpdateTime = blockTime
|
||||
|
||||
return commission, nil
|
||||
}
|
||||
|
||||
// remove the validator record and associated indexes
|
||||
// except for the bonded validator index which is only handled in ApplyAndReturnTendermintUpdates
|
||||
func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) {
|
||||
|
||||
// first retrieve the old validator record
|
||||
validator, found := k.GetValidator(ctx, address)
|
||||
if !found {
|
||||
return
|
||||
}
|
||||
|
||||
// delete the old validator record
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
pool := k.GetPool(ctx)
|
||||
store.Delete(GetValidatorKey(address))
|
||||
store.Delete(GetValidatorByConsAddrKey(sdk.ConsAddress(validator.ConsPubKey.Address())))
|
||||
store.Delete(GetValidatorsByPowerIndexKey(validator, pool))
|
||||
|
||||
}
|
||||
|
||||
//___________________________________________________________________________
|
||||
// get groups of validators
|
||||
|
||||
// get the set of all validators with no limits, used during genesis dump
|
||||
func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []types.Validator) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, ValidatorsKey)
|
||||
@ -132,8 +233,6 @@ func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve uint16) (validators [
|
||||
return validators[:i] // trim if the array length < maxRetrieve
|
||||
}
|
||||
|
||||
//___________________________________________________________________________
|
||||
|
||||
// get the group of the bonded validators
|
||||
func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validator) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
@ -153,8 +252,7 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat
|
||||
panic("maxValidators is less than the number of records in ValidatorsBonded Store, store should have been updated")
|
||||
}
|
||||
address := GetAddressFromValBondedIndexKey(iterator.Key())
|
||||
validator, found := k.GetValidator(ctx, address)
|
||||
ensureValidatorFound(found, address)
|
||||
validator := k.mustGetValidator(ctx, address)
|
||||
|
||||
validators[i] = validator
|
||||
i++
|
||||
@ -163,9 +261,7 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat
|
||||
}
|
||||
|
||||
// get the group of bonded validators sorted by power-rank
|
||||
//
|
||||
// TODO: Rename to GetBondedValidatorsByPower or GetValidatorsByPower(ctx, status)
|
||||
func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator {
|
||||
func (k Keeper) GetBondedValidatorsByPower(ctx sdk.Context) []types.Validator {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
maxValidators := k.GetParams(ctx).MaxValidators
|
||||
validators := make([]types.Validator, maxValidators)
|
||||
@ -176,8 +272,7 @@ func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator {
|
||||
i := 0
|
||||
for ; iterator.Valid() && i < int(maxValidators); iterator.Next() {
|
||||
address := iterator.Value()
|
||||
validator, found := k.GetValidator(ctx, address)
|
||||
ensureValidatorFound(found, address)
|
||||
validator := k.mustGetValidator(ctx, address)
|
||||
|
||||
if validator.Status == sdk.Bonded {
|
||||
validators[i] = validator
|
||||
@ -186,554 +281,3 @@ func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator {
|
||||
}
|
||||
return validators[:i] // trim
|
||||
}
|
||||
|
||||
//_________________________________________________________________________
|
||||
// Accumulated updates to the active/bonded validator set for tendermint
|
||||
|
||||
// get the most recently updated validators
|
||||
//
|
||||
// CONTRACT: Only validators with non-zero power or zero-power that were bonded
|
||||
// at the previous block height or were removed from the validator set entirely
|
||||
// are returned to Tendermint.
|
||||
func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate) {
|
||||
tstore := ctx.TransientStore(k.storeTKey)
|
||||
|
||||
iterator := sdk.KVStorePrefixIterator(tstore, TendermintUpdatesTKey)
|
||||
defer iterator.Close()
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
var abciVal abci.ValidatorUpdate
|
||||
|
||||
abciValBytes := iterator.Value()
|
||||
k.cdc.MustUnmarshalBinary(abciValBytes, &abciVal)
|
||||
|
||||
pub, err := tmtypes.PB2TM.PubKey(abciVal.GetPubKey())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
val, found := k.GetValidator(ctx, sdk.ValAddress(pub.Address()))
|
||||
if found {
|
||||
// The validator is new or already exists in the store and must adhere to
|
||||
// Tendermint invariants.
|
||||
prevBonded := val.BondHeight < ctx.BlockHeight() && val.BondHeight > val.UnbondingHeight
|
||||
zeroPower := val.GetPower().Equal(sdk.ZeroDec())
|
||||
|
||||
if !zeroPower || zeroPower && prevBonded {
|
||||
updates = append(updates, abciVal)
|
||||
}
|
||||
} else {
|
||||
// Add the ABCI validator in such a case where the validator was removed
|
||||
// from the store as it must have existed before.
|
||||
updates = append(updates, abciVal)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//___________________________________________________________________________
|
||||
|
||||
// Perform all the necessary steps for when a validator changes its power. This
|
||||
// function updates all validator stores as well as tendermint update store.
|
||||
// It may kick out validators if a new validator is entering the bonded validator
|
||||
// group.
|
||||
//
|
||||
// TODO: Remove above nolint, function needs to be simplified!
|
||||
func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
tstore := ctx.TransientStore(k.storeTKey)
|
||||
pool := k.GetPool(ctx)
|
||||
oldValidator, oldFound := k.GetValidator(ctx, validator.OperatorAddr)
|
||||
|
||||
validator = k.updateForJailing(ctx, oldFound, oldValidator, validator)
|
||||
powerIncreasing := k.getPowerIncreasing(ctx, oldFound, oldValidator, validator)
|
||||
validator.BondHeight, validator.BondIntraTxCounter = k.bondIncrement(ctx, oldFound, oldValidator)
|
||||
valPower := k.updateValidatorPower(ctx, oldFound, oldValidator, validator, pool)
|
||||
cliffPower := k.GetCliffValidatorPower(ctx)
|
||||
cliffValExists := (cliffPower != nil)
|
||||
var valPowerLTcliffPower bool
|
||||
if cliffValExists {
|
||||
valPowerLTcliffPower = (bytes.Compare(valPower, cliffPower) == -1)
|
||||
}
|
||||
|
||||
switch {
|
||||
|
||||
// if the validator is already bonded and the power is increasing, we need
|
||||
// perform the following:
|
||||
// a) update Tendermint
|
||||
// b) check if the cliff validator needs to be updated
|
||||
case powerIncreasing && !validator.Jailed &&
|
||||
(oldFound && oldValidator.Status == sdk.Bonded):
|
||||
|
||||
bz := k.cdc.MustMarshalBinary(validator.ABCIValidatorUpdate())
|
||||
tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bz)
|
||||
|
||||
if cliffValExists {
|
||||
cliffAddr := sdk.ValAddress(k.GetCliffValidator(ctx))
|
||||
if bytes.Equal(cliffAddr, validator.OperatorAddr) {
|
||||
k.updateCliffValidator(ctx, validator)
|
||||
}
|
||||
}
|
||||
|
||||
// if is a new validator and the new power is less than the cliff validator
|
||||
case cliffValExists && !oldFound && valPowerLTcliffPower:
|
||||
// skip to completion
|
||||
|
||||
// if was unbonded and the new power is less than the cliff validator
|
||||
case cliffValExists &&
|
||||
(oldFound && oldValidator.Status == sdk.Unbonded) &&
|
||||
valPowerLTcliffPower: //(valPower < cliffPower
|
||||
// skip to completion
|
||||
|
||||
default:
|
||||
// default case - validator was either:
|
||||
// a) not-bonded and now has power-rank greater than cliff validator
|
||||
// b) bonded and now has decreased in power
|
||||
|
||||
// update the validator set for this validator
|
||||
updatedVal, updated := k.UpdateBondedValidators(ctx, validator)
|
||||
if updated {
|
||||
// the validator has changed bonding status
|
||||
validator = updatedVal
|
||||
break
|
||||
}
|
||||
|
||||
// if decreased in power but still bonded, update Tendermint validator
|
||||
if oldFound && oldValidator.BondedTokens().GT(validator.BondedTokens()) {
|
||||
bz := k.cdc.MustMarshalBinary(validator.ABCIValidatorUpdate())
|
||||
tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bz)
|
||||
}
|
||||
}
|
||||
|
||||
k.SetValidator(ctx, validator)
|
||||
return validator
|
||||
}
|
||||
|
||||
// updateCliffValidator determines if the current cliff validator needs to be
|
||||
// updated or swapped. If the provided affected validator is the current cliff
|
||||
// validator before it's power was increased, either the cliff power key will
|
||||
// be updated or if it's power is greater than the next bonded validator by
|
||||
// power, it'll be swapped.
|
||||
func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validator) {
|
||||
var newCliffVal types.Validator
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
pool := k.GetPool(ctx)
|
||||
cliffAddr := sdk.ValAddress(k.GetCliffValidator(ctx))
|
||||
|
||||
oldCliffVal, found := k.GetValidator(ctx, cliffAddr)
|
||||
if !found {
|
||||
panic(fmt.Sprintf("cliff validator record not found for address: %X\n", cliffAddr))
|
||||
}
|
||||
|
||||
// Create a validator iterator ranging from smallest to largest by power
|
||||
// starting the current cliff validator's power.
|
||||
start := GetValidatorsByPowerIndexKey(oldCliffVal, pool)
|
||||
end := sdk.PrefixEndBytes(ValidatorsByPowerIndexKey)
|
||||
iterator := store.Iterator(start, end)
|
||||
|
||||
if iterator.Valid() {
|
||||
ownerAddr := iterator.Value()
|
||||
currVal, found := k.GetValidator(ctx, ownerAddr)
|
||||
ensureValidatorFound(found, ownerAddr)
|
||||
|
||||
if currVal.Status != sdk.Bonded || currVal.Jailed {
|
||||
panic(fmt.Sprintf("unexpected jailed or unbonded validator for address: %X\n", ownerAddr))
|
||||
}
|
||||
|
||||
newCliffVal = currVal
|
||||
iterator.Close()
|
||||
} else {
|
||||
panic("failed to create valid validator power iterator")
|
||||
}
|
||||
|
||||
affectedValRank := GetValidatorsByPowerIndexKey(affectedVal, pool)
|
||||
newCliffValRank := GetValidatorsByPowerIndexKey(newCliffVal, pool)
|
||||
|
||||
if bytes.Equal(affectedVal.OperatorAddr, newCliffVal.OperatorAddr) {
|
||||
// The affected validator remains the cliff validator, however, since
|
||||
// the store does not contain the new power, update the new power rank.
|
||||
store.Set(ValidatorPowerCliffKey, affectedValRank)
|
||||
} else if bytes.Compare(affectedValRank, newCliffValRank) > 0 {
|
||||
// The affected validator no longer remains the cliff validator as it's
|
||||
// power is greater than the new cliff validator.
|
||||
k.setCliffValidator(ctx, newCliffVal, pool)
|
||||
} else {
|
||||
panic("invariant broken: the cliff validator should change or it should remain the same")
|
||||
}
|
||||
}
|
||||
|
||||
func (k Keeper) updateForJailing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) types.Validator {
|
||||
if newValidator.Jailed && oldFound && oldValidator.Status == sdk.Bonded {
|
||||
newValidator = k.beginUnbondingValidator(ctx, newValidator)
|
||||
|
||||
// need to also clear the cliff validator spot because the jail has
|
||||
// opened up a new spot which will be filled when
|
||||
// updateValidatorsBonded is called
|
||||
k.clearCliffValidator(ctx)
|
||||
}
|
||||
return newValidator
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
func (k Keeper) getPowerIncreasing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) bool {
|
||||
if oldFound && oldValidator.BondedTokens().LT(newValidator.BondedTokens()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// get the bond height and incremented intra-tx counter
|
||||
// nolint: unparam
|
||||
func (k Keeper) bondIncrement(
|
||||
ctx sdk.Context, found bool, oldValidator types.Validator) (height int64, intraTxCounter int16) {
|
||||
|
||||
// if already a validator, copy the old block height and counter
|
||||
if found && oldValidator.Status == sdk.Bonded {
|
||||
height = oldValidator.BondHeight
|
||||
intraTxCounter = oldValidator.BondIntraTxCounter
|
||||
return
|
||||
}
|
||||
|
||||
height = ctx.BlockHeight()
|
||||
counter := k.GetIntraTxCounter(ctx)
|
||||
intraTxCounter = counter
|
||||
|
||||
k.SetIntraTxCounter(ctx, counter+1)
|
||||
return
|
||||
}
|
||||
|
||||
func (k Keeper) updateValidatorPower(ctx sdk.Context, oldFound bool, oldValidator,
|
||||
newValidator types.Validator, pool types.Pool) (valPower []byte) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
||||
// update the list ordered by voting power
|
||||
if oldFound {
|
||||
store.Delete(GetValidatorsByPowerIndexKey(oldValidator, pool))
|
||||
}
|
||||
valPower = GetValidatorsByPowerIndexKey(newValidator, pool)
|
||||
store.Set(valPower, newValidator.OperatorAddr)
|
||||
|
||||
return valPower
|
||||
}
|
||||
|
||||
// Update the bonded validator group based on a change to the validator
|
||||
// affectedValidator. This function potentially adds the affectedValidator to
|
||||
// the bonded validator group which kicks out the cliff validator. Under this
|
||||
// situation this function returns the updated affectedValidator.
|
||||
//
|
||||
// The correct bonded subset of validators is retrieved by iterating through an
|
||||
// index of the validators sorted by power, stored using the
|
||||
// ValidatorsByPowerIndexKey. Simultaneously the current validator records are
|
||||
// updated in store with the ValidatorsBondedIndexKey. This store is used to
|
||||
// determine if a validator is a validator without needing to iterate over all
|
||||
// validators.
|
||||
func (k Keeper) UpdateBondedValidators(
|
||||
ctx sdk.Context, affectedValidator types.Validator) (
|
||||
updatedVal types.Validator, updated bool) {
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
||||
oldCliffValidatorAddr := k.GetCliffValidator(ctx)
|
||||
maxValidators := k.GetParams(ctx).MaxValidators
|
||||
bondedValidatorsCount := 0
|
||||
var validator, validatorToBond types.Validator
|
||||
newValidatorBonded := false
|
||||
|
||||
// create a validator iterator ranging from largest to smallest by power
|
||||
iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey)
|
||||
for ; iterator.Valid() && bondedValidatorsCount < int(maxValidators); iterator.Next() {
|
||||
|
||||
// either retrieve the original validator from the store, or under the
|
||||
// situation that this is the "affected validator" just use the
|
||||
// validator provided because it has not yet been updated in the store
|
||||
ownerAddr := iterator.Value()
|
||||
if bytes.Equal(ownerAddr, affectedValidator.OperatorAddr) {
|
||||
validator = affectedValidator
|
||||
} else {
|
||||
var found bool
|
||||
validator, found = k.GetValidator(ctx, ownerAddr)
|
||||
ensureValidatorFound(found, ownerAddr)
|
||||
}
|
||||
|
||||
// if we've reached jailed validators no further bonded validators exist
|
||||
if validator.Jailed {
|
||||
if validator.Status == sdk.Bonded {
|
||||
panic(fmt.Sprintf("jailed validator cannot be bonded, address: %X\n", ownerAddr))
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
// increment the total number of bonded validators and potentially mark
|
||||
// the validator to bond
|
||||
if validator.Status != sdk.Bonded {
|
||||
validatorToBond = validator
|
||||
if newValidatorBonded {
|
||||
panic("already decided to bond a validator, can't bond another!")
|
||||
}
|
||||
newValidatorBonded = true
|
||||
}
|
||||
|
||||
bondedValidatorsCount++
|
||||
}
|
||||
|
||||
iterator.Close()
|
||||
|
||||
if newValidatorBonded && bytes.Equal(oldCliffValidatorAddr, validator.OperatorAddr) {
|
||||
panic("cliff validator has not been changed, yet we bonded a new validator")
|
||||
}
|
||||
|
||||
// clear or set the cliff validator
|
||||
if bondedValidatorsCount == int(maxValidators) {
|
||||
k.setCliffValidator(ctx, validator, k.GetPool(ctx))
|
||||
} else if len(oldCliffValidatorAddr) > 0 {
|
||||
k.clearCliffValidator(ctx)
|
||||
}
|
||||
|
||||
// swap the cliff validator for a new validator if the affected validator
|
||||
// was bonded
|
||||
if newValidatorBonded {
|
||||
if oldCliffValidatorAddr != nil {
|
||||
oldCliffVal, found := k.GetValidator(ctx, oldCliffValidatorAddr)
|
||||
ensureValidatorFound(found, oldCliffValidatorAddr)
|
||||
|
||||
if bytes.Equal(validatorToBond.OperatorAddr, affectedValidator.OperatorAddr) {
|
||||
|
||||
// begin unbonding the old cliff validator iff the affected
|
||||
// validator was newly bonded and has greater power
|
||||
k.beginUnbondingValidator(ctx, oldCliffVal)
|
||||
} else {
|
||||
// otherwise begin unbonding the affected validator, which must
|
||||
// have been kicked out
|
||||
affectedValidator = k.beginUnbondingValidator(ctx, affectedValidator)
|
||||
}
|
||||
}
|
||||
|
||||
validator = k.bondValidator(ctx, validatorToBond)
|
||||
if bytes.Equal(validator.OperatorAddr, affectedValidator.OperatorAddr) {
|
||||
return validator, true
|
||||
}
|
||||
|
||||
return affectedValidator, true
|
||||
}
|
||||
|
||||
return types.Validator{}, false
|
||||
}
|
||||
|
||||
// full update of the bonded validator set, many can be added/kicked
|
||||
func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
||||
// clear the current validators store, add to the ToKickOut temp store
|
||||
toKickOut := make(map[string]byte)
|
||||
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
ownerAddr := GetAddressFromValBondedIndexKey(iterator.Key())
|
||||
toKickOut[string(ownerAddr)] = 0
|
||||
}
|
||||
|
||||
iterator.Close()
|
||||
|
||||
var validator types.Validator
|
||||
|
||||
oldCliffValidatorAddr := k.GetCliffValidator(ctx)
|
||||
maxValidators := k.GetParams(ctx).MaxValidators
|
||||
bondedValidatorsCount := 0
|
||||
|
||||
iterator = sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey)
|
||||
for ; iterator.Valid() && bondedValidatorsCount < int(maxValidators); iterator.Next() {
|
||||
var found bool
|
||||
|
||||
ownerAddr := iterator.Value()
|
||||
validator, found = k.GetValidator(ctx, ownerAddr)
|
||||
ensureValidatorFound(found, ownerAddr)
|
||||
|
||||
_, found = toKickOut[string(ownerAddr)]
|
||||
if found {
|
||||
delete(toKickOut, string(ownerAddr))
|
||||
} else {
|
||||
// If the validator wasn't in the toKickOut group it means it wasn't
|
||||
// previously a validator, therefor update the validator to enter
|
||||
// the validator group.
|
||||
validator = k.bondValidator(ctx, validator)
|
||||
}
|
||||
|
||||
if validator.Jailed {
|
||||
// we should no longer consider jailed validators as they are ranked
|
||||
// lower than any non-jailed/bonded validators
|
||||
if validator.Status == sdk.Bonded {
|
||||
panic(fmt.Sprintf("jailed validator cannot be bonded for address: %s\n", ownerAddr))
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
bondedValidatorsCount++
|
||||
}
|
||||
|
||||
iterator.Close()
|
||||
|
||||
// clear or set the cliff validator
|
||||
if bondedValidatorsCount == int(maxValidators) {
|
||||
k.setCliffValidator(ctx, validator, k.GetPool(ctx))
|
||||
} else if len(oldCliffValidatorAddr) > 0 {
|
||||
k.clearCliffValidator(ctx)
|
||||
}
|
||||
|
||||
kickOutValidators(k, ctx, toKickOut)
|
||||
return
|
||||
}
|
||||
|
||||
func kickOutValidators(k Keeper, ctx sdk.Context, toKickOut map[string]byte) {
|
||||
for key := range toKickOut {
|
||||
ownerAddr := []byte(key)
|
||||
validator, found := k.GetValidator(ctx, ownerAddr)
|
||||
ensureValidatorFound(found, ownerAddr)
|
||||
k.beginUnbondingValidator(ctx, validator)
|
||||
}
|
||||
}
|
||||
|
||||
// perform all the store operations for when a validator status becomes unbonded
|
||||
func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
pool := k.GetPool(ctx)
|
||||
params := k.GetParams(ctx)
|
||||
|
||||
// sanity check
|
||||
if validator.Status == sdk.Unbonded ||
|
||||
validator.Status == sdk.Unbonding {
|
||||
panic(fmt.Sprintf("should not already be unbonded or unbonding, validator: %v\n", validator))
|
||||
}
|
||||
|
||||
// set the status
|
||||
validator, pool = validator.UpdateStatus(pool, sdk.Unbonding)
|
||||
k.SetPool(ctx, pool)
|
||||
|
||||
validator.UnbondingMinTime = ctx.BlockHeader().Time.Add(params.UnbondingTime)
|
||||
validator.UnbondingHeight = ctx.BlockHeader().Height
|
||||
|
||||
// save the now unbonded validator record
|
||||
k.SetValidator(ctx, validator)
|
||||
|
||||
// add to accumulated changes for tendermint
|
||||
bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorUpdateZero())
|
||||
tstore := ctx.TransientStore(k.storeTKey)
|
||||
tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI)
|
||||
|
||||
// also remove from the Bonded types.Validators Store
|
||||
store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr))
|
||||
|
||||
k.OnValidatorBeginUnbonding(ctx, validator.ConsAddress())
|
||||
return validator
|
||||
}
|
||||
|
||||
// perform all the store operations for when a validator status becomes bonded
|
||||
func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
pool := k.GetPool(ctx)
|
||||
|
||||
// sanity check
|
||||
if validator.Status == sdk.Bonded {
|
||||
panic(fmt.Sprintf("should not already be bonded, validator: %v\n", validator))
|
||||
}
|
||||
|
||||
validator.BondHeight = ctx.BlockHeight()
|
||||
|
||||
// set the status
|
||||
validator, pool = validator.UpdateStatus(pool, sdk.Bonded)
|
||||
k.SetPool(ctx, pool)
|
||||
|
||||
// save the now bonded validator record to the three referenced stores
|
||||
k.SetValidator(ctx, validator)
|
||||
store.Set(GetValidatorsBondedIndexKey(validator.OperatorAddr), []byte{})
|
||||
|
||||
// add to accumulated changes for tendermint
|
||||
bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorUpdate())
|
||||
tstore := ctx.TransientStore(k.storeTKey)
|
||||
tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI)
|
||||
|
||||
k.OnValidatorBonded(ctx, validator.ConsAddress())
|
||||
return validator
|
||||
}
|
||||
|
||||
// remove the validator record and associated indexes
|
||||
func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) {
|
||||
|
||||
k.OnValidatorRemoved(ctx, address)
|
||||
|
||||
// first retrieve the old validator record
|
||||
validator, found := k.GetValidator(ctx, address)
|
||||
if !found {
|
||||
return
|
||||
}
|
||||
|
||||
// delete the old validator record
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
pool := k.GetPool(ctx)
|
||||
store.Delete(GetValidatorKey(address))
|
||||
store.Delete(GetValidatorByConsAddrKey(sdk.ConsAddress(validator.ConsPubKey.Address())))
|
||||
store.Delete(GetValidatorsByPowerIndexKey(validator, pool))
|
||||
|
||||
// delete from the current and power weighted validator groups if the validator
|
||||
// is bonded - and add validator with zero power to the validator updates
|
||||
if store.Get(GetValidatorsBondedIndexKey(validator.OperatorAddr)) == nil {
|
||||
return
|
||||
}
|
||||
store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr))
|
||||
|
||||
bz := k.cdc.MustMarshalBinary(validator.ABCIValidatorUpdateZero())
|
||||
tstore := ctx.TransientStore(k.storeTKey)
|
||||
tstore.Set(GetTendermintUpdatesTKey(address), bz)
|
||||
}
|
||||
|
||||
// UpdateValidatorCommission attempts to update a validator's commission rate.
|
||||
// An error is returned if the new commission rate is invalid.
|
||||
func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, validator types.Validator, newRate sdk.Dec) sdk.Error {
|
||||
commission := validator.Commission
|
||||
blockTime := ctx.BlockHeader().Time
|
||||
|
||||
if err := commission.ValidateNewRate(newRate, blockTime); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
validator.Commission.Rate = newRate
|
||||
validator.Commission.UpdateTime = blockTime
|
||||
|
||||
k.SetValidator(ctx, validator)
|
||||
k.OnValidatorCommissionChange(ctx, validator.OperatorAddr)
|
||||
return nil
|
||||
}
|
||||
|
||||
//__________________________________________________________________________
|
||||
|
||||
// get the current validator on the cliff
|
||||
func (k Keeper) GetCliffValidator(ctx sdk.Context) []byte {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
return store.Get(ValidatorCliffIndexKey)
|
||||
}
|
||||
|
||||
// get the current power of the validator on the cliff
|
||||
func (k Keeper) GetCliffValidatorPower(ctx sdk.Context) []byte {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
return store.Get(ValidatorPowerCliffKey)
|
||||
}
|
||||
|
||||
// set the current validator and power of the validator on the cliff
|
||||
func (k Keeper) setCliffValidator(ctx sdk.Context, validator types.Validator, pool types.Pool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := GetValidatorsByPowerIndexKey(validator, pool)
|
||||
store.Set(ValidatorPowerCliffKey, bz)
|
||||
store.Set(ValidatorCliffIndexKey, validator.OperatorAddr)
|
||||
}
|
||||
|
||||
// clear the current validator and power of the validator on the cliff
|
||||
func (k Keeper) clearCliffValidator(ctx sdk.Context) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
store.Delete(ValidatorPowerCliffKey)
|
||||
store.Delete(ValidatorCliffIndexKey)
|
||||
}
|
||||
|
||||
func ensureValidatorFound(found bool, ownerAddr []byte) {
|
||||
if !found {
|
||||
panic(fmt.Sprintf("validator record not found for address: %X\n", ownerAddr))
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,18 +13,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// for testing, remove all validator update entries after applied to Tendermint
|
||||
func clearTendermintUpdates(ctx sdk.Context, k Keeper) {
|
||||
store := ctx.TransientStore(k.storeTKey)
|
||||
|
||||
// delete subspace
|
||||
iterator := sdk.KVStorePrefixIterator(store, TendermintUpdatesTKey)
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
store.Delete(iterator.Key())
|
||||
}
|
||||
iterator.Close()
|
||||
}
|
||||
|
||||
//_______________________________________________________
|
||||
|
||||
func TestSetValidator(t *testing.T) {
|
||||
@ -41,11 +29,17 @@ func TestSetValidator(t *testing.T) {
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares))
|
||||
keeper.SetPool(ctx, pool)
|
||||
keeper.UpdateValidator(ctx, validator)
|
||||
keeper.SetValidator(ctx, validator)
|
||||
keeper.SetValidatorByPowerIndex(ctx, validator, pool)
|
||||
|
||||
// after the save the validator should be bonded
|
||||
// ensure update
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
validator, found := keeper.GetValidator(ctx, valAddr)
|
||||
require.True(t, found)
|
||||
require.Equal(t, 1, len(updates))
|
||||
require.Equal(t, validator.ABCIValidatorUpdate(), updates[0])
|
||||
|
||||
// after the save the validator should be bonded
|
||||
require.Equal(t, sdk.Bonded, validator.Status)
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens))
|
||||
assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares))
|
||||
@ -59,7 +53,7 @@ func TestSetValidator(t *testing.T) {
|
||||
require.Equal(t, 1, len(resVals))
|
||||
assert.True(ValEq(t, validator, resVals[0]))
|
||||
|
||||
resVals = keeper.GetValidatorsByPower(ctx)
|
||||
resVals = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, 1, len(resVals))
|
||||
require.True(ValEq(t, validator, resVals[0]))
|
||||
|
||||
@ -71,10 +65,6 @@ func TestSetValidator(t *testing.T) {
|
||||
require.Equal(t, 1, len(resVals))
|
||||
require.True(ValEq(t, validator, resVals[0]))
|
||||
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
require.Equal(t, validator.ABCIValidatorUpdate(), updates[0])
|
||||
|
||||
allVals := keeper.GetAllValidators(ctx)
|
||||
require.Equal(t, 1, len(allVals))
|
||||
}
|
||||
@ -94,27 +84,28 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) {
|
||||
require.Equal(t, sdk.Unbonded, validator.Status)
|
||||
require.Equal(t, int64(100), validator.Tokens.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
keeper.UpdateValidator(ctx, validator)
|
||||
testingUpdateValidator(keeper, ctx, validator)
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool)
|
||||
|
||||
pool = keeper.GetPool(ctx)
|
||||
power := GetValidatorsByPowerIndexKey(validator, pool)
|
||||
require.True(t, keeper.validatorByPowerIndexExists(ctx, power))
|
||||
require.True(t, validatorByPowerIndexExists(keeper, ctx, power))
|
||||
|
||||
// burn half the delegator shares
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validator, pool)
|
||||
validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewDec(2)))
|
||||
require.Equal(t, int64(50), burned.RoundInt64())
|
||||
keeper.SetPool(ctx, pool) // update the pool
|
||||
keeper.UpdateValidator(ctx, validator) // update the validator, possibly kicking it out
|
||||
require.False(t, keeper.validatorByPowerIndexExists(ctx, power))
|
||||
keeper.SetPool(ctx, pool) // update the pool
|
||||
testingUpdateValidator(keeper, ctx, validator) // update the validator, possibly kicking it out
|
||||
require.False(t, validatorByPowerIndexExists(keeper, ctx, power))
|
||||
|
||||
pool = keeper.GetPool(ctx)
|
||||
validator, found = keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
power = GetValidatorsByPowerIndexKey(validator, pool)
|
||||
require.True(t, keeper.validatorByPowerIndexExists(ctx, power))
|
||||
require.True(t, validatorByPowerIndexExists(keeper, ctx, power))
|
||||
}
|
||||
|
||||
func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) {
|
||||
@ -144,7 +135,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) {
|
||||
val, pool, _ = val.AddTokensFromDel(pool, sdk.NewInt(int64((i+1)*10)))
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
val = keeper.UpdateValidator(ctx, val)
|
||||
val = testingUpdateValidator(keeper, ctx, val)
|
||||
validators[i] = val
|
||||
}
|
||||
|
||||
@ -152,17 +143,10 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) {
|
||||
|
||||
// remove enough tokens to kick out the validator below the current cliff
|
||||
// validator and next in line cliff validator
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, nextCliffVal, pool)
|
||||
nextCliffVal, pool, _ = nextCliffVal.RemoveDelShares(pool, sdk.NewDec(21))
|
||||
keeper.SetPool(ctx, pool)
|
||||
nextCliffVal = keeper.UpdateValidator(ctx, nextCliffVal)
|
||||
|
||||
// require the cliff validator has changed
|
||||
cliffVal := validators[numVals-maxVals-1]
|
||||
require.Equal(t, cliffVal.OperatorAddr, sdk.ValAddress(keeper.GetCliffValidator(ctx)))
|
||||
|
||||
// require the cliff validator power has changed
|
||||
cliffPower := keeper.GetCliffValidatorPower(ctx)
|
||||
require.Equal(t, GetValidatorsByPowerIndexKey(cliffVal, pool), cliffPower)
|
||||
nextCliffVal = testingUpdateValidator(keeper, ctx, nextCliffVal)
|
||||
|
||||
expectedValStatus := map[int]sdk.BondStatus{
|
||||
9: sdk.Bonded, 8: sdk.Bonded, 7: sdk.Bonded, 5: sdk.Bonded, 4: sdk.Bonded,
|
||||
@ -182,75 +166,6 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCliffValidatorChange(t *testing.T) {
|
||||
numVals := 10
|
||||
maxVals := 5
|
||||
|
||||
// create context, keeper, and pool for tests
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
pool := keeper.GetPool(ctx)
|
||||
|
||||
// create keeper parameters
|
||||
params := keeper.GetParams(ctx)
|
||||
params.MaxValidators = uint16(maxVals)
|
||||
keeper.SetParams(ctx, params)
|
||||
|
||||
// create a random pool
|
||||
pool.LooseTokens = sdk.NewDec(10000)
|
||||
pool.BondedTokens = sdk.NewDec(1234)
|
||||
keeper.SetPool(ctx, pool)
|
||||
|
||||
validators := make([]types.Validator, numVals)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
moniker := fmt.Sprintf("val#%d", int64(i))
|
||||
val := types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker})
|
||||
val.BondHeight = int64(i)
|
||||
val.BondIntraTxCounter = int16(i)
|
||||
val, pool, _ = val.AddTokensFromDel(pool, sdk.NewInt(int64((i+1)*10)))
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
val = keeper.UpdateValidator(ctx, val)
|
||||
validators[i] = val
|
||||
}
|
||||
|
||||
// add a large amount of tokens to current cliff validator
|
||||
currCliffVal := validators[numVals-maxVals]
|
||||
currCliffVal, pool, _ = currCliffVal.AddTokensFromDel(pool, sdk.NewInt(200))
|
||||
keeper.SetPool(ctx, pool)
|
||||
currCliffVal = keeper.UpdateValidator(ctx, currCliffVal)
|
||||
|
||||
// assert new cliff validator to be set to the second lowest bonded validator by power
|
||||
newCliffVal := validators[numVals-maxVals+1]
|
||||
require.Equal(t, newCliffVal.OperatorAddr, sdk.ValAddress(keeper.GetCliffValidator(ctx)))
|
||||
|
||||
// assert cliff validator power should have been updated
|
||||
cliffPower := keeper.GetCliffValidatorPower(ctx)
|
||||
require.Equal(t, GetValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower)
|
||||
|
||||
// add small amount of tokens to new current cliff validator
|
||||
newCliffVal, pool, _ = newCliffVal.AddTokensFromDel(pool, sdk.NewInt(1))
|
||||
keeper.SetPool(ctx, pool)
|
||||
newCliffVal = keeper.UpdateValidator(ctx, newCliffVal)
|
||||
|
||||
// assert cliff validator has not change but increased in power
|
||||
cliffPower = keeper.GetCliffValidatorPower(ctx)
|
||||
require.Equal(t, newCliffVal.OperatorAddr, sdk.ValAddress(keeper.GetCliffValidator(ctx)))
|
||||
require.Equal(t, GetValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower)
|
||||
|
||||
// add enough power to cliff validator to be equal in rank to next validator
|
||||
newCliffVal, pool, _ = newCliffVal.AddTokensFromDel(pool, sdk.NewInt(9))
|
||||
keeper.SetPool(ctx, pool)
|
||||
newCliffVal = keeper.UpdateValidator(ctx, newCliffVal)
|
||||
|
||||
// assert new cliff validator due to power rank construction
|
||||
newCliffVal = validators[numVals-maxVals+2]
|
||||
require.Equal(t, newCliffVal.OperatorAddr, sdk.ValAddress(keeper.GetCliffValidator(ctx)))
|
||||
|
||||
// assert cliff validator power should have been updated
|
||||
cliffPower = keeper.GetCliffValidatorPower(ctx)
|
||||
require.Equal(t, GetValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower)
|
||||
}
|
||||
|
||||
func TestSlashToZeroPowerRemoved(t *testing.T) {
|
||||
// initialize setup
|
||||
ctx, _, keeper := CreateTestInput(t, false, 100)
|
||||
@ -263,12 +178,14 @@ func TestSlashToZeroPowerRemoved(t *testing.T) {
|
||||
require.Equal(t, int64(100), validator.Tokens.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
keeper.SetValidatorByConsAddr(ctx, validator)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool)
|
||||
|
||||
// slash the validator by 100%
|
||||
consAddr0 := sdk.ConsAddress(PKs[0].Address())
|
||||
keeper.Slash(ctx, consAddr0, 0, 100, sdk.OneDec())
|
||||
// apply TM updates
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
// validator should have been deleted
|
||||
_, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.False(t, found)
|
||||
@ -306,7 +223,7 @@ func TestValidatorBasics(t *testing.T) {
|
||||
assert.True(sdk.DecEq(t, sdk.ZeroDec(), pool.BondedTokens))
|
||||
|
||||
// set and retrieve a record
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
keeper.SetValidatorByConsAddr(ctx, validators[0])
|
||||
resVal, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
@ -333,7 +250,7 @@ func TestValidatorBasics(t *testing.T) {
|
||||
validators[0].Status = sdk.Bonded
|
||||
validators[0].Tokens = sdk.NewDec(10)
|
||||
validators[0].DelegatorShares = sdk.NewDec(10)
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
resVal, found = keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
assert.True(ValEq(t, validators[0], resVal))
|
||||
@ -343,8 +260,8 @@ func TestValidatorBasics(t *testing.T) {
|
||||
assert.True(ValEq(t, validators[0], resVals[0]))
|
||||
|
||||
// add other validators
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
validators[2] = keeper.UpdateValidator(ctx, validators[2])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[2] = testingUpdateValidator(keeper, ctx, validators[2])
|
||||
resVal, found = keeper.GetValidator(ctx, addrVals[1])
|
||||
require.True(t, found)
|
||||
assert.True(ValEq(t, validators[1], resVal))
|
||||
@ -364,7 +281,7 @@ func TestValidatorBasics(t *testing.T) {
|
||||
require.False(t, found)
|
||||
}
|
||||
|
||||
// test how the validators are sorted, tests GetValidatorsByPower
|
||||
// test how the validators are sorted, tests GetBondedValidatorsByPower
|
||||
func GetValidatorSortingUnmixed(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
|
||||
@ -377,11 +294,11 @@ func GetValidatorSortingUnmixed(t *testing.T) {
|
||||
validators[i].Status = sdk.Bonded
|
||||
validators[i].Tokens = sdk.NewDec(amt)
|
||||
validators[i].DelegatorShares = sdk.NewDec(amt)
|
||||
keeper.UpdateValidator(ctx, validators[i])
|
||||
testingUpdateValidator(keeper, ctx, validators[i])
|
||||
}
|
||||
|
||||
// first make sure everything made it in to the gotValidator group
|
||||
resValidators := keeper.GetValidatorsByPower(ctx)
|
||||
resValidators := keeper.GetBondedValidatorsByPower(ctx)
|
||||
assert.Equal(t, n, len(resValidators))
|
||||
assert.Equal(t, sdk.NewDec(400), resValidators[0].BondedTokens(), "%v", resValidators)
|
||||
assert.Equal(t, sdk.NewDec(200), resValidators[1].BondedTokens(), "%v", resValidators)
|
||||
@ -396,15 +313,15 @@ func GetValidatorSortingUnmixed(t *testing.T) {
|
||||
|
||||
// test a basic increase in voting power
|
||||
validators[3].Tokens = sdk.NewDec(500)
|
||||
keeper.UpdateValidator(ctx, validators[3])
|
||||
resValidators = keeper.GetValidatorsByPower(ctx)
|
||||
testingUpdateValidator(keeper, ctx, validators[3])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, len(resValidators), n)
|
||||
assert.True(ValEq(t, validators[3], resValidators[0]))
|
||||
|
||||
// test a decrease in voting power
|
||||
validators[3].Tokens = sdk.NewDec(300)
|
||||
keeper.UpdateValidator(ctx, validators[3])
|
||||
resValidators = keeper.GetValidatorsByPower(ctx)
|
||||
testingUpdateValidator(keeper, ctx, validators[3])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, len(resValidators), n)
|
||||
assert.True(ValEq(t, validators[3], resValidators[0]))
|
||||
assert.True(ValEq(t, validators[4], resValidators[1]))
|
||||
@ -412,8 +329,8 @@ func GetValidatorSortingUnmixed(t *testing.T) {
|
||||
// test equal voting power, different age
|
||||
validators[3].Tokens = sdk.NewDec(200)
|
||||
ctx = ctx.WithBlockHeight(10)
|
||||
keeper.UpdateValidator(ctx, validators[3])
|
||||
resValidators = keeper.GetValidatorsByPower(ctx)
|
||||
testingUpdateValidator(keeper, ctx, validators[3])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, len(resValidators), n)
|
||||
assert.True(ValEq(t, validators[3], resValidators[0]))
|
||||
assert.True(ValEq(t, validators[4], resValidators[1]))
|
||||
@ -422,8 +339,8 @@ func GetValidatorSortingUnmixed(t *testing.T) {
|
||||
|
||||
// no change in voting power - no change in sort
|
||||
ctx = ctx.WithBlockHeight(20)
|
||||
keeper.UpdateValidator(ctx, validators[4])
|
||||
resValidators = keeper.GetValidatorsByPower(ctx)
|
||||
testingUpdateValidator(keeper, ctx, validators[4])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, len(resValidators), n)
|
||||
assert.True(ValEq(t, validators[3], resValidators[0]))
|
||||
assert.True(ValEq(t, validators[4], resValidators[1]))
|
||||
@ -431,12 +348,12 @@ func GetValidatorSortingUnmixed(t *testing.T) {
|
||||
// change in voting power of both validators, both still in v-set, no age change
|
||||
validators[3].Tokens = sdk.NewDec(300)
|
||||
validators[4].Tokens = sdk.NewDec(300)
|
||||
keeper.UpdateValidator(ctx, validators[3])
|
||||
resValidators = keeper.GetValidatorsByPower(ctx)
|
||||
testingUpdateValidator(keeper, ctx, validators[3])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, len(resValidators), n)
|
||||
ctx = ctx.WithBlockHeight(30)
|
||||
keeper.UpdateValidator(ctx, validators[4])
|
||||
resValidators = keeper.GetValidatorsByPower(ctx)
|
||||
testingUpdateValidator(keeper, ctx, validators[4])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, len(resValidators), n, "%v", resValidators)
|
||||
assert.True(ValEq(t, validators[3], resValidators[0]))
|
||||
assert.True(ValEq(t, validators[4], resValidators[1]))
|
||||
@ -473,7 +390,7 @@ func GetValidatorSortingMixed(t *testing.T) {
|
||||
validators[4].Tokens = sdk.NewDec(amts[4])
|
||||
|
||||
for i := range amts {
|
||||
keeper.UpdateValidator(ctx, validators[i])
|
||||
testingUpdateValidator(keeper, ctx, validators[i])
|
||||
}
|
||||
val0, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[0]))
|
||||
require.True(t, found)
|
||||
@ -492,7 +409,7 @@ func GetValidatorSortingMixed(t *testing.T) {
|
||||
require.Equal(t, sdk.Bonded, val4.Status)
|
||||
|
||||
// first make sure everything made it in to the gotValidator group
|
||||
resValidators := keeper.GetValidatorsByPower(ctx)
|
||||
resValidators := keeper.GetBondedValidatorsByPower(ctx)
|
||||
assert.Equal(t, n, len(resValidators))
|
||||
assert.Equal(t, sdk.NewDec(400), resValidators[0].BondedTokens(), "%v", resValidators)
|
||||
assert.Equal(t, sdk.NewDec(200), resValidators[1].BondedTokens(), "%v", resValidators)
|
||||
@ -525,24 +442,26 @@ func TestGetValidatorsEdgeCases(t *testing.T) {
|
||||
moniker := fmt.Sprintf("val#%d", int64(i))
|
||||
validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker})
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
validators[i].BondIntraTxCounter = int16(i)
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[i] = keeper.UpdateValidator(ctx, validators[i])
|
||||
validators[i] = testingUpdateValidator(keeper, ctx, validators[i])
|
||||
}
|
||||
|
||||
for i := range amts {
|
||||
validators[i], found = keeper.GetValidator(ctx, validators[i].OperatorAddr)
|
||||
require.True(t, found)
|
||||
}
|
||||
resValidators := keeper.GetValidatorsByPower(ctx)
|
||||
resValidators := keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, nMax, uint16(len(resValidators)))
|
||||
assert.True(ValEq(t, validators[2], resValidators[0]))
|
||||
assert.True(ValEq(t, validators[3], resValidators[1]))
|
||||
|
||||
pool := keeper.GetPool(ctx)
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validators[0], pool)
|
||||
validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(500))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
resValidators = keeper.GetValidatorsByPower(ctx)
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, nMax, uint16(len(resValidators)))
|
||||
assert.True(ValEq(t, validators[0], resValidators[0]))
|
||||
assert.True(ValEq(t, validators[2], resValidators[1]))
|
||||
@ -556,28 +475,31 @@ func TestGetValidatorsEdgeCases(t *testing.T) {
|
||||
|
||||
validators[3], found = keeper.GetValidator(ctx, validators[3].OperatorAddr)
|
||||
require.True(t, found)
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool)
|
||||
validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(1))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[3] = keeper.UpdateValidator(ctx, validators[3])
|
||||
resValidators = keeper.GetValidatorsByPower(ctx)
|
||||
validators[3] = testingUpdateValidator(keeper, ctx, validators[3])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, nMax, uint16(len(resValidators)))
|
||||
assert.True(ValEq(t, validators[0], resValidators[0]))
|
||||
assert.True(ValEq(t, validators[3], resValidators[1]))
|
||||
|
||||
// validator 3 kicked out temporarily
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool)
|
||||
validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[3] = keeper.UpdateValidator(ctx, validators[3])
|
||||
resValidators = keeper.GetValidatorsByPower(ctx)
|
||||
validators[3] = testingUpdateValidator(keeper, ctx, validators[3])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, nMax, uint16(len(resValidators)))
|
||||
assert.True(ValEq(t, validators[0], resValidators[0]))
|
||||
assert.True(ValEq(t, validators[2], resValidators[1]))
|
||||
|
||||
// validator 4 does not get spot back
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool)
|
||||
validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(200))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[3] = keeper.UpdateValidator(ctx, validators[3])
|
||||
resValidators = keeper.GetValidatorsByPower(ctx)
|
||||
validators[3] = testingUpdateValidator(keeper, ctx, validators[3])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, nMax, uint16(len(resValidators)))
|
||||
assert.True(ValEq(t, validators[0], resValidators[0]))
|
||||
assert.True(ValEq(t, validators[2], resValidators[1]))
|
||||
@ -600,34 +522,39 @@ func TestValidatorBondHeight(t *testing.T) {
|
||||
validators[0] = types.NewValidator(sdk.ValAddress(Addrs[0]), PKs[0], types.Description{})
|
||||
validators[1] = types.NewValidator(sdk.ValAddress(Addrs[1]), PKs[1], types.Description{})
|
||||
validators[2] = types.NewValidator(sdk.ValAddress(Addrs[2]), PKs[2], types.Description{})
|
||||
validators[0].BondIntraTxCounter = 0
|
||||
validators[1].BondIntraTxCounter = 1
|
||||
validators[2].BondIntraTxCounter = 2
|
||||
|
||||
validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(200))
|
||||
validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(100))
|
||||
validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(100))
|
||||
keeper.SetPool(ctx, pool)
|
||||
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
|
||||
////////////////////////////////////////
|
||||
// If two validators both increase to the same voting power in the same block,
|
||||
// the one with the first transaction should become bonded
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
validators[2] = keeper.UpdateValidator(ctx, validators[2])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[2] = testingUpdateValidator(keeper, ctx, validators[2])
|
||||
|
||||
pool = keeper.GetPool(ctx)
|
||||
|
||||
resValidators := keeper.GetValidatorsByPower(ctx)
|
||||
resValidators := keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, uint16(len(resValidators)), params.MaxValidators)
|
||||
|
||||
assert.True(ValEq(t, validators[0], resValidators[0]))
|
||||
assert.True(ValEq(t, validators[1], resValidators[1]))
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validators[1], pool)
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validators[2], pool)
|
||||
validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(50))
|
||||
validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(50))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[2] = keeper.UpdateValidator(ctx, validators[2])
|
||||
resValidators = keeper.GetValidatorsByPower(ctx)
|
||||
validators[2] = testingUpdateValidator(keeper, ctx, validators[2])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, params.MaxValidators, uint16(len(resValidators)))
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
assert.True(ValEq(t, validators[0], resValidators[0]))
|
||||
assert.True(ValEq(t, validators[2], resValidators[1]))
|
||||
}
|
||||
@ -646,20 +573,21 @@ func TestFullValidatorSetPowerChange(t *testing.T) {
|
||||
pool := keeper.GetPool(ctx)
|
||||
validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{})
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
validators[i].BondIntraTxCounter = int16(i)
|
||||
keeper.SetPool(ctx, pool)
|
||||
keeper.UpdateValidator(ctx, validators[i])
|
||||
testingUpdateValidator(keeper, ctx, validators[i])
|
||||
}
|
||||
for i := range amts {
|
||||
var found bool
|
||||
validators[i], found = keeper.GetValidator(ctx, validators[i].OperatorAddr)
|
||||
require.True(t, found)
|
||||
}
|
||||
assert.Equal(t, sdk.Unbonding, validators[0].Status)
|
||||
assert.Equal(t, sdk.Unbonded, validators[0].Status)
|
||||
assert.Equal(t, sdk.Unbonding, validators[1].Status)
|
||||
assert.Equal(t, sdk.Bonded, validators[2].Status)
|
||||
assert.Equal(t, sdk.Bonded, validators[3].Status)
|
||||
assert.Equal(t, sdk.Unbonded, validators[4].Status)
|
||||
resValidators := keeper.GetValidatorsByPower(ctx)
|
||||
resValidators := keeper.GetBondedValidatorsByPower(ctx)
|
||||
assert.Equal(t, max, len(resValidators))
|
||||
assert.True(ValEq(t, validators[2], resValidators[0])) // in the order of txs
|
||||
assert.True(ValEq(t, validators[3], resValidators[1]))
|
||||
@ -668,14 +596,14 @@ func TestFullValidatorSetPowerChange(t *testing.T) {
|
||||
pool := keeper.GetPool(ctx)
|
||||
validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(600))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
resValidators = keeper.GetValidatorsByPower(ctx)
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
assert.Equal(t, max, len(resValidators))
|
||||
assert.True(ValEq(t, validators[0], resValidators[0]))
|
||||
assert.True(ValEq(t, validators[2], resValidators[1]))
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesAllNone(t *testing.T) {
|
||||
func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
|
||||
amts := []int64{10, 20}
|
||||
@ -693,17 +621,22 @@ func TestGetTendermintUpdatesAllNone(t *testing.T) {
|
||||
|
||||
// test from nothing to something
|
||||
// tendermintUpdate set: {} -> {c1, c3}
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
pool := keeper.GetPool(ctx)
|
||||
keeper.SetValidator(ctx, validators[0])
|
||||
keeper.SetValidatorByPowerIndex(ctx, validators[0], pool)
|
||||
keeper.SetValidator(ctx, validators[1])
|
||||
keeper.SetValidatorByPowerIndex(ctx, validators[1], pool)
|
||||
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
assert.Equal(t, 2, len(updates))
|
||||
assert.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0])
|
||||
assert.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1])
|
||||
validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddr)
|
||||
validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddr)
|
||||
assert.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1])
|
||||
assert.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0])
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesIdentical(t *testing.T) {
|
||||
func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
|
||||
amts := []int64{10, 20}
|
||||
@ -714,19 +647,18 @@ func TestGetTendermintUpdatesIdentical(t *testing.T) {
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
keeper.SetPool(ctx, pool)
|
||||
}
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// test identical,
|
||||
// tendermintUpdate set: {} -> {}
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesSingleValueChange(t *testing.T) {
|
||||
func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
|
||||
amts := []int64{10, 20}
|
||||
@ -737,24 +669,23 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) {
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
keeper.SetPool(ctx, pool)
|
||||
}
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// test single value change
|
||||
// tendermintUpdate set: {} -> {c1'}
|
||||
validators[0].Status = sdk.Bonded
|
||||
validators[0].Tokens = sdk.NewDec(600)
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
require.Equal(t, 1, len(updates))
|
||||
require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0])
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) {
|
||||
func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
|
||||
amts := []int64{10, 20}
|
||||
@ -765,10 +696,9 @@ func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) {
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
keeper.SetPool(ctx, pool)
|
||||
}
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// test multiple value change
|
||||
// tendermintUpdate set: {c1, c3} -> {c1', c3'}
|
||||
@ -776,16 +706,16 @@ func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) {
|
||||
validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(190))
|
||||
validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(80))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 2, len(updates))
|
||||
require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0])
|
||||
require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1])
|
||||
require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1])
|
||||
require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0])
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesInserted(t *testing.T) {
|
||||
func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
|
||||
amts := []int64{10, 20, 5, 15, 25}
|
||||
@ -796,36 +726,42 @@ func TestGetTendermintUpdatesInserted(t *testing.T) {
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
keeper.SetPool(ctx, pool)
|
||||
}
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// test validtor added at the beginning
|
||||
// tendermintUpdate set: {} -> {c0}
|
||||
validators[2] = keeper.UpdateValidator(ctx, validators[2])
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
pool := keeper.GetPool(ctx)
|
||||
keeper.SetValidator(ctx, validators[2])
|
||||
keeper.SetValidatorByPowerIndex(ctx, validators[2], pool)
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddr)
|
||||
require.Equal(t, 1, len(updates))
|
||||
require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0])
|
||||
|
||||
// test validtor added at the beginning
|
||||
// tendermintUpdate set: {} -> {c0}
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
validators[3] = keeper.UpdateValidator(ctx, validators[3])
|
||||
updates = keeper.GetTendermintUpdates(ctx)
|
||||
pool = keeper.GetPool(ctx)
|
||||
keeper.SetValidator(ctx, validators[3])
|
||||
keeper.SetValidatorByPowerIndex(ctx, validators[3], pool)
|
||||
updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
validators[3], _ = keeper.GetValidator(ctx, validators[3].OperatorAddr)
|
||||
require.Equal(t, 1, len(updates))
|
||||
require.Equal(t, validators[3].ABCIValidatorUpdate(), updates[0])
|
||||
|
||||
// test validtor added at the end
|
||||
// tendermintUpdate set: {} -> {c0}
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
validators[4] = keeper.UpdateValidator(ctx, validators[4])
|
||||
updates = keeper.GetTendermintUpdates(ctx)
|
||||
pool = keeper.GetPool(ctx)
|
||||
keeper.SetValidator(ctx, validators[4])
|
||||
keeper.SetValidatorByPowerIndex(ctx, validators[4], pool)
|
||||
updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
validators[4], _ = keeper.GetValidator(ctx, validators[4].OperatorAddr)
|
||||
require.Equal(t, 1, len(updates))
|
||||
require.Equal(t, validators[4].ABCIValidatorUpdate(), updates[0])
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesWithCliffValidator(t *testing.T) {
|
||||
func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
params := types.DefaultParams()
|
||||
params.MaxValidators = 2
|
||||
@ -839,34 +775,33 @@ func TestGetTendermintUpdatesWithCliffValidator(t *testing.T) {
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
keeper.SetPool(ctx, pool)
|
||||
}
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// test validator added at the end but not inserted in the valset
|
||||
// tendermintUpdate set: {} -> {}
|
||||
keeper.UpdateValidator(ctx, validators[2])
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
testingUpdateValidator(keeper, ctx, validators[2])
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 0, len(updates))
|
||||
|
||||
// test validator change its power and become a gotValidator (pushing out an existing)
|
||||
// tendermintUpdate set: {} -> {c0, c4}
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
pool := keeper.GetPool(ctx)
|
||||
validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[2] = keeper.UpdateValidator(ctx, validators[2])
|
||||
|
||||
updates = keeper.GetTendermintUpdates(ctx)
|
||||
keeper.SetValidator(ctx, validators[2])
|
||||
keeper.SetValidatorByPowerIndex(ctx, validators[2], pool)
|
||||
updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddr)
|
||||
require.Equal(t, 2, len(updates), "%v", updates)
|
||||
require.Equal(t, validators[0].ABCIValidatorUpdateZero(), updates[0])
|
||||
require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[1])
|
||||
require.Equal(t, validators[0].ABCIValidatorUpdateZero(), updates[1])
|
||||
require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0])
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesPowerDecrease(t *testing.T) {
|
||||
func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
|
||||
amts := []int64{100, 100}
|
||||
@ -875,12 +810,12 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) {
|
||||
pool := keeper.GetPool(ctx)
|
||||
validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{})
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
validators[i].BondIntraTxCounter = int16(i)
|
||||
keeper.SetPool(ctx, pool)
|
||||
}
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// check initial power
|
||||
require.Equal(t, sdk.NewDec(100).RoundInt64(), validators[0].GetPower().RoundInt64())
|
||||
@ -892,21 +827,21 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) {
|
||||
validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewDec(20))
|
||||
validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewDec(30))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
|
||||
// power has changed
|
||||
require.Equal(t, sdk.NewDec(80).RoundInt64(), validators[0].GetPower().RoundInt64())
|
||||
require.Equal(t, sdk.NewDec(70).RoundInt64(), validators[1].GetPower().RoundInt64())
|
||||
|
||||
// Tendermint updates should reflect power change
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 2, len(updates))
|
||||
require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0])
|
||||
require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1])
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesNewValidator(t *testing.T) {
|
||||
func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
params := keeper.GetParams(ctx)
|
||||
params.MaxValidators = uint16(3)
|
||||
@ -923,28 +858,33 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) {
|
||||
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
|
||||
|
||||
validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{})
|
||||
validators[i].BondIntraTxCounter = int16(i)
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[i] = keeper.UpdateValidator(ctx, validators[i])
|
||||
keeper.SetValidator(ctx, validators[i])
|
||||
keeper.SetValidatorByPowerIndex(ctx, validators[i], pool)
|
||||
}
|
||||
|
||||
// verify initial Tendermint updates are correct
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, len(validators), len(updates))
|
||||
validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddr)
|
||||
validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddr)
|
||||
require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0])
|
||||
require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1])
|
||||
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// update initial validator set
|
||||
for i, amt := range amts {
|
||||
pool := keeper.GetPool(ctx)
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validators[i], pool)
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[i] = keeper.UpdateValidator(ctx, validators[i])
|
||||
keeper.SetValidator(ctx, validators[i])
|
||||
keeper.SetValidatorByPowerIndex(ctx, validators[i], pool)
|
||||
}
|
||||
|
||||
// add a new validator that goes from zero power, to non-zero power, back to
|
||||
@ -958,10 +898,11 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) {
|
||||
validator, pool, _ = validator.AddTokensFromDel(pool, amt)
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
keeper.SetValidator(ctx, validator)
|
||||
|
||||
validator, pool, _ = validator.RemoveDelShares(pool, sdk.NewDecFromInt(amt))
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
keeper.SetValidator(ctx, validator)
|
||||
keeper.SetValidatorByPowerIndex(ctx, validator, pool)
|
||||
|
||||
// add a new validator that increases in power
|
||||
valPubKey = PKs[len(validators)+2]
|
||||
@ -969,19 +910,22 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) {
|
||||
|
||||
validator = types.NewValidator(valAddr, valPubKey, types.Description{})
|
||||
validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(500))
|
||||
|
||||
keeper.SetValidator(ctx, validator)
|
||||
keeper.SetValidatorByPowerIndex(ctx, validator, pool)
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
|
||||
// verify initial Tendermint updates are correct
|
||||
updates = keeper.GetTendermintUpdates(ctx)
|
||||
updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
validator, _ = keeper.GetValidator(ctx, validator.OperatorAddr)
|
||||
validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddr)
|
||||
validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddr)
|
||||
require.Equal(t, len(validators)+1, len(updates))
|
||||
require.Equal(t, validator.ABCIValidatorUpdate(), updates[0])
|
||||
require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1])
|
||||
require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[2])
|
||||
}
|
||||
|
||||
func TestGetTendermintUpdatesBondTransition(t *testing.T) {
|
||||
func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||
params := keeper.GetParams(ctx)
|
||||
params.MaxValidators = uint16(2)
|
||||
@ -1000,60 +944,67 @@ func TestGetTendermintUpdatesBondTransition(t *testing.T) {
|
||||
|
||||
validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{Moniker: moniker})
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
|
||||
validators[i].BondIntraTxCounter = int16(i)
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[i] = keeper.UpdateValidator(ctx, validators[i])
|
||||
keeper.SetValidator(ctx, validators[i])
|
||||
keeper.SetValidatorByPowerIndex(ctx, validators[i], pool)
|
||||
}
|
||||
|
||||
// verify initial Tendermint updates are correct
|
||||
updates := keeper.GetTendermintUpdates(ctx)
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 2, len(updates))
|
||||
validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddr)
|
||||
validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddr)
|
||||
require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0])
|
||||
require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1])
|
||||
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// delegate to validator with lowest power but not enough to bond
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
pool := keeper.GetPool(ctx)
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, validators[0].OperatorAddr)
|
||||
var found bool
|
||||
validators[0], found = keeper.GetValidator(ctx, validators[0].OperatorAddr)
|
||||
require.True(t, found)
|
||||
|
||||
validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(1))
|
||||
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validators[0], pool)
|
||||
validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(1))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[0] = keeper.UpdateValidator(ctx, validator)
|
||||
keeper.SetValidator(ctx, validators[0])
|
||||
keeper.SetValidatorByPowerIndex(ctx, validators[0], pool)
|
||||
|
||||
// verify initial Tendermint updates are correct
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// create a series of events that will bond and unbond the validator with
|
||||
// lowest power in a single block context (height)
|
||||
ctx = ctx.WithBlockHeight(2)
|
||||
pool = keeper.GetPool(ctx)
|
||||
|
||||
validator, found = keeper.GetValidator(ctx, validators[1].OperatorAddr)
|
||||
validators[1], found = keeper.GetValidator(ctx, validators[1].OperatorAddr)
|
||||
require.True(t, found)
|
||||
|
||||
validator, pool, _ = validator.RemoveDelShares(pool, validator.DelegatorShares)
|
||||
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validators[0], pool)
|
||||
validators[0], pool, _ = validators[0].RemoveDelShares(pool, validators[0].DelegatorShares)
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
|
||||
validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(250))
|
||||
keeper.SetValidator(ctx, validators[0])
|
||||
keeper.SetValidatorByPowerIndex(ctx, validators[0], pool)
|
||||
updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 0, len(updates))
|
||||
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validators[1], pool)
|
||||
validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(250))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[1] = keeper.UpdateValidator(ctx, validator)
|
||||
keeper.SetValidator(ctx, validators[1])
|
||||
keeper.SetValidatorByPowerIndex(ctx, validators[1], pool)
|
||||
|
||||
// verify initial Tendermint updates are correct
|
||||
updates = keeper.GetTendermintUpdates(ctx)
|
||||
updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(updates))
|
||||
require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0])
|
||||
|
||||
clearTendermintUpdates(ctx, keeper)
|
||||
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
}
|
||||
|
||||
func TestUpdateValidatorCommission(t *testing.T) {
|
||||
@ -1072,6 +1023,9 @@ func TestUpdateValidatorCommission(t *testing.T) {
|
||||
val1, _ = val1.SetInitialCommission(commission1)
|
||||
val2, _ = val2.SetInitialCommission(commission2)
|
||||
|
||||
keeper.SetValidator(ctx, val1)
|
||||
keeper.SetValidator(ctx, val2)
|
||||
|
||||
testCases := []struct {
|
||||
validator types.Validator
|
||||
newRate sdk.Dec
|
||||
@ -1085,11 +1039,13 @@ func TestUpdateValidatorCommission(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
err := keeper.UpdateValidatorCommission(ctx, tc.validator, tc.newRate)
|
||||
commission, err := keeper.UpdateValidatorCommission(ctx, tc.validator, tc.newRate)
|
||||
|
||||
if tc.expectedErr {
|
||||
require.Error(t, err, "expected error for test case #%d with rate: %s", i, tc.newRate)
|
||||
} else {
|
||||
tc.validator.Commission = commission
|
||||
keeper.SetValidator(ctx, tc.validator)
|
||||
val, found := keeper.GetValidator(ctx, tc.validator.OperatorAddr)
|
||||
|
||||
require.True(t, found,
|
||||
|
||||
@ -71,8 +71,8 @@ func TestQueryValidators(t *testing.T) {
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, amt)
|
||||
}
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[0] = keeper.UpdateValidator(ctx, validators[0])
|
||||
validators[1] = keeper.UpdateValidator(ctx, validators[1])
|
||||
keeper.SetValidator(ctx, validators[0])
|
||||
keeper.SetValidator(ctx, validators[1])
|
||||
|
||||
// Query Validators
|
||||
queriedValidators := keeper.GetValidators(ctx, params.MaxValidators)
|
||||
@ -114,9 +114,14 @@ func TestQueryDelegation(t *testing.T) {
|
||||
// Create Validators and Delegation
|
||||
val1 := types.NewValidator(addrVal1, pk1, types.Description{})
|
||||
keeper.SetValidator(ctx, val1)
|
||||
pool := keeper.GetPool(ctx)
|
||||
keeper.SetValidatorByPowerIndex(ctx, val1, pool)
|
||||
|
||||
keeper.Delegate(ctx, addrAcc2, sdk.NewCoin("steak", sdk.NewInt(20)), val1, true)
|
||||
|
||||
// apply TM updates
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// Query Delegator bonded validators
|
||||
queryParams := newTestDelegatorQuery(addrAcc2)
|
||||
bz, errRes := cdc.MarshalJSON(queryParams)
|
||||
|
||||
@ -37,9 +37,7 @@ var (
|
||||
|
||||
GetValidatorKey = keeper.GetValidatorKey
|
||||
GetValidatorByConsAddrKey = keeper.GetValidatorByConsAddrKey
|
||||
GetValidatorsBondedIndexKey = keeper.GetValidatorsBondedIndexKey
|
||||
GetValidatorsByPowerIndexKey = keeper.GetValidatorsByPowerIndexKey
|
||||
GetTendermintUpdatesTKey = keeper.GetTendermintUpdatesTKey
|
||||
GetDelegationKey = keeper.GetDelegationKey
|
||||
GetDelegationsKey = keeper.GetDelegationsKey
|
||||
ParamKey = keeper.ParamKey
|
||||
@ -48,9 +46,6 @@ var (
|
||||
ValidatorsByConsAddrKey = keeper.ValidatorsByConsAddrKey
|
||||
ValidatorsBondedIndexKey = keeper.ValidatorsBondedIndexKey
|
||||
ValidatorsByPowerIndexKey = keeper.ValidatorsByPowerIndexKey
|
||||
ValidatorCliffIndexKey = keeper.ValidatorCliffIndexKey
|
||||
ValidatorPowerCliffKey = keeper.ValidatorPowerCliffKey
|
||||
TendermintUpdatesTKey = keeper.TendermintUpdatesTKey
|
||||
DelegationKey = keeper.DelegationKey
|
||||
IntraTxCounterKey = keeper.IntraTxCounterKey
|
||||
GetUBDKey = keeper.GetUBDKey
|
||||
|
||||
@ -314,6 +314,12 @@ func (v Validator) ABCIValidatorUpdate() abci.ValidatorUpdate {
|
||||
}
|
||||
}
|
||||
|
||||
// ABCIValidatorPowerBytes
|
||||
func (v Validator) ABCIValidatorPowerBytes(cdc *codec.Codec) []byte {
|
||||
power := v.BondedTokens().RoundInt64()
|
||||
return cdc.MustMarshalBinary(power)
|
||||
}
|
||||
|
||||
// ABCIValidatorUpdateZero returns an abci.ValidatorUpdate from a staked validator type
|
||||
// with zero power used for validator updates.
|
||||
func (v Validator) ABCIValidatorUpdateZero() abci.ValidatorUpdate {
|
||||
@ -429,6 +435,7 @@ func (v Validator) BondedTokens() sdk.Dec {
|
||||
return sdk.ZeroDec()
|
||||
}
|
||||
|
||||
// TODO remove this once the validator queue logic is implemented
|
||||
// Returns if the validator should be considered unbonded
|
||||
func (v Validator) IsUnbonded(ctx sdk.Context) bool {
|
||||
switch v.Status {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user