Merge PR #3717: Allow the undelegation of more coins than were delegated; More validity checks.
This commit is contained in:
parent
7e08b62f4e
commit
10bd98e58e
|
@ -96,6 +96,12 @@ CLI flag.
|
|||
where validator is unexpectedly slashed throwing off test calculations
|
||||
* [\#3411] Include the `RequestInitChain.Time` in the block header init during
|
||||
`InitChain`.
|
||||
* [\#3717] Update the vesting specification and implementation to cap deduction from
|
||||
`DelegatedVesting` by at most `DelegatedVesting`. This accounts for the case where
|
||||
the undelegation amount may exceed the original delegation amount due to
|
||||
truncation of undelegation tokens.
|
||||
* [\#3717] Ignore unknown proposers in allocating rewards for proposers, in case
|
||||
unbonding period was just 1 block and proposer was already deleted.
|
||||
* [\#3726] Cap(clip) reward to remaining coins in AllocateTokens.
|
||||
|
||||
### Tendermint
|
||||
|
|
|
@ -171,7 +171,7 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest
|
|||
Pool: staking.InitialPool(),
|
||||
Params: staking.Params{
|
||||
UnbondingTime: time.Duration(randIntBetween(r, 60, 60*60*24*3*2)) * time.Second,
|
||||
MaxValidators: uint16(r.Intn(250)),
|
||||
MaxValidators: uint16(r.Intn(250) + 1),
|
||||
BondDenom: sdk.DefaultBondDenom,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -251,10 +251,12 @@ func DelegateCoins(t Time, from Account, amount Coins) {
|
|||
### Undelegating
|
||||
|
||||
For a vesting account attempting to undelegate `D` coins, the following is performed:
|
||||
NOTE: `DV < D` and `(DV + DF) < D` may be possible due to quirks in the rounding of
|
||||
delegation/undelegation logic.
|
||||
|
||||
1. Verify `(DV + DF) >= D > 0` (this is simply a sanity check)
|
||||
1. Verify `D > 0`
|
||||
2. Compute `X := min(DF, D)` (portion of `D` that should become free, prioritizing free coins)
|
||||
3. Compute `Y := D - X` (portion of `D` that should remain vesting)
|
||||
3. Compute `Y := min(DV, D - X)` (portion of `D` that should remain vesting)
|
||||
4. Set `DF -= X`
|
||||
5. Set `DV -= Y`
|
||||
6. Set `BC += D`
|
||||
|
@ -274,6 +276,11 @@ func (cva ContinuousVestingAccount) TrackUndelegation(amount Coins) {
|
|||
with an excess `DV` amount, even after all its coins have vested. This is because
|
||||
undelegating free coins are prioritized.
|
||||
|
||||
**Note**: The undelegation (bond refund) amount may exceed the delegated
|
||||
vesting (bond) amount due to the way undelegation truncates the bond refund,
|
||||
which can increase the validator's exchange rate (tokens/shares) slightly if the
|
||||
undelegated tokens are non-integral.
|
||||
|
||||
#### Keepers/Handlers
|
||||
|
||||
```go
|
||||
|
|
|
@ -389,8 +389,6 @@ func (coins Coins) AmountOf(denom string) Int {
|
|||
|
||||
// IsAllPositive returns true if there is at least one coin and all currencies
|
||||
// have a positive value.
|
||||
//
|
||||
// TODO: Remove once unsigned integers are used.
|
||||
func (coins Coins) IsAllPositive() bool {
|
||||
if len(coins) == 0 {
|
||||
return false
|
||||
|
|
|
@ -287,6 +287,11 @@ func (bva *BaseVestingAccount) trackDelegation(vestingCoins, amount sdk.Coins) {
|
|||
// by which amount the base coins need to increase. The resulting base coins are
|
||||
// returned.
|
||||
//
|
||||
// NOTE: The undelegation (bond refund) amount may exceed the delegated
|
||||
// vesting (bond) amount due to the way undelegation truncates the bond refund,
|
||||
// which can increase the validator's exchange rate (tokens/shares) slightly if
|
||||
// the undelegated tokens are non-integral.
|
||||
//
|
||||
// CONTRACT: The account's coins and undelegation coins must be sorted.
|
||||
func (bva *BaseVestingAccount) TrackUndelegation(amount sdk.Coins) {
|
||||
for _, coin := range amount {
|
||||
|
@ -295,12 +300,13 @@ func (bva *BaseVestingAccount) TrackUndelegation(amount sdk.Coins) {
|
|||
panic("undelegation attempt with zero coins")
|
||||
}
|
||||
delegatedFree := bva.DelegatedFree.AmountOf(coin.Denom)
|
||||
delegatedVesting := bva.DelegatedVesting.AmountOf(coin.Denom)
|
||||
|
||||
// compute x and y per the specification, where:
|
||||
// X := min(DF, D)
|
||||
// Y := D - X
|
||||
// Y := min(DV, D - X)
|
||||
x := sdk.MinInt(delegatedFree, coin.Amount)
|
||||
y := coin.Amount.Sub(x)
|
||||
y := sdk.MinInt(delegatedVesting, coin.Amount.Sub(x))
|
||||
|
||||
if !x.IsZero() {
|
||||
xCoin := sdk.NewCoin(coin.Denom, x)
|
||||
|
|
|
@ -47,7 +47,13 @@ func NewBaseKeeper(ak auth.AccountKeeper,
|
|||
}
|
||||
|
||||
// SetCoins sets the coins at the addr.
|
||||
func (keeper BaseKeeper) SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) sdk.Error {
|
||||
func (keeper BaseKeeper) SetCoins(
|
||||
ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins,
|
||||
) sdk.Error {
|
||||
|
||||
if !amt.IsValid() {
|
||||
return sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
return setCoins(ctx, keeper.ak, addr, amt)
|
||||
}
|
||||
|
||||
|
@ -56,6 +62,9 @@ func (keeper BaseKeeper) SubtractCoins(
|
|||
ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins,
|
||||
) (sdk.Coins, sdk.Tags, sdk.Error) {
|
||||
|
||||
if !amt.IsValid() {
|
||||
return nil, nil, sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
return subtractCoins(ctx, keeper.ak, addr, amt)
|
||||
}
|
||||
|
||||
|
@ -64,6 +73,9 @@ func (keeper BaseKeeper) AddCoins(
|
|||
ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins,
|
||||
) (sdk.Coins, sdk.Tags, sdk.Error) {
|
||||
|
||||
if !amt.IsValid() {
|
||||
return nil, nil, sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
return addCoins(ctx, keeper.ak, addr, amt)
|
||||
}
|
||||
|
||||
|
@ -78,14 +90,27 @@ func (keeper BaseKeeper) InputOutputCoins(
|
|||
// DelegateCoins performs delegation by deducting amt coins from an account with
|
||||
// address addr. For vesting accounts, delegations amounts are tracked for both
|
||||
// vesting and vested coins.
|
||||
func (keeper BaseKeeper) DelegateCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Tags, sdk.Error) {
|
||||
func (keeper BaseKeeper) DelegateCoins(
|
||||
ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins,
|
||||
) (sdk.Tags, sdk.Error) {
|
||||
|
||||
if !amt.IsValid() {
|
||||
return nil, sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
return delegateCoins(ctx, keeper.ak, addr, amt)
|
||||
}
|
||||
|
||||
// UndelegateCoins performs undelegation by crediting amt coins to an account with
|
||||
// address addr. For vesting accounts, undelegation amounts are tracked for both
|
||||
// vesting and vested coins.
|
||||
func (keeper BaseKeeper) UndelegateCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Tags, sdk.Error) {
|
||||
// If any of the undelegation amounts are negative, an error is returned.
|
||||
func (keeper BaseKeeper) UndelegateCoins(
|
||||
ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins,
|
||||
) (sdk.Tags, sdk.Error) {
|
||||
|
||||
if !amt.IsValid() {
|
||||
return nil, sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
return undelegateCoins(ctx, keeper.ak, addr, amt)
|
||||
}
|
||||
|
||||
|
@ -126,6 +151,10 @@ func NewBaseSendKeeper(ak auth.AccountKeeper,
|
|||
func (keeper BaseSendKeeper) SendCoins(
|
||||
ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins,
|
||||
) (sdk.Tags, sdk.Error) {
|
||||
|
||||
if !amt.IsValid() {
|
||||
return nil, sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
return sendCoins(ctx, keeper.ak, fromAddr, toAddr, amt)
|
||||
}
|
||||
|
||||
|
@ -188,6 +217,9 @@ func getCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress) sdk.C
|
|||
}
|
||||
|
||||
func setCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins) sdk.Error {
|
||||
if !amt.IsValid() {
|
||||
return sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
acc := am.GetAccount(ctx, addr)
|
||||
if acc == nil {
|
||||
acc = am.NewAccountWithAddress(ctx, addr)
|
||||
|
@ -218,6 +250,11 @@ func setAccount(ctx sdk.Context, ak auth.AccountKeeper, acc auth.Account) {
|
|||
//
|
||||
// CONTRACT: If the account is a vesting account, the amount has to be spendable.
|
||||
func subtractCoins(ctx sdk.Context, ak auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) {
|
||||
|
||||
if !amt.IsValid() {
|
||||
return nil, nil, sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
|
||||
oldCoins, spendableCoins := sdk.Coins{}, sdk.Coins{}
|
||||
|
||||
acc := getAccount(ctx, ak, addr)
|
||||
|
@ -244,6 +281,11 @@ func subtractCoins(ctx sdk.Context, ak auth.AccountKeeper, addr sdk.AccAddress,
|
|||
|
||||
// AddCoins adds amt to the coins at the addr.
|
||||
func addCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) {
|
||||
|
||||
if !amt.IsValid() {
|
||||
return nil, nil, sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
|
||||
oldCoins := getCoins(ctx, am, addr)
|
||||
newCoins := oldCoins.Add(amt)
|
||||
|
||||
|
@ -260,9 +302,9 @@ func addCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress, amt s
|
|||
}
|
||||
|
||||
// SendCoins moves coins from one account to another
|
||||
// Returns ErrInvalidCoins if amt is invalid.
|
||||
func sendCoins(ctx sdk.Context, am auth.AccountKeeper, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) (sdk.Tags, sdk.Error) {
|
||||
// Safety check ensuring that when sending coins the keeper must maintain the
|
||||
// supply invariant.
|
||||
if !amt.IsValid() {
|
||||
return nil, sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
|
@ -284,7 +326,7 @@ func sendCoins(ctx sdk.Context, am auth.AccountKeeper, fromAddr sdk.AccAddress,
|
|||
// NOTE: Make sure to revert state changes from tx on error
|
||||
func inputOutputCoins(ctx sdk.Context, am auth.AccountKeeper, inputs []Input, outputs []Output) (sdk.Tags, sdk.Error) {
|
||||
// Safety check ensuring that when sending coins the keeper must maintain the
|
||||
// supply invariant.
|
||||
// Check supply invariant and validity of Coins.
|
||||
if err := ValidateInputsOutputs(inputs, outputs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -314,6 +356,10 @@ func delegateCoins(
|
|||
ctx sdk.Context, ak auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins,
|
||||
) (sdk.Tags, sdk.Error) {
|
||||
|
||||
if !amt.IsValid() {
|
||||
return nil, sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
|
||||
acc := getAccount(ctx, ak, addr)
|
||||
if acc == nil {
|
||||
return nil, sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", addr))
|
||||
|
@ -344,6 +390,10 @@ func undelegateCoins(
|
|||
ctx sdk.Context, ak auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins,
|
||||
) (sdk.Tags, sdk.Error) {
|
||||
|
||||
if !amt.IsValid() {
|
||||
return nil, sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
|
||||
acc := getAccount(ctx, ak, addr)
|
||||
if acc == nil {
|
||||
return nil, sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", addr))
|
||||
|
@ -361,22 +411,24 @@ func undelegateCoins(
|
|||
), nil
|
||||
}
|
||||
|
||||
func trackDelegation(acc auth.Account, blockTime time.Time, amount sdk.Coins) error {
|
||||
// CONTRACT: assumes that amt is valid.
|
||||
func trackDelegation(acc auth.Account, blockTime time.Time, amt sdk.Coins) error {
|
||||
vacc, ok := acc.(auth.VestingAccount)
|
||||
if ok {
|
||||
vacc.TrackDelegation(blockTime, amount)
|
||||
vacc.TrackDelegation(blockTime, amt)
|
||||
return nil
|
||||
}
|
||||
|
||||
return acc.SetCoins(acc.GetCoins().Sub(amount))
|
||||
return acc.SetCoins(acc.GetCoins().Sub(amt))
|
||||
}
|
||||
|
||||
func trackUndelegation(acc auth.Account, amount sdk.Coins) error {
|
||||
// CONTRACT: assumes that amt is valid.
|
||||
func trackUndelegation(acc auth.Account, amt sdk.Coins) error {
|
||||
vacc, ok := acc.(auth.VestingAccount)
|
||||
if ok {
|
||||
vacc.TrackUndelegation(amount)
|
||||
vacc.TrackUndelegation(amt)
|
||||
return nil
|
||||
}
|
||||
|
||||
return acc.SetCoins(acc.GetCoins().Add(amount))
|
||||
return acc.SetCoins(acc.GetCoins().Add(amt))
|
||||
}
|
||||
|
|
|
@ -35,6 +35,9 @@ func (msg MsgSend) ValidateBasic() sdk.Error {
|
|||
if msg.ToAddress.Empty() {
|
||||
return sdk.ErrInvalidAddress("missing recipient address")
|
||||
}
|
||||
if !msg.Amount.IsValid() {
|
||||
return sdk.ErrInvalidCoins("send amount is invalid: " + msg.Amount.String())
|
||||
}
|
||||
if !msg.Amount.IsAllPositive() {
|
||||
return sdk.ErrInsufficientCoins("send amount must be positive")
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
@ -8,6 +10,7 @@ import (
|
|||
|
||||
// allocate fees handles distribution of the collected fees
|
||||
func (k Keeper) AllocateTokens(ctx sdk.Context, sumPrecommitPower, totalPower int64, proposer sdk.ConsAddress, votes []abci.VoteInfo) {
|
||||
logger := ctx.Logger().With("module", "x/distribution")
|
||||
|
||||
// fetch collected fees & fee pool
|
||||
feesCollectedInt := k.feeCollectionKeeper.GetCollectedFees(ctx)
|
||||
|
@ -35,9 +38,20 @@ func (k Keeper) AllocateTokens(ctx sdk.Context, sumPrecommitPower, totalPower in
|
|||
proposerReward := feesCollected.MulDecTruncate(proposerMultiplier)
|
||||
|
||||
// pay proposer
|
||||
remaining := feesCollected
|
||||
proposerValidator := k.stakingKeeper.ValidatorByConsAddr(ctx, proposer)
|
||||
if proposerValidator != nil {
|
||||
k.AllocateTokensToValidator(ctx, proposerValidator, proposerReward)
|
||||
remaining := feesCollected.Sub(proposerReward)
|
||||
remaining = feesCollected.Sub(proposerReward)
|
||||
} else {
|
||||
// proposer can be unknown if say, the unbonding period is 1 block, so
|
||||
// e.g. a validator undelegates at block X, it's removed entirely by
|
||||
// block X+1's endblock, then X+2 we need to refer to the previous
|
||||
// proposer for X+1, but we've forgotten about them.
|
||||
logger.Error(fmt.Sprintf(
|
||||
"WARNING: Attempt to allocate proposer rewards to unknown proposer %s. This should happen only if the proposer unbonded completely within a single block, which generally should not happen except in exceptional circumstances (or fuzz testing). We recommend you investigate immediately.",
|
||||
proposer.String()))
|
||||
}
|
||||
|
||||
// calculate fraction allocated to validators
|
||||
communityTax := k.GetCommunityTax(ctx)
|
||||
|
|
|
@ -107,10 +107,12 @@ func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val sdk.Validator, de
|
|||
k.SetFeePool(ctx, feePool)
|
||||
|
||||
// add coins to user account
|
||||
if !coins.IsZero() {
|
||||
withdrawAddr := k.GetDelegatorWithdrawAddr(ctx, del.GetDelegatorAddr())
|
||||
if _, _, err := k.bankKeeper.AddCoins(ctx, withdrawAddr, coins); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// remove delegator starting info
|
||||
k.DeleteDelegatorStartingInfo(ctx, del.GetValidatorAddr(), del.GetDelegatorAddr())
|
||||
|
|
|
@ -37,6 +37,7 @@ func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr
|
|||
h.k.SetOutstandingRewards(ctx, outstanding.Sub(commission))
|
||||
|
||||
// add to validator account
|
||||
if !coins.IsZero() {
|
||||
accAddr := sdk.AccAddress(valAddr)
|
||||
withdrawAddr := h.k.GetDelegatorWithdrawAddr(ctx, accAddr)
|
||||
|
||||
|
@ -44,6 +45,7 @@ func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr
|
|||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// remove commission record
|
||||
h.k.DeleteValidatorAccumulatedCommission(ctx, valAddr)
|
||||
|
||||
|
|
|
@ -87,12 +87,14 @@ func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddr
|
|||
outstanding := k.GetOutstandingRewards(ctx)
|
||||
k.SetOutstandingRewards(ctx, outstanding.Sub(sdk.NewDecCoins(coins)))
|
||||
|
||||
if !coins.IsZero() {
|
||||
accAddr := sdk.AccAddress(valAddr)
|
||||
withdrawAddr := k.GetDelegatorWithdrawAddr(ctx, accAddr)
|
||||
|
||||
if _, _, err := k.bankKeeper.AddCoins(ctx, withdrawAddr, coins); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -183,7 +183,7 @@ func randomDeposit(r *rand.Rand) sdk.Coins {
|
|||
// Pick a random proposal ID
|
||||
func randomProposalID(r *rand.Rand, k gov.Keeper, ctx sdk.Context) (proposalID uint64, ok bool) {
|
||||
lastProposalID := k.GetLastProposalID(ctx)
|
||||
if lastProposalID < 1 {
|
||||
if lastProposalID < 1 || lastProposalID == (2<<63-1) {
|
||||
return 0, false
|
||||
}
|
||||
proposalID = uint64(r.Intn(1+int(lastProposalID)) - 1)
|
||||
|
|
|
@ -44,6 +44,7 @@ func handleIBCReceiveMsg(ctx sdk.Context, ibcm Mapper, ck BankKeeper, msg MsgIBC
|
|||
return ErrInvalidSequence(ibcm.codespace).Result()
|
||||
}
|
||||
|
||||
// XXX Check that packet.Coins is valid and positive (nonzero)
|
||||
_, _, err := ck.AddCoins(ctx, packet.DestAddr, packet.Coins)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
|
|
|
@ -17,6 +17,14 @@ type mockValidator struct {
|
|||
livenessState int
|
||||
}
|
||||
|
||||
func (mv mockValidator) String() string {
|
||||
return fmt.Sprintf("mockValidator{%s:%X power:%v state:%v}",
|
||||
mv.val.PubKey.Type,
|
||||
mv.val.PubKey.Data,
|
||||
mv.val.Power,
|
||||
mv.livenessState)
|
||||
}
|
||||
|
||||
type mockValidators map[string]mockValidator
|
||||
|
||||
// get mockValidators from abci validators
|
||||
|
|
|
@ -37,13 +37,32 @@ func RandStringOfLength(r *rand.Rand, n int) string {
|
|||
}
|
||||
|
||||
// Generate a random amount
|
||||
// Note: The range of RandomAmount includes max, and is, in fact, biased to return max as well as 0.
|
||||
func RandomAmount(r *rand.Rand, max sdk.Int) sdk.Int {
|
||||
return sdk.NewInt(int64(r.Intn(int(max.Int64()))))
|
||||
var randInt = big.NewInt(0)
|
||||
switch r.Intn(10) {
|
||||
case 0:
|
||||
// randInt = big.NewInt(0)
|
||||
case 1:
|
||||
randInt = max.BigInt()
|
||||
default: // NOTE: there are 10 total cases.
|
||||
randInt = big.NewInt(0).Rand(r, max.BigInt()) // up to max - 1
|
||||
}
|
||||
return sdk.NewIntFromBigInt(randInt)
|
||||
}
|
||||
|
||||
// RandomDecAmount generates a random decimal amount
|
||||
// Note: The range of RandomDecAmount includes max, and is, in fact, biased to return max as well as 0.
|
||||
func RandomDecAmount(r *rand.Rand, max sdk.Dec) sdk.Dec {
|
||||
randInt := big.NewInt(0).Rand(r, max.Int)
|
||||
var randInt = big.NewInt(0)
|
||||
switch r.Intn(10) {
|
||||
case 0:
|
||||
// randInt = big.NewInt(0)
|
||||
case 1:
|
||||
randInt = max.Int // the underlying big int with all precision bits.
|
||||
default: // NOTE: there are 10 total cases.
|
||||
randInt = big.NewInt(0).Rand(r, max.Int)
|
||||
}
|
||||
return sdk.NewDecFromBigIntWithPrec(randInt, sdk.Precision)
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,16 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio
|
|||
consAddr := sdk.ConsAddress(addr)
|
||||
pubkey, err := k.getPubkey(ctx, addr)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))
|
||||
// Ignore evidence that cannot be handled.
|
||||
// NOTE:
|
||||
// We used to panic with:
|
||||
// `panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))`,
|
||||
// but this couples the expectations of the app to both Tendermint and
|
||||
// the simulator. Both are expected to provide the full range of
|
||||
// allowable but none of the disallowed evidence types. Instead of
|
||||
// getting this coordination right, it is easier to relax the
|
||||
// constraints and ignore evidence that cannot be handled.
|
||||
return
|
||||
}
|
||||
|
||||
// Reject evidence if the double-sign is too old
|
||||
|
@ -154,7 +163,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
|
|||
}
|
||||
|
||||
if missed {
|
||||
logger.Info(fmt.Sprintf("Absent validator %s at height %d, %d missed, threshold %d", addr, height, signInfo.MissedBlocksCounter, k.MinSignedPerWindow(ctx)))
|
||||
logger.Info(fmt.Sprintf("Absent validator %s (%v) at height %d, %d missed, threshold %d", addr, pubkey, height, signInfo.MissedBlocksCounter, k.MinSignedPerWindow(ctx)))
|
||||
}
|
||||
|
||||
minHeight := signInfo.StartHeight + k.SignedBlocksWindow(ctx)
|
||||
|
|
|
@ -207,7 +207,7 @@ func TestUnbondDelegation(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUnbondingDelegationsMaxEntries(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1)
|
||||
pool := keeper.GetPool(ctx)
|
||||
startTokens := sdk.TokensFromTendermintPower(10)
|
||||
pool.NotBondedTokens = startTokens
|
||||
|
@ -372,7 +372,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUndelegateFromUnbondedValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1)
|
||||
pool := keeper.GetPool(ctx)
|
||||
startTokens := sdk.TokensFromTendermintPower(20)
|
||||
pool.NotBondedTokens = startTokens
|
||||
|
|
|
@ -30,11 +30,11 @@ func TestPool(t *testing.T) {
|
|||
|
||||
//check that the empty keeper loads the default
|
||||
resPool := keeper.GetPool(ctx)
|
||||
require.True(t, expPool.Equal(resPool))
|
||||
require.Equal(t, expPool, resPool)
|
||||
|
||||
//modify a params, save, and retrieve
|
||||
expPool.BondedTokens = sdk.NewInt(777)
|
||||
keeper.SetPool(ctx, expPool)
|
||||
resPool = keeper.GetPool(ctx)
|
||||
require.True(t, expPool.Equal(resPool))
|
||||
require.Equal(t, expPool, resPool)
|
||||
}
|
||||
|
|
|
@ -74,8 +74,9 @@ func MakeTestCodec() *codec.Codec {
|
|||
return cdc
|
||||
}
|
||||
|
||||
// hogpodge of all sorts of input required for testing
|
||||
// init power is converted to an amount of tokens
|
||||
// Hogpodge of all sorts of input required for testing.
|
||||
// `initPower` is converted to an amount of tokens.
|
||||
// If `initPower` is 0, no addrs get created.
|
||||
func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context, auth.AccountKeeper, Keeper) {
|
||||
|
||||
initCoins := sdk.TokensFromTendermintPower(initPower)
|
||||
|
@ -128,9 +129,12 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context
|
|||
// fill all the addresses with some coins, set the loose pool tokens simultaneously
|
||||
for _, addr := range Addrs {
|
||||
pool := keeper.GetPool(ctx)
|
||||
_, _, err := ck.AddCoins(ctx, addr, sdk.Coins{
|
||||
err := error(nil)
|
||||
if !initCoins.IsZero() {
|
||||
_, _, err = ck.AddCoins(ctx, addr, sdk.Coins{
|
||||
{keeper.BondDenom(ctx), initCoins},
|
||||
})
|
||||
}
|
||||
require.Nil(t, err)
|
||||
pool.NotBondedTokens = pool.NotBondedTokens.Add(initCoins)
|
||||
keeper.SetPool(ctx, pool)
|
||||
|
|
|
@ -82,6 +82,9 @@ func SimulateMsgEditValidator(k staking.Keeper) simulation.Operation {
|
|||
Details: simulation.RandStringOfLength(r, 10),
|
||||
}
|
||||
|
||||
if len(k.GetAllValidators(ctx)) == 0 {
|
||||
return noOperation, nil, nil
|
||||
}
|
||||
val := keeper.RandomValidator(r, k, ctx)
|
||||
address := val.GetOperator()
|
||||
newCommissionRate := simulation.RandomDecAmount(r, val.Commission.MaxRate)
|
||||
|
@ -110,6 +113,9 @@ func SimulateMsgDelegate(m auth.AccountKeeper, k staking.Keeper) simulation.Oper
|
|||
action string, fOp []simulation.FutureOperation, err error) {
|
||||
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
if len(k.GetAllValidators(ctx)) == 0 {
|
||||
return noOperation, nil, nil
|
||||
}
|
||||
val := keeper.RandomValidator(r, k, ctx)
|
||||
validatorAddress := val.GetOperator()
|
||||
delegatorAcc := simulation.RandomAcc(r, accs)
|
||||
|
@ -119,7 +125,7 @@ func SimulateMsgDelegate(m auth.AccountKeeper, k staking.Keeper) simulation.Oper
|
|||
amount = simulation.RandomAmount(r, amount)
|
||||
}
|
||||
if amount.Equal(sdk.ZeroInt()) {
|
||||
return "no-operation", nil, nil
|
||||
return noOperation, nil, nil
|
||||
}
|
||||
|
||||
msg := staking.NewMsgDelegate(
|
||||
|
@ -186,6 +192,9 @@ func SimulateMsgBeginRedelegate(m auth.AccountKeeper, k staking.Keeper) simulati
|
|||
action string, fOp []simulation.FutureOperation, err error) {
|
||||
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
if len(k.GetAllValidators(ctx)) == 0 {
|
||||
return noOperation, nil, nil
|
||||
}
|
||||
srcVal := keeper.RandomValidator(r, k, ctx)
|
||||
srcValidatorAddress := srcVal.GetOperator()
|
||||
destVal := keeper.RandomValidator(r, k, ctx)
|
||||
|
|
Loading…
Reference in New Issue