2018-07-17 11:50:30 -07:00
package simulation
import (
2018-09-09 08:34:09 -07:00
"fmt"
2018-07-17 11:50:30 -07:00
"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/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
2018-10-20 23:22:48 -07:00
func AllInvariants ( ck bank . Keeper , k stake . Keeper , am auth . AccountKeeper ) simulation . Invariant {
2018-09-09 08:34:09 -07:00
return func ( app * baseapp . BaseApp ) error {
err := SupplyInvariants ( ck , k , am ) ( app )
if err != nil {
return err
}
err = PositivePowerInvariant ( k ) ( app )
if err != nil {
return err
}
err = ValidatorSetInvariant ( k ) ( app )
return err
2018-07-17 11:50:30 -07:00
}
}
// SupplyInvariants checks that the total supply reflects all held loose tokens, bonded tokens, and unbonding delegations
2018-08-31 15:22:37 -07:00
// nolint: unparam
2018-10-20 23:22:48 -07:00
func SupplyInvariants ( ck bank . Keeper , k stake . Keeper , am auth . AccountKeeper ) simulation . Invariant {
2018-09-09 08:34:09 -07:00
return func ( app * baseapp . BaseApp ) error {
2018-07-17 11:50:30 -07:00
ctx := app . NewContext ( false , abci . Header { } )
2018-09-27 06:52:30 -07:00
pool := k . GetPool ( ctx )
2018-07-17 11:50:30 -07:00
loose := sdk . ZeroInt ( )
2018-08-14 17:15:02 -07:00
bonded := sdk . ZeroDec ( )
2018-07-17 11:50:30 -07:00
am . IterateAccounts ( ctx , func ( acc auth . Account ) bool {
loose = loose . Add ( acc . GetCoins ( ) . AmountOf ( "steak" ) )
return false
} )
2018-07-17 22:37:38 -07:00
k . IterateUnbondingDelegations ( ctx , func ( _ int64 , ubd stake . UnbondingDelegation ) bool {
loose = loose . Add ( ubd . Balance . Amount )
return false
} )
2018-07-17 11:50:30 -07:00
k . IterateValidators ( ctx , func ( _ int64 , validator sdk . Validator ) bool {
switch validator . GetStatus ( ) {
case sdk . Bonded :
bonded = bonded . Add ( validator . GetPower ( ) )
2018-07-18 00:42:18 -07:00
case sdk . Unbonding :
2018-08-26 21:38:31 -07:00
loose = loose . Add ( validator . GetTokens ( ) . RoundInt ( ) )
2018-07-18 00:42:18 -07:00
case sdk . Unbonded :
loose = loose . Add ( validator . GetTokens ( ) . RoundInt ( ) )
2018-07-17 11:50:30 -07:00
}
return false
} )
2018-07-18 00:42:18 -07:00
// Loose tokens should equal coin supply plus unbonding delegations plus tokens on unbonded validators
2018-09-27 06:52:30 -07:00
if pool . LooseTokens . RoundInt64 ( ) != loose . Int64 ( ) {
return fmt . Errorf ( "expected loose tokens to equal total steak held by accounts - pool.LooseTokens: %v, sum of account tokens: %v" , pool . LooseTokens . RoundInt64 ( ) , loose . Int64 ( ) )
}
2018-07-18 00:42:18 -07:00
// Bonded tokens should equal sum of tokens with bonded validators
2018-09-27 06:52:30 -07:00
if pool . BondedTokens . RoundInt64 ( ) != bonded . RoundInt64 ( ) {
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 . RoundInt64 ( ) , bonded . RoundInt64 ( ) )
}
2018-07-17 11:50:30 -07:00
// TODO Inflation check on total supply
2018-09-09 08:34:09 -07:00
return nil
2018-07-17 11:50:30 -07:00
}
}
// PositivePowerInvariant checks that all stored validators have > 0 power
func PositivePowerInvariant ( k stake . Keeper ) simulation . Invariant {
2018-09-09 08:34:09 -07:00
return func ( app * baseapp . BaseApp ) error {
2018-07-17 11:50:30 -07:00
ctx := app . NewContext ( false , abci . Header { } )
2018-09-09 08:34:09 -07:00
var err error
2018-07-17 11:50:30 -07:00
k . IterateValidatorsBonded ( ctx , func ( _ int64 , validator sdk . Validator ) bool {
2018-09-09 08:34:09 -07:00
if ! validator . GetPower ( ) . GT ( sdk . ZeroDec ( ) ) {
2018-09-24 21:09:31 -07:00
err = fmt . Errorf ( "validator with non-positive power stored. (pubkey %v)" , validator . GetConsPubKey ( ) )
2018-09-09 08:34:09 -07:00
return true
}
2018-07-17 11:50:30 -07:00
return false
} )
2018-09-09 08:34:09 -07:00
return err
2018-07-17 11:50:30 -07:00
}
}
// ValidatorSetInvariant checks equivalence of Tendermint validator set and SDK validator set
func ValidatorSetInvariant ( k stake . Keeper ) simulation . Invariant {
2018-09-09 08:34:09 -07:00
return func ( app * baseapp . BaseApp ) error {
2018-07-17 11:50:30 -07:00
// TODO
2018-09-09 08:34:09 -07:00
return nil
2018-07-17 11:50:30 -07:00
}
}