-
Notifications
You must be signed in to change notification settings - Fork 0
/
invariants.go
113 lines (99 loc) · 3.81 KB
/
invariants.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package simulation
import (
"fmt"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
"github.com/cosmos/cosmos-sdk/x/stake"
abci "github.com/tendermint/tendermint/abci/types"
)
// AllInvariants runs all invariants of the stake module.
// Currently: total supply, positive power
func AllInvariants(ck bank.Keeper, k stake.Keeper, d distribution.Keeper, am auth.AccountKeeper) simulation.Invariant {
return func(app *baseapp.BaseApp) error {
err := SupplyInvariants(ck, k, d, am)(app)
if err != nil {
return err
}
err = PositivePowerInvariant(k)(app)
if err != nil {
return err
}
err = ValidatorSetInvariant(k)(app)
return err
}
}
// SupplyInvariants checks that the total supply reflects all held loose tokens, bonded tokens, and unbonding delegations
// nolint: unparam
func SupplyInvariants(ck bank.Keeper, k stake.Keeper, d distribution.Keeper, am auth.AccountKeeper) simulation.Invariant {
return func(app *baseapp.BaseApp) error {
ctx := app.NewContext(sdk.RunTxModeDeliver, abci.Header{})
pool := k.GetPool(ctx)
loose := sdk.ZeroDec()
bonded := sdk.ZeroDec()
am.IterateAccounts(ctx, func(acc sdk.Account) bool {
loose = loose.Add(sdk.NewDecFromInt(acc.GetCoins().AmountOf("steak")))
return false
})
k.IterateUnbondingDelegations(ctx, func(_ int64, ubd stake.UnbondingDelegation) bool {
loose = loose.Add(sdk.NewDecFromInt(ubd.Balance.Amount))
return false
})
k.IterateValidators(ctx, func(_ int64, validator sdk.Validator) bool {
switch validator.GetStatus() {
case sdk.Bonded:
bonded = bonded.Add(validator.GetPower())
case sdk.Unbonding:
loose = loose.Add(validator.GetTokens())
case sdk.Unbonded:
loose = loose.Add(validator.GetTokens())
}
return false
})
feePool := d.GetFeePool(ctx)
// add community pool
loose = loose.Add(feePool.CommunityPool.AmountOf("steak"))
// add validator distribution pool
loose = loose.Add(feePool.Pool.AmountOf("steak"))
// add validator distribution commission and yet-to-be-withdrawn-by-delegators
d.IterateValidatorDistInfos(ctx, func(_ int64, distInfo distribution.ValidatorDistInfo) (stop bool) {
loose = loose.Add(distInfo.Pool.AmountOf("steak"))
loose = loose.Add(distInfo.PoolCommission.AmountOf("steak"))
return false
})
// Loose tokens should equal coin supply plus unbonding delegations plus tokens on unbonded validators
if !pool.LooseTokens.Equal(loose) {
return fmt.Errorf("expected loose tokens to equal total steak held by accounts - pool.LooseTokens: %v, sum of account tokens: %v", pool.LooseTokens, loose)
}
// Bonded tokens should equal sum of tokens with bonded validators
if !pool.BondedTokens.Equal(bonded) {
return fmt.Errorf("expected bonded tokens to equal total steak held by bonded validators - pool.BondedTokens: %v, sum of bonded validator tokens: %v", pool.BondedTokens, bonded)
}
return nil
}
}
// PositivePowerInvariant checks that all stored validators have > 0 power
func PositivePowerInvariant(k stake.Keeper) simulation.Invariant {
return func(app *baseapp.BaseApp) error {
ctx := app.NewContext(sdk.RunTxModeDeliver, abci.Header{})
var err error
k.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) bool {
if !validator.GetPower().GT(sdk.ZeroDec()) {
err = fmt.Errorf("validator with non-positive power stored. (pubkey %v)", validator.GetConsPubKey())
return true
}
return false
})
return err
}
}
// ValidatorSetInvariant checks equivalence of Tendermint validator set and SDK validator set
func ValidatorSetInvariant(k stake.Keeper) simulation.Invariant {
return func(app *baseapp.BaseApp) error {
// TODO
return nil
}
}