cosmos-sdk/cmd/gaia/app/sim_test.go

209 lines
6.1 KiB
Go
Raw Normal View History

package app
2018-07-11 15:14:37 -07:00
import (
2018-07-17 15:04:10 -07:00
"encoding/json"
2018-07-18 23:40:46 -07:00
"flag"
2018-07-17 15:04:10 -07:00
"math/rand"
"os"
2018-07-11 15:14:37 -07:00
"testing"
"github.com/stretchr/testify/require"
2018-07-12 13:01:43 -07:00
"github.com/tendermint/tendermint/crypto"
2018-07-12 13:01:43 -07:00
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/baseapp"
2018-07-17 15:04:10 -07:00
sdk "github.com/cosmos/cosmos-sdk/types"
2018-07-18 00:05:48 -07:00
banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation"
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
2018-07-16 18:25:15 -07:00
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
2018-07-17 11:33:53 -07:00
stake "github.com/cosmos/cosmos-sdk/x/stake"
2018-07-17 15:04:10 -07:00
stakesim "github.com/cosmos/cosmos-sdk/x/stake/simulation"
2018-07-16 18:15:50 -07:00
)
2018-07-18 23:40:46 -07:00
var (
seed int64
numBlocks int
blockSize int
enabled bool
verbose bool
usegoleveldb bool
2018-07-11 15:14:37 -07:00
)
2018-07-18 23:40:46 -07:00
func init() {
flag.Int64Var(&seed, "SimulationSeed", 42, "Simulation random seed")
flag.IntVar(&numBlocks, "SimulationNumBlocks", 500, "Number of blocks")
flag.IntVar(&blockSize, "SimulationBlockSize", 200, "Operations per block")
2018-07-18 23:40:46 -07:00
flag.BoolVar(&enabled, "SimulationEnabled", false, "Enable the simulation")
flag.BoolVar(&verbose, "SimulationVerbose", false, "Verbose log output")
flag.BoolVar(&usegoleveldb, "SimulationGoLevelDB", false, "Use GoLevelDB instead of memdb")
2018-07-18 23:40:46 -07:00
}
func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage {
2018-07-17 15:04:10 -07:00
var genesisAccounts []GenesisAccount
2018-07-17 11:33:53 -07:00
2018-07-17 15:04:10 -07:00
// Randomly generate some genesis accounts
for _, acc := range accs {
2018-07-17 15:04:10 -07:00
coins := sdk.Coins{sdk.Coin{"steak", sdk.NewInt(100)}}
genesisAccounts = append(genesisAccounts, GenesisAccount{
Address: acc,
2018-07-17 15:04:10 -07:00
Coins: coins,
})
}
2018-07-16 18:15:50 -07:00
2018-07-17 11:33:53 -07:00
// Default genesis state
2018-07-17 16:01:36 -07:00
stakeGenesis := stake.DefaultGenesisState()
var validators []stake.Validator
var delegations []stake.Delegation
// XXX Try different numbers of initially bonded validators
numInitiallyBonded := int64(50)
for i := 0; i < int(numInitiallyBonded); i++ {
validator := stake.NewValidator(accs[i], keys[i].PubKey(), stake.Description{})
2018-08-20 08:10:43 -07:00
validator.Tokens = sdk.NewDec(100)
validator.DelegatorShares = sdk.NewDec(100)
delegation := stake.Delegation{accs[i], accs[i], sdk.NewDec(100), 0}
validators = append(validators, validator)
delegations = append(delegations, delegation)
}
2018-08-20 08:10:43 -07:00
stakeGenesis.Pool.LooseTokens = sdk.NewDec(int64(100*250) + (numInitiallyBonded * 100))
stakeGenesis.Validators = validators
stakeGenesis.Bonds = delegations
// No inflation, for now
2018-08-20 08:10:43 -07:00
stakeGenesis.Params.InflationMax = sdk.NewDec(0)
stakeGenesis.Params.InflationMin = sdk.NewDec(0)
genesis := GenesisState{
2018-07-17 15:04:10 -07:00
Accounts: genesisAccounts,
2018-07-17 16:01:36 -07:00
StakeData: stakeGenesis,
2018-07-17 11:33:53 -07:00
}
// Marshal genesis
appState, err := MakeCodec().MarshalJSON(genesis)
2018-07-17 11:33:53 -07:00
if err != nil {
panic(err)
}
2018-07-17 15:04:10 -07:00
return appState
}
func testAndRunTxs(app *GaiaApp) []simulation.Operation {
return []simulation.Operation{
banksim.SimulateSingleInputMsgSend(app.accountMapper),
govsim.SimulateMsgSubmitProposal(app.govKeeper, app.stakeKeeper),
govsim.SimulateMsgDeposit(app.govKeeper, app.stakeKeeper),
govsim.SimulateMsgVote(app.govKeeper, app.stakeKeeper),
stakesim.SimulateMsgCreateValidator(app.accountMapper, app.stakeKeeper),
stakesim.SimulateMsgEditValidator(app.stakeKeeper),
stakesim.SimulateMsgDelegate(app.accountMapper, app.stakeKeeper),
stakesim.SimulateMsgBeginUnbonding(app.accountMapper, app.stakeKeeper),
stakesim.SimulateMsgCompleteUnbonding(app.stakeKeeper),
stakesim.SimulateMsgBeginRedelegate(app.accountMapper, app.stakeKeeper),
stakesim.SimulateMsgCompleteRedelegate(app.stakeKeeper),
2018-08-22 08:56:13 -07:00
slashingsim.SimulateMsgUnjail(app.slashingKeeper),
}
}
func invariants(app *GaiaApp) []simulation.Invariant {
return []simulation.Invariant{
func(t *testing.T, baseapp *baseapp.BaseApp, log string) {
banksim.NonnegativeBalanceInvariant(app.accountMapper)(t, baseapp, log)
govsim.AllInvariants()(t, baseapp, log)
stakesim.AllInvariants(app.coinKeeper, app.stakeKeeper, app.accountMapper)(t, baseapp, log)
slashingsim.AllInvariants()(t, baseapp, log)
},
}
}
2018-08-29 23:02:15 -07:00
// Profile with:
// /usr/local/go/bin/go test -benchmem -run=^$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$ -cpuprofile cpu.out
func BenchmarkFullGaiaSimulation(b *testing.B) {
// Setup Gaia application
var logger log.Logger
logger = log.NewNopLogger()
var db dbm.DB
db = dbm.NewMemDB()
if usegoleveldb {
db, _ = dbm.NewGoLevelDB("Simulation", os.TempDir())
}
2018-08-29 23:02:15 -07:00
app := NewGaiaApp(logger, db, nil)
// Run randomized simulation
// TODO parameterize numbers, save for a later PR
2018-08-30 00:13:31 -07:00
simulation.SimulateFromSeed(
2018-08-29 23:02:15 -07:00
b, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
[]simulation.RandSetup{},
2018-08-30 00:13:31 -07:00
invariants(app), // these shouldn't get ran
2018-08-29 23:02:15 -07:00
10,
100,
false,
)
}
2018-07-17 15:04:10 -07:00
func TestFullGaiaSimulation(t *testing.T) {
2018-07-18 23:40:46 -07:00
if !enabled {
2018-07-17 15:04:10 -07:00
t.Skip("Skipping Gaia simulation")
}
// Setup Gaia application
var logger log.Logger
if verbose {
logger = log.TestingLogger()
} else {
logger = log.NewNopLogger()
}
2018-07-17 15:04:10 -07:00
db := dbm.NewMemDB()
app := NewGaiaApp(logger, db, nil)
require.Equal(t, "GaiaApp", app.Name())
2018-07-16 18:15:50 -07:00
// Run randomized simulation
2018-07-17 22:37:38 -07:00
simulation.SimulateFromSeed(
t, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
2018-07-16 18:25:15 -07:00
[]simulation.RandSetup{},
invariants(app),
2018-07-18 23:40:46 -07:00
numBlocks,
2018-07-18 00:54:41 -07:00
blockSize,
false,
2018-07-16 18:15:50 -07:00
)
2018-07-11 15:14:37 -07:00
}
// TODO: Make another test for the fuzzer itself, which just has noOp txs
// and doesn't depend on gaia
func TestAppStateDeterminism(t *testing.T) {
if !enabled {
t.Skip("Skipping Gaia simulation")
}
numSeeds := 5
numTimesToRunPerSeed := 5
appHashList := make([]json.RawMessage, numTimesToRunPerSeed)
for i := 0; i < numSeeds; i++ {
seed := rand.Int63()
for j := 0; j < numTimesToRunPerSeed; j++ {
logger := log.NewNopLogger()
db := dbm.NewMemDB()
app := NewGaiaApp(logger, db, nil)
// Run randomized simulation
simulation.SimulateFromSeed(
t, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
[]simulation.RandSetup{},
[]simulation.Invariant{},
20,
20,
true,
)
appHash := app.LastCommitID().Hash
appHashList[j] = appHash
}
for k := 1; k < numTimesToRunPerSeed; k++ {
require.Equal(t, appHashList[0], appHashList[k], "appHash list: %v", appHashList)
}
}
}