Update stake simulation
This commit is contained in:
parent
cbc9d7d1da
commit
af206bd0ed
|
@ -0,0 +1,76 @@
|
|||
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{})
|
||||
pool := k.GetPool(ctx)
|
||||
|
||||
// Loose tokens should equal coin supply
|
||||
loose := sdk.ZeroInt()
|
||||
am.IterateAccounts(ctx, func(acc auth.Account) bool {
|
||||
loose = loose.Add(acc.GetCoins().AmountOf("steak"))
|
||||
return false
|
||||
})
|
||||
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, loose, log)
|
||||
// stats["stake/invariant/looseTokens"] += 1
|
||||
|
||||
// Bonded tokens should equal sum of tokens with bonded validators
|
||||
bonded := sdk.ZeroRat()
|
||||
k.IterateValidators(ctx, func(_ int64, validator sdk.Validator) bool {
|
||||
switch validator.GetStatus() {
|
||||
case sdk.Bonded:
|
||||
bonded = bonded.Add(validator.GetPower())
|
||||
}
|
||||
return false
|
||||
})
|
||||
require.True(t, pool.BondedTokens.Equal(bonded), "expected bonded tokens to equal total steak held by bonded validators\nlog: %s", log)
|
||||
// stats["stake/invariant/bondedTokens"] += 1
|
||||
|
||||
// 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 {
|
||||
require.True(t, validator.GetPower().GT(sdk.ZeroRat()), "validator with non-positive power stored")
|
||||
return false
|
||||
})
|
||||
// stats["stake/invariant/positivePower"] += 1
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
|
@ -1,16 +1,19 @@
|
|||
package simulation
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"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"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
@ -20,73 +23,12 @@ var (
|
|||
stats = make(map[string]int)
|
||||
)
|
||||
|
||||
// ModuleInvariants runs all invariants of the stake module.
|
||||
// Currently: total supply, positive power
|
||||
func ModuleInvariants(ck bank.Keeper, k stake.Keeper) mock.Invariant {
|
||||
return func(t *testing.T, app *mock.App, log string) {
|
||||
SupplyInvariants(ck, k)(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) mock.Invariant {
|
||||
return func(t *testing.T, app *mock.App, log string) {
|
||||
ctx := app.NewContext(false, abci.Header{})
|
||||
pool := k.GetPool(ctx)
|
||||
|
||||
// Loose tokens should equal coin supply
|
||||
loose := sdk.ZeroInt()
|
||||
app.AccountMapper.IterateAccounts(ctx, func(acc auth.Account) bool {
|
||||
loose = loose.Add(acc.GetCoins().AmountOf("steak"))
|
||||
return false
|
||||
})
|
||||
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, loose, log)
|
||||
stats["stake/invariant/looseTokens"] += 1
|
||||
|
||||
// Bonded tokens should equal sum of tokens with bonded validators
|
||||
bonded := sdk.ZeroRat()
|
||||
k.IterateValidators(ctx, func(_ int64, validator sdk.Validator) bool {
|
||||
switch validator.GetStatus() {
|
||||
case sdk.Bonded:
|
||||
bonded = bonded.Add(validator.GetPower())
|
||||
}
|
||||
return false
|
||||
})
|
||||
require.True(t, pool.BondedTokens.Equal(bonded), "expected bonded tokens to equal total steak held by bonded validators\nlog: %s", log)
|
||||
stats["stake/invariant/bondedTokens"] += 1
|
||||
|
||||
// TODO Inflation check on total supply
|
||||
}
|
||||
}
|
||||
|
||||
// PositivePowerInvariant checks that all stored validators have > 0 power
|
||||
func PositivePowerInvariant(k stake.Keeper) mock.Invariant {
|
||||
return func(t *testing.T, app *mock.App, log string) {
|
||||
ctx := app.NewContext(false, abci.Header{})
|
||||
k.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) bool {
|
||||
require.True(t, validator.GetPower().GT(sdk.ZeroRat()), "validator with non-positive power stored")
|
||||
return false
|
||||
})
|
||||
stats["stake/invariant/positivePower"] += 1
|
||||
}
|
||||
}
|
||||
|
||||
// ValidatorSetInvariant checks equivalence of Tendermint validator set and SDK validator set
|
||||
func ValidatorSetInvariant(k stake.Keeper) mock.Invariant {
|
||||
return func(t *testing.T, app *mock.App, log string) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
// SimulateMsgCreateValidator
|
||||
func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) mock.TestAndRunMsg {
|
||||
return func(t *testing.T, r *rand.Rand, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.TestAndRunTx {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
description := stake.Description{
|
||||
Moniker: mock.RandStringOfLength(r, 10),
|
||||
Moniker: simulation.RandStringOfLength(r, 10),
|
||||
}
|
||||
key := keys[r.Intn(len(keys))]
|
||||
pubkey := key.PubKey()
|
||||
|
@ -119,13 +61,13 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) mock.TestA
|
|||
}
|
||||
|
||||
// SimulateMsgEditValidator
|
||||
func SimulateMsgEditValidator(k stake.Keeper) mock.TestAndRunMsg {
|
||||
return func(t *testing.T, r *rand.Rand, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
func SimulateMsgEditValidator(k stake.Keeper) simulation.TestAndRunTx {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
description := stake.Description{
|
||||
Moniker: mock.RandStringOfLength(r, 10),
|
||||
Identity: mock.RandStringOfLength(r, 10),
|
||||
Website: mock.RandStringOfLength(r, 10),
|
||||
Details: mock.RandStringOfLength(r, 10),
|
||||
Moniker: simulation.RandStringOfLength(r, 10),
|
||||
Identity: simulation.RandStringOfLength(r, 10),
|
||||
Website: simulation.RandStringOfLength(r, 10),
|
||||
Details: simulation.RandStringOfLength(r, 10),
|
||||
}
|
||||
key := keys[r.Intn(len(keys))]
|
||||
pubkey := key.PubKey()
|
||||
|
@ -147,8 +89,8 @@ func SimulateMsgEditValidator(k stake.Keeper) mock.TestAndRunMsg {
|
|||
}
|
||||
|
||||
// SimulateMsgDelegate
|
||||
func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) mock.TestAndRunMsg {
|
||||
return func(t *testing.T, r *rand.Rand, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.TestAndRunTx {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
validatorKey := keys[r.Intn(len(keys))]
|
||||
validatorAddress := sdk.AccAddress(validatorKey.PubKey().Address())
|
||||
|
@ -179,8 +121,8 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) mock.TestAndRunMs
|
|||
}
|
||||
|
||||
// SimulateMsgBeginUnbonding
|
||||
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) mock.TestAndRunMsg {
|
||||
return func(t *testing.T, r *rand.Rand, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.TestAndRunTx {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
validatorKey := keys[r.Intn(len(keys))]
|
||||
validatorAddress := sdk.AccAddress(validatorKey.PubKey().Address())
|
||||
|
@ -211,8 +153,8 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) mock.TestAn
|
|||
}
|
||||
|
||||
// SimulateMsgCompleteUnbonding
|
||||
func SimulateMsgCompleteUnbonding(k stake.Keeper) mock.TestAndRunMsg {
|
||||
return func(t *testing.T, r *rand.Rand, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.TestAndRunTx {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
validatorKey := keys[r.Intn(len(keys))]
|
||||
validatorAddress := sdk.AccAddress(validatorKey.PubKey().Address())
|
||||
delegatorKey := keys[r.Intn(len(keys))]
|
||||
|
@ -234,8 +176,8 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) mock.TestAndRunMsg {
|
|||
}
|
||||
|
||||
// SimulateMsgBeginRedelegate
|
||||
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) mock.TestAndRunMsg {
|
||||
return func(t *testing.T, r *rand.Rand, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.TestAndRunTx {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
sourceValidatorKey := keys[r.Intn(len(keys))]
|
||||
sourceValidatorAddress := sdk.AccAddress(sourceValidatorKey.PubKey().Address())
|
||||
|
@ -270,8 +212,8 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) mock.TestA
|
|||
}
|
||||
|
||||
// SimulateMsgCompleteRedelegate
|
||||
func SimulateMsgCompleteRedelegate(k stake.Keeper) mock.TestAndRunMsg {
|
||||
return func(t *testing.T, r *rand.Rand, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.TestAndRunTx {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
|
||||
validatorSrcKey := keys[r.Intn(len(keys))]
|
||||
validatorSrcAddress := sdk.AccAddress(validatorSrcKey.PubKey().Address())
|
||||
validatorDstKey := keys[r.Intn(len(keys))]
|
||||
|
@ -296,7 +238,7 @@ func SimulateMsgCompleteRedelegate(k stake.Keeper) mock.TestAndRunMsg {
|
|||
}
|
||||
|
||||
// SimulationSetup
|
||||
func SimulationSetup(mapp *mock.App, k stake.Keeper) mock.RandSetup {
|
||||
func SimulationSetup(mapp *mock.App, k stake.Keeper) simulation.RandSetup {
|
||||
return func(r *rand.Rand, privKeys []crypto.PrivKey) {
|
||||
ctx := mapp.NewContext(false, abci.Header{})
|
||||
stake.InitGenesis(ctx, k, stake.DefaultGenesisState())
|
||||
|
@ -338,8 +280,9 @@ func TestStakeWithRandomMessages(t *testing.T) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
mapp.SimpleRandomizedTestingFromSeed(
|
||||
t, 20, []mock.TestAndRunMsg{
|
||||
simulation.Simulate(
|
||||
t, mapp.BaseApp, json.RawMessage("{}"),
|
||||
[]simulation.TestAndRunTx{
|
||||
SimulateMsgCreateValidator(mapper, stakeKeeper),
|
||||
SimulateMsgEditValidator(stakeKeeper),
|
||||
SimulateMsgDelegate(mapper, stakeKeeper),
|
||||
|
@ -348,10 +291,10 @@ func TestStakeWithRandomMessages(t *testing.T) {
|
|||
SimulateMsgCompleteUnbonding(stakeKeeper),
|
||||
SimulateMsgBeginRedelegate(mapper, stakeKeeper),
|
||||
SimulateMsgCompleteRedelegate(stakeKeeper),
|
||||
}, []mock.RandSetup{
|
||||
}, []simulation.RandSetup{
|
||||
SimulationSetup(mapp, stakeKeeper),
|
||||
}, []mock.Invariant{
|
||||
ModuleInvariants(coinKeeper, stakeKeeper),
|
||||
}, []simulation.Invariant{
|
||||
AllInvariants(coinKeeper, stakeKeeper, mapp.AccountMapper),
|
||||
}, 10, 100, 500,
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in New Issue