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 {
|
func NewCoin(denom string, amount int64) Coin {
|
||||||
|
return NewIntCoin(denom, NewInt(amount))
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIntCoin(denom string, amount Int) Coin {
|
||||||
return Coin{
|
return Coin{
|
||||||
Denom: denom,
|
Denom: denom,
|
||||||
Amount: NewInt(amount),
|
Amount: amount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,3 +135,29 @@ func RandFromBigInterval(r *rand.Rand, intervals []BigInterval) sdk.Int {
|
||||||
|
|
||||||
return result
|
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
|
// Currently: total supply, positive power
|
||||||
func ModuleInvariants(ck bank.Keeper, k Keeper) mock.Invariant {
|
func ModuleInvariants(ck bank.Keeper, k Keeper) mock.Invariant {
|
||||||
return func(t *testing.T, app *mock.App, log string) {
|
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)
|
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
|
// SupplyInvariants checks that the total supply reflects all held loose tokens, bonded tokens, and unbonding delegations
|
||||||
func TotalSupplyInvariant(ck bank.Keeper, k Keeper) mock.Invariant {
|
func SupplyInvariants(ck bank.Keeper, k Keeper) mock.Invariant {
|
||||||
return func(t *testing.T, app *mock.App, log string) {
|
return func(t *testing.T, app *mock.App, log string) {
|
||||||
ctx := app.NewContext(false, abci.Header{})
|
ctx := app.NewContext(false, abci.Header{})
|
||||||
pool := k.GetPool(ctx)
|
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")
|
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
|
// Bonded tokens should equal sum of tokens with bonded validators
|
||||||
|
|
||||||
// Unbonded tokens should equal sum of tokens with unbonded 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
|
// SimulateMsgDelegate
|
||||||
func SimulateMsgDelegate(k Keeper) mock.TestAndRunMsg {
|
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) {
|
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
|
// SimulationSetup
|
||||||
func SimulationSetup(mapp *mock.App, k Keeper) mock.RandSetup {
|
func SimulationSetup(mapp *mock.App, k Keeper) mock.RandSetup {
|
||||||
return func(r *rand.Rand, privKeys []crypto.PrivKey) {
|
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) {
|
func TestStakeWithRandomMessages(t *testing.T) {
|
||||||
mapp := mock.NewApp()
|
mapp := mock.NewApp()
|
||||||
|
|
||||||
bank.RegisterWire(mapp.Cdc)
|
bank.RegisterWire(mapp.Cdc)
|
||||||
coinKeeper := bank.NewKeeper(mapp.AccountMapper)
|
mapper := mapp.AccountMapper
|
||||||
|
coinKeeper := bank.NewKeeper(mapper)
|
||||||
stakeKey := sdk.NewKVStoreKey("stake")
|
stakeKey := sdk.NewKVStoreKey("stake")
|
||||||
stakeKeeper := NewKeeper(mapp.Cdc, stakeKey, coinKeeper, DefaultCodespace)
|
stakeKeeper := NewKeeper(mapp.Cdc, stakeKey, coinKeeper, DefaultCodespace)
|
||||||
mapp.Router().AddRoute("stake", NewHandler(stakeKeeper))
|
mapp.Router().AddRoute("stake", NewHandler(stakeKeeper))
|
||||||
|
@ -89,7 +194,13 @@ func TestStakeWithRandomMessages(t *testing.T) {
|
||||||
|
|
||||||
mapp.SimpleRandomizedTestingFromSeed(
|
mapp.SimpleRandomizedTestingFromSeed(
|
||||||
t, 20, []mock.TestAndRunMsg{
|
t, 20, []mock.TestAndRunMsg{
|
||||||
|
SimulateMsgCreateValidator(mapper, stakeKeeper),
|
||||||
|
SimulateMsgEditValidator(stakeKeeper),
|
||||||
SimulateMsgDelegate(stakeKeeper),
|
SimulateMsgDelegate(stakeKeeper),
|
||||||
|
SimulateMsgBeginUnbonding(stakeKeeper),
|
||||||
|
SimulateMsgCompleteUnbonding(stakeKeeper),
|
||||||
|
SimulateMsgBeginRedelegate(stakeKeeper),
|
||||||
|
SimulateMsgCompleteRedelegate(stakeKeeper),
|
||||||
}, []mock.RandSetup{
|
}, []mock.RandSetup{
|
||||||
SimulationSetup(mapp, stakeKeeper),
|
SimulationSetup(mapp, stakeKeeper),
|
||||||
}, []mock.Invariant{
|
}, []mock.Invariant{
|
||||||
|
|
Loading…
Reference in New Issue