Invariants & random Msgs in progress

This commit is contained in:
Christopher Goes 2018-07-11 02:36:50 +02:00
parent a33229380b
commit 940cfa98af
3 changed files with 148 additions and 7 deletions

View File

@ -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,
}
}

View File

@ -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)
}

View File

@ -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{