2018-07-17 11:50:30 -07:00
package simulation
import (
"testing"
"github.com/stretchr/testify/require"
"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
func AllInvariants ( ck bank . Keeper , k stake . Keeper , am auth . AccountMapper ) simulation . Invariant {
return func ( t * testing . T , app * baseapp . BaseApp , log string ) {
SupplyInvariants ( ck , k , am ) ( t , app , log )
PositivePowerInvariant ( k ) ( t , app , log )
ValidatorSetInvariant ( k ) ( t , app , log )
}
}
// SupplyInvariants checks that the total supply reflects all held loose tokens, bonded tokens, and unbonding delegations
func SupplyInvariants ( ck bank . Keeper , k stake . Keeper , am auth . AccountMapper ) simulation . Invariant {
return func ( t * testing . T , app * baseapp . BaseApp , log string ) {
ctx := app . NewContext ( false , abci . Header { } )
2018-08-17 07:19:33 -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-08-17 07:19:33 -07:00
// XXX TODO https://github.com/cosmos/cosmos-sdk/issues/2063#issuecomment-413720872
// require.True(t, pool.LooseTokens.RoundInt64() == loose.Int64(), "expected loose tokens to equal total steak held by accounts - pool.LooseTokens: %v, sum of account tokens: %v\nlog: %s",
// pool.LooseTokens.RoundInt64(), loose.Int64(), log)
2018-07-18 00:42:18 -07:00
// Bonded tokens should equal sum of tokens with bonded validators
2018-08-17 07:19:33 -07:00
// XXX TODO https://github.com/cosmos/cosmos-sdk/issues/2063#issuecomment-413720872
// require.True(t, pool.BondedTokens.RoundInt64() == bonded.RoundInt64(), "expected bonded tokens to equal total steak held by bonded validators - pool.BondedTokens: %v, sum of bonded validator tokens: %v\nlog: %s",
// pool.BondedTokens.RoundInt64(), bonded.RoundInt64(), log)
2018-07-17 11:50:30 -07:00
// TODO Inflation check on total supply
}
}
// PositivePowerInvariant checks that all stored validators have > 0 power
func PositivePowerInvariant ( k stake . Keeper ) simulation . Invariant {
return func ( t * testing . T , app * baseapp . BaseApp , log string ) {
ctx := app . NewContext ( false , abci . Header { } )
k . IterateValidatorsBonded ( ctx , func ( _ int64 , validator sdk . Validator ) bool {
2018-08-14 17:15:02 -07:00
require . True ( t , validator . GetPower ( ) . GT ( sdk . ZeroDec ( ) ) , "validator with non-positive power stored" )
2018-07-17 11:50:30 -07:00
return false
} )
}
}
// ValidatorSetInvariant checks equivalence of Tendermint validator set and SDK validator set
func ValidatorSetInvariant ( k stake . Keeper ) simulation . Invariant {
return func ( t * testing . T , app * baseapp . BaseApp , log string ) {
// TODO
}
}