Invariants & random Msgs in progress
This commit is contained in:
parent
a33229380b
commit
940cfa98af
|
@ -15,9 +15,13 @@ type Coin struct {
|
|||
}
|
||||
|
||||
func NewCoin(denom string, amount int64) Coin {
|
||||
return NewIntCoin(denom, NewInt(amount))
|
||||
}
|
||||
|
||||
func NewIntCoin(denom string, amount Int) Coin {
|
||||
return Coin{
|
||||
Denom: denom,
|
||||
Amount: NewInt(amount),
|
||||
Amount: amount,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -135,3 +135,29 @@ func RandFromBigInterval(r *rand.Rand, intervals []BigInterval) sdk.Int {
|
|||
|
||||
return result
|
||||
}
|
||||
|
||||
// shamelessly copied from https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang#31832326
|
||||
|
||||
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
const (
|
||||
letterIdxBits = 6 // 6 bits to represent a letter index
|
||||
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
||||
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
||||
)
|
||||
|
||||
func RandStringOfLength(r *rand.Rand, n int) string {
|
||||
b := make([]byte, n)
|
||||
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
|
||||
for i, cache, remain := n-1, r.Int63(), letterIdxMax; i >= 0; {
|
||||
if remain == 0 {
|
||||
cache, remain = r.Int63(), letterIdxMax
|
||||
}
|
||||
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
||||
b[i] = letterBytes[idx]
|
||||
i--
|
||||
}
|
||||
cache >>= letterIdxBits
|
||||
remain--
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
|
|
@ -20,13 +20,14 @@ import (
|
|||
// Currently: total supply, positive power
|
||||
func ModuleInvariants(ck bank.Keeper, k Keeper) mock.Invariant {
|
||||
return func(t *testing.T, app *mock.App, log string) {
|
||||
TotalSupplyInvariant(ck, k)(t, app, log)
|
||||
SupplyInvariants(ck, k)(t, app, log)
|
||||
PositivePowerInvariant(k)(t, app, log)
|
||||
ValidatorSetInvariant(k)(t, app, log)
|
||||
}
|
||||
}
|
||||
|
||||
// TotalSupplyInvariant checks that the total supply reflects all held loose tokens, bonded tokens, and unbonding delegations
|
||||
func TotalSupplyInvariant(ck bank.Keeper, k Keeper) mock.Invariant {
|
||||
// SupplyInvariants checks that the total supply reflects all held loose tokens, bonded tokens, and unbonding delegations
|
||||
func SupplyInvariants(ck bank.Keeper, k Keeper) mock.Invariant {
|
||||
return func(t *testing.T, app *mock.App, log string) {
|
||||
ctx := app.NewContext(false, abci.Header{})
|
||||
pool := k.GetPool(ctx)
|
||||
|
@ -40,8 +41,26 @@ func TotalSupplyInvariant(ck bank.Keeper, k Keeper) mock.Invariant {
|
|||
require.True(t, sdk.NewInt(pool.LooseTokens).Equal(loose), "expected loose tokens to equal total steak held by accounts")
|
||||
|
||||
// Bonded tokens should equal sum of tokens with bonded validators
|
||||
|
||||
// Unbonded tokens should equal sum of tokens with unbonded validators
|
||||
bonded := sdk.ZeroRat()
|
||||
unbonded := sdk.ZeroRat()
|
||||
k.IterateValidators(ctx, func(_ int64, validator sdk.Validator) bool {
|
||||
switch validator.GetStatus() {
|
||||
case sdk.Bonded:
|
||||
bonded = bonded.Add(validator.GetPower())
|
||||
case sdk.Unbonding:
|
||||
// TODO
|
||||
case sdk.Unbonded:
|
||||
unbonded = unbonded.Add(validator.GetPower())
|
||||
}
|
||||
return false
|
||||
})
|
||||
require.True(t, sdk.NewRat(pool.BondedTokens).Equal(bonded), "expected bonded tokens to equal total steak held by bonded validators")
|
||||
require.True(t, sdk.NewRat(pool.UnbondedTokens).Equal(unbonded), "expected unbonded tokens to equal total steak held by unbonded validators")
|
||||
|
||||
// TODO Unbonding tokens
|
||||
|
||||
// TODO Inflation check on total supply
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,6 +75,59 @@ func PositivePowerInvariant(k Keeper) mock.Invariant {
|
|||
}
|
||||
}
|
||||
|
||||
// ValidatorSetInvariant checks equivalence of Tendermint validator set and SDK validator set
|
||||
func ValidatorSetInvariant(k Keeper) mock.Invariant {
|
||||
return func(t *testing.T, app *mock.App, log string) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
// SimulateMsgCreateValidator
|
||||
func SimulateMsgCreateValidator(m auth.AccountMapper, k Keeper) mock.TestAndRunMsg {
|
||||
return func(t *testing.T, r *rand.Rand, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
description := Description{
|
||||
Moniker: mock.RandStringOfLength(r, 10),
|
||||
}
|
||||
key := keys[r.Intn(len(keys))]
|
||||
pubkey := key.PubKey()
|
||||
address := sdk.AccAddress(pubkey.Address())
|
||||
amount := m.GetAccount(ctx, address).GetCoins().AmountOf(denom)
|
||||
if amount.GT(sdk.ZeroInt()) {
|
||||
amount = sdk.NewInt(int64(r.Intn(int(amount.Int64()))))
|
||||
}
|
||||
msg := MsgCreateValidator{
|
||||
Description: description,
|
||||
ValidatorAddr: address,
|
||||
PubKey: pubkey,
|
||||
SelfDelegation: sdk.NewIntCoin(denom, amount),
|
||||
}
|
||||
action = fmt.Sprintf("TestMsgCreateValidator: %s", msg.GetSignBytes())
|
||||
return action, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SimulateMsgEditValidator
|
||||
func SimulateMsgEditValidator(k Keeper) mock.TestAndRunMsg {
|
||||
return func(t *testing.T, r *rand.Rand, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
description := Description{
|
||||
Moniker: mock.RandStringOfLength(r, 10),
|
||||
Identity: mock.RandStringOfLength(r, 10),
|
||||
Website: mock.RandStringOfLength(r, 10),
|
||||
Details: mock.RandStringOfLength(r, 10),
|
||||
}
|
||||
key := keys[r.Intn(len(keys))]
|
||||
pubkey := key.PubKey()
|
||||
address := sdk.AccAddress(pubkey.Address())
|
||||
msg := MsgEditValidator{
|
||||
Description: description,
|
||||
ValidatorAddr: address,
|
||||
}
|
||||
action = fmt.Sprintf("TestMsgEditValidator: %s", msg.GetSignBytes())
|
||||
return action, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SimulateMsgDelegate
|
||||
func SimulateMsgDelegate(k Keeper) mock.TestAndRunMsg {
|
||||
return func(t *testing.T, r *rand.Rand, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
|
@ -64,6 +136,38 @@ func SimulateMsgDelegate(k Keeper) mock.TestAndRunMsg {
|
|||
}
|
||||
}
|
||||
|
||||
// SimulateMsgBeginUnbonding
|
||||
func SimulateMsgBeginUnbonding(k Keeper) mock.TestAndRunMsg {
|
||||
return func(t *testing.T, r *rand.Rand, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
msg := fmt.Sprintf("TestMsgBeginUnbonding with %s", "ok")
|
||||
return msg, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SimulateMsgCompleteUnbonding
|
||||
func SimulateMsgCompleteUnbonding(k Keeper) mock.TestAndRunMsg {
|
||||
return func(t *testing.T, r *rand.Rand, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
msg := fmt.Sprintf("TestMsgCompleteUnbonding with %s", "ok")
|
||||
return msg, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SimulateMsgBeginRedelegate
|
||||
func SimulateMsgBeginRedelegate(k Keeper) mock.TestAndRunMsg {
|
||||
return func(t *testing.T, r *rand.Rand, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
msg := fmt.Sprintf("TestMsgBeginRedelegate with %s", "ok")
|
||||
return msg, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SimulateMsgCompleteRedelegate
|
||||
func SimulateMsgCompleteRedelegate(k Keeper) mock.TestAndRunMsg {
|
||||
return func(t *testing.T, r *rand.Rand, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
msg := fmt.Sprintf("TestMsgCompleteRedelegate with %s", "ok")
|
||||
return msg, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SimulationSetup
|
||||
func SimulationSetup(mapp *mock.App, k Keeper) mock.RandSetup {
|
||||
return func(r *rand.Rand, privKeys []crypto.PrivKey) {
|
||||
|
@ -72,12 +176,13 @@ func SimulationSetup(mapp *mock.App, k Keeper) mock.RandSetup {
|
|||
}
|
||||
}
|
||||
|
||||
// Test random messages
|
||||
// TestStakeWithRandomMessages
|
||||
func TestStakeWithRandomMessages(t *testing.T) {
|
||||
mapp := mock.NewApp()
|
||||
|
||||
bank.RegisterWire(mapp.Cdc)
|
||||
coinKeeper := bank.NewKeeper(mapp.AccountMapper)
|
||||
mapper := mapp.AccountMapper
|
||||
coinKeeper := bank.NewKeeper(mapper)
|
||||
stakeKey := sdk.NewKVStoreKey("stake")
|
||||
stakeKeeper := NewKeeper(mapp.Cdc, stakeKey, coinKeeper, DefaultCodespace)
|
||||
mapp.Router().AddRoute("stake", NewHandler(stakeKeeper))
|
||||
|
@ -89,7 +194,13 @@ func TestStakeWithRandomMessages(t *testing.T) {
|
|||
|
||||
mapp.SimpleRandomizedTestingFromSeed(
|
||||
t, 20, []mock.TestAndRunMsg{
|
||||
SimulateMsgCreateValidator(mapper, stakeKeeper),
|
||||
SimulateMsgEditValidator(stakeKeeper),
|
||||
SimulateMsgDelegate(stakeKeeper),
|
||||
SimulateMsgBeginUnbonding(stakeKeeper),
|
||||
SimulateMsgCompleteUnbonding(stakeKeeper),
|
||||
SimulateMsgBeginRedelegate(stakeKeeper),
|
||||
SimulateMsgCompleteRedelegate(stakeKeeper),
|
||||
}, []mock.RandSetup{
|
||||
SimulationSetup(mapp, stakeKeeper),
|
||||
}, []mock.Invariant{
|
||||
|
|
Loading…
Reference in New Issue