Merge remote-tracking branch 'origin/dev/simulation_remove_pubkey_ops' into develop

This commit is contained in:
Jae Kwon 2018-09-24 21:29:41 -07:00
commit c31c0d2822
12 changed files with 151 additions and 126 deletions

View File

@ -44,6 +44,7 @@ BREAKING CHANGES
* [types] [\#2119](https://github.com/cosmos/cosmos-sdk/issues/2119) Parsed error messages and ABCI log errors to make them more human readable.
* [simulation] Rename TestAndRunTx to Operation [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
* [simulation] Remove log and testing.TB from Operation and Invariants, in favor of using errors \#2282
* [simulation] Remove usage of keys and addrs in the types, in favor of simulation.Account \#2384
* [tools] Removed gocyclo [#2211](https://github.com/cosmos/cosmos-sdk/issues/2211)
* [baseapp] Remove `SetTxDecoder` in favor of requiring the decoder be set in baseapp initialization. [#1441](https://github.com/cosmos/cosmos-sdk/issues/1441)
* [baseapp] [\#1921](https://github.com/cosmos/cosmos-sdk/issues/1921) Add minimumFees field to BaseApp.

View File

@ -10,7 +10,6 @@ import (
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
@ -42,14 +41,14 @@ func init() {
flag.BoolVar(&commit, "SimulationCommit", false, "Have the simulation commit")
}
func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage {
func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
var genesisAccounts []GenesisAccount
// Randomly generate some genesis accounts
for _, acc := range accs {
coins := sdk.Coins{sdk.Coin{"steak", sdk.NewInt(100)}}
genesisAccounts = append(genesisAccounts, GenesisAccount{
Address: acc,
Address: acc.Address,
Coins: coins,
})
}
@ -61,10 +60,10 @@ func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json
// XXX Try different numbers of initially bonded validators
numInitiallyBonded := int64(50)
for i := 0; i < int(numInitiallyBonded); i++ {
validator := stake.NewValidator(sdk.ValAddress(accs[i]), keys[i].PubKey(), stake.Description{})
validator := stake.NewValidator(sdk.ValAddress(accs[i].Address), accs[i].PubKey, stake.Description{})
validator.Tokens = sdk.NewDec(100)
validator.DelegatorShares = sdk.NewDec(100)
delegation := stake.Delegation{accs[i], sdk.ValAddress(accs[i]), sdk.NewDec(100), 0}
delegation := stake.Delegation{accs[i].Address, sdk.ValAddress(accs[i].Address), sdk.NewDec(100), 0}
validators = append(validators, validator)
delegations = append(delegations, delegation)
}

View File

@ -18,19 +18,18 @@ import (
// SimulateSingleInputMsgSend tests and runs a single msg send, with one input and one output, where both
// accounts already exist.
func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, err error) {
fromKey := simulation.RandomKey(r, keys)
fromAddr := sdk.AccAddress(fromKey.PubKey().Address())
toKey := simulation.RandomKey(r, keys)
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOps []simulation.FutureOperation, err error) {
fromAcc := simulation.RandomAcc(r, accs)
toAcc := simulation.RandomAcc(r, accs)
// Disallow sending money to yourself
for {
if !fromKey.Equals(toKey) {
if !fromAcc.PubKey.Equals(toAcc.PubKey) {
break
}
toKey = simulation.RandomKey(r, keys)
toAcc = simulation.RandomAcc(r, accs)
}
toAddr := sdk.AccAddress(toKey.PubKey().Address())
initFromCoins := mapper.GetAccount(ctx, fromAddr).GetCoins()
toAddr := toAcc.Address
initFromCoins := mapper.GetAccount(ctx, fromAcc.Address).GetCoins()
if len(initFromCoins) == 0 {
return "skipping, no coins at all", nil, nil
@ -43,7 +42,7 @@ func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation
}
action = fmt.Sprintf("%s is sending %s %s to %s",
fromAddr.String(),
fromAcc.Address.String(),
amt.String(),
initFromCoins[denomIndex].Denom,
toAddr.String(),
@ -51,10 +50,10 @@ func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation
coins := sdk.Coins{{initFromCoins[denomIndex].Denom, amt}}
var msg = bank.MsgSend{
Inputs: []bank.Input{bank.NewInput(fromAddr, coins)},
Inputs: []bank.Input{bank.NewInput(fromAcc.Address, coins)},
Outputs: []bank.Output{bank.NewOutput(toAddr, coins)},
}
goErr = sendAndVerifyMsgSend(app, mapper, msg, ctx, []crypto.PrivKey{fromKey})
goErr = sendAndVerifyMsgSend(app, mapper, msg, ctx, []crypto.PrivKey{fromAcc.PrivKey})
if goErr != nil {
return "", nil, goErr
}

View File

@ -5,8 +5,6 @@ import (
"math/rand"
"testing"
"github.com/tendermint/tendermint/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/mock"
@ -26,8 +24,8 @@ func TestBankWithRandomMessages(t *testing.T) {
panic(err)
}
appStateFn := func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage {
mock.RandomSetGenesis(r, mapp, accs, []string{"stake"})
appStateFn := func(r *rand.Rand, accs []simulation.Account) json.RawMessage {
simulation.RandomSetGenesis(r, mapp, accs, []string{"stake"})
return json.RawMessage("{}")
}

View File

@ -6,8 +6,6 @@ import (
"math/rand"
"time"
"github.com/tendermint/tendermint/crypto"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/gov"
@ -45,9 +43,9 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe
})
statePercentageArray := []float64{1, .9, .75, .4, .15, 0}
curNumVotesState := 1
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, err error) {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOps []simulation.FutureOperation, err error) {
// 1) submit proposal now
sender := simulation.RandomKey(r, keys)
sender := simulation.RandomAcc(r, accs)
msg, err := simulationCreateMsgSubmitProposal(r, sender)
if err != nil {
return "", nil, err
@ -61,16 +59,16 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe
// 2) Schedule operations for votes
// 2.1) first pick a number of people to vote.
curNumVotesState = numVotesTransitionMatrix.NextState(r, curNumVotesState)
numVotes := int(math.Ceil(float64(len(keys)) * statePercentageArray[curNumVotesState]))
numVotes := int(math.Ceil(float64(len(accs)) * statePercentageArray[curNumVotesState]))
// 2.2) select who votes and when
whoVotes := r.Perm(len(keys))
whoVotes := r.Perm(len(accs))
// didntVote := whoVotes[numVotes:]
whoVotes = whoVotes[:numVotes]
votingPeriod := k.GetVotingProcedure(ctx).VotingPeriod
fops := make([]simulation.FutureOperation, numVotes+1)
for i := 0; i < numVotes; i++ {
whenVote := ctx.BlockHeader().Time.Add(time.Duration(r.Int63n(int64(votingPeriod.Seconds()))) * time.Second)
fops[i] = simulation.FutureOperation{BlockTime: whenVote, Op: operationSimulateMsgVote(k, sk, keys[whoVotes[i]], proposalID)}
fops[i] = simulation.FutureOperation{BlockTime: whenVote, Op: operationSimulateMsgVote(k, sk, accs[whoVotes[i]], proposalID)}
}
// 3) Make an operation to ensure slashes were done correctly. (Really should be a future invariant)
// TODO: Find a way to check if a validator was slashed other than just checking their balance a block
@ -84,8 +82,8 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe
// Note: Currently doesn't ensure that the proposal txt is in JSON form
func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operation {
handler := gov.NewHandler(k)
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, err error) {
sender := simulation.RandomKey(r, keys)
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOps []simulation.FutureOperation, err error) {
sender := simulation.RandomAcc(r, accs)
msg, err := simulationCreateMsgSubmitProposal(r, sender)
if err != nil {
return "", nil, err
@ -111,14 +109,13 @@ func simulateHandleMsgSubmitProposal(msg gov.MsgSubmitProposal, sk stake.Keeper,
return
}
func simulationCreateMsgSubmitProposal(r *rand.Rand, sender crypto.PrivKey) (msg gov.MsgSubmitProposal, err error) {
addr := sdk.AccAddress(sender.PubKey().Address())
func simulationCreateMsgSubmitProposal(r *rand.Rand, sender simulation.Account) (msg gov.MsgSubmitProposal, err error) {
deposit := randomDeposit(r)
msg = gov.NewMsgSubmitProposal(
simulation.RandStringOfLength(r, 5),
simulation.RandStringOfLength(r, 5),
gov.ProposalTypeText,
addr,
sender.Address,
deposit,
)
if msg.ValidateBasic() != nil {
@ -129,15 +126,14 @@ func simulationCreateMsgSubmitProposal(r *rand.Rand, sender crypto.PrivKey) (msg
// SimulateMsgDeposit
func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
key := simulation.RandomKey(r, keys)
addr := sdk.AccAddress(key.PubKey().Address())
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
acc := simulation.RandomAcc(r, accs)
proposalID, ok := randomProposalID(r, k, ctx)
if !ok {
return "no-operation", nil, nil
}
deposit := randomDeposit(r)
msg := gov.NewMsgDeposit(addr, proposalID, deposit)
msg := gov.NewMsgDeposit(acc.Address, proposalID, deposit)
if msg.ValidateBasic() != nil {
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
}
@ -159,14 +155,14 @@ func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
// SimulateMsgVote
// nolint: unparam
func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation {
return operationSimulateMsgVote(k, sk, nil, -1)
return operationSimulateMsgVote(k, sk, simulation.Account{}, -1)
}
// nolint: unparam
func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey, proposalID int64) simulation.Operation {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
if key == nil {
key = simulation.RandomKey(r, keys)
func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, acc simulation.Account, proposalID int64) simulation.Operation {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
if acc.Equals(simulation.Account{}) {
acc = simulation.RandomAcc(r, accs)
}
var ok bool
@ -177,10 +173,9 @@ func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey,
return "no-operation", nil, nil
}
}
addr := sdk.AccAddress(key.PubKey().Address())
option := randomVotingOption(r)
msg := gov.NewMsgVote(addr, proposalID, option)
msg := gov.NewMsgVote(acc.Address, proposalID, option)
if msg.ValidateBasic() != nil {
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
}

View File

@ -6,7 +6,6 @@ import (
"testing"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank"
@ -43,12 +42,12 @@ func TestGovWithRandomMessages(t *testing.T) {
panic(err)
}
appStateFn := func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage {
mock.RandomSetGenesis(r, mapp, accs, []string{"stake"})
appStateFn := func(r *rand.Rand, accs []simulation.Account) json.RawMessage {
simulation.RandomSetGenesis(r, mapp, accs, []string{"stake"})
return json.RawMessage("{}")
}
setup := func(r *rand.Rand, privKeys []crypto.PrivKey) {
setup := func(r *rand.Rand, accs []simulation.Account) {
ctx := mapp.NewContext(false, abci.Header{})
stake.InitGenesis(ctx, stakeKeeper, stake.DefaultGenesisState())
gov.InitGenesis(ctx, govKeeper, gov.DefaultGenesisState())

View File

@ -15,17 +15,15 @@ import (
"time"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/mock"
)
// Simulate tests application by sending random messages.
func Simulate(t *testing.T, app *baseapp.BaseApp,
appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage,
appStateFn func(r *rand.Rand, accs []Account) json.RawMessage,
ops []WeightedOperation, setups []RandSetup,
invariants []Invariant, numBlocks int, blockSize int, commit bool) error {
@ -33,16 +31,16 @@ func Simulate(t *testing.T, app *baseapp.BaseApp,
return SimulateFromSeed(t, app, appStateFn, time, ops, setups, invariants, numBlocks, blockSize, commit)
}
func initChain(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress, setups []RandSetup, app *baseapp.BaseApp,
appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage) (validators map[string]mockValidator) {
res := app.InitChain(abci.RequestInitChain{AppStateBytes: appStateFn(r, keys, accs)})
func initChain(r *rand.Rand, accounts []Account, setups []RandSetup, app *baseapp.BaseApp,
appStateFn func(r *rand.Rand, accounts []Account) json.RawMessage) (validators map[string]mockValidator) {
res := app.InitChain(abci.RequestInitChain{AppStateBytes: appStateFn(r, accounts)})
validators = make(map[string]mockValidator)
for _, validator := range res.Validators {
validators[string(validator.Address)] = mockValidator{validator, GetMemberOfInitialState(r, initialLivenessWeightings)}
}
for i := 0; i < len(setups); i++ {
setups[i](r, keys)
setups[i](r, accounts)
}
return
@ -56,7 +54,7 @@ func randTimestamp(r *rand.Rand) time.Time {
// SimulateFromSeed tests an application by running the provided
// operations, testing the provided invariants, but using the provided seed.
func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage,
appStateFn func(r *rand.Rand, accs []Account) json.RawMessage,
seed int64, ops []WeightedOperation, setups []RandSetup, invariants []Invariant,
numBlocks int, blockSize int, commit bool) (simError error) {
@ -69,7 +67,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
fmt.Printf("Starting the simulation from time %v, unixtime %v\n", timestamp.UTC().Format(time.UnixDate), timestamp.Unix())
timeDiff := maxTimePerBlock - minTimePerBlock
keys, accs := mock.GeneratePrivKeyAddressPairsFromRand(r, numKeys)
accs := RandomAccounts(r, numKeys)
// Setup event stats
events := make(map[string]uint)
@ -77,7 +75,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
events[what]++
}
validators := initChain(r, keys, accs, setups, app, appStateFn)
validators := initChain(r, accs, setups, app, appStateFn)
header := abci.Header{Height: 0, Time: timestamp}
opCount := 0
@ -139,10 +137,10 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
thisBlockSize := getBlockSize(r, blockSize)
// Run queued operations. Ignores blocksize if blocksize is too small
numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), tb, r, app, ctx, keys, logWriter, displayLogs, event)
numQueuedTimeOpsRan := runQueuedTimeOperations(timeOperationQueue, header.Time, tb, r, app, ctx, keys, logWriter, displayLogs, event)
numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), tb, r, app, ctx, accs, logWriter, displayLogs, event)
numQueuedTimeOpsRan := runQueuedTimeOperations(timeOperationQueue, header.Time, tb, r, app, ctx, accs, logWriter, displayLogs, event)
thisBlockSize = thisBlockSize - numQueuedOpsRan - numQueuedTimeOpsRan
operations := blockSimulator(thisBlockSize, r, app, ctx, keys, header, logWriter)
operations := blockSimulator(thisBlockSize, r, app, ctx, accs, header, logWriter)
opCount += operations + numQueuedOpsRan + numQueuedTimeOpsRan
res := app.EndBlock(abci.RequestEndBlock{})
@ -176,7 +174,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
// Returns a function to simulate blocks. Written like this to avoid constant parameters being passed everytime, to minimize
// memory overhead
func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event func(string), invariants []Invariant, ops []WeightedOperation, operationQueue map[int][]Operation, timeOperationQueue []FutureOperation, totalNumBlocks int, displayLogs func()) func(
blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, privKeys []crypto.PrivKey, header abci.Header, logWriter func(string)) (opCount int) {
blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, header abci.Header, logWriter func(string)) (opCount int) {
totalOpWeight := 0
for i := 0; i < len(ops); i++ {
totalOpWeight += ops[i].Weight
@ -193,9 +191,9 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event f
return ops[0].Op
}
return func(blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
keys []crypto.PrivKey, header abci.Header, logWriter func(string)) (opCount int) {
accounts []Account, header abci.Header, logWriter func(string)) (opCount int) {
for j := 0; j < blocksize; j++ {
logUpdate, futureOps, err := selectOp(r)(r, app, ctx, keys, event)
logUpdate, futureOps, err := selectOp(r)(r, app, ctx, accounts, event)
if err != nil {
displayLogs()
tb.Fatalf("error on operation %d within block %d, %v", header.Height, opCount, err)
@ -264,14 +262,14 @@ func queueOperations(queuedOperations map[int][]Operation, queuedTimeOperations
// nolint: errcheck
func runQueuedOperations(queueOperations map[int][]Operation, height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
privKeys []crypto.PrivKey, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) {
accounts []Account, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) {
if queuedOps, ok := queueOperations[height]; ok {
numOps := len(queuedOps)
for i := 0; i < numOps; i++ {
// For now, queued operations cannot queue more operations.
// If a need arises for us to support queued messages to queue more messages, this can
// be changed.
logUpdate, _, err := queuedOps[i](r, app, ctx, privKeys, event)
logUpdate, _, err := queuedOps[i](r, app, ctx, accounts, event)
logWriter(logUpdate)
if err != nil {
displayLogs()
@ -285,14 +283,14 @@ func runQueuedOperations(queueOperations map[int][]Operation, height int, tb tes
}
func runQueuedTimeOperations(queueOperations []FutureOperation, currentTime time.Time, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
privKeys []crypto.PrivKey, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) {
accounts []Account, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) {
numOpsRan = 0
for len(queueOperations) > 0 && currentTime.After(queueOperations[0].BlockTime) {
// For now, queued operations cannot queue more operations.
// If a need arises for us to support queued messages to queue more messages, this can
// be changed.
logUpdate, _, err := queueOperations[0].Op(r, app, ctx, privKeys, event)
logUpdate, _, err := queueOperations[0].Op(r, app, ctx, accounts, event)
logWriter(logUpdate)
if err != nil {
displayLogs()

View File

@ -23,11 +23,11 @@ type (
// Operations can optionally provide a list of "FutureOperations" to run later
// These will be ran at the beginning of the corresponding block.
Operation func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
privKeys []crypto.PrivKey, event func(string),
accounts []Account, event func(string),
) (action string, futureOperations []FutureOperation, err error)
// RandSetup performs the random setup the mock module needs.
RandSetup func(r *rand.Rand, privKeys []crypto.PrivKey)
RandSetup func(r *rand.Rand, accounts []Account)
// An Invariant is a function which tests a particular invariant.
// If the invariant has been broken, it should return an error
@ -35,6 +35,15 @@ type (
// The simulator will then halt and print the logs.
Invariant func(app *baseapp.BaseApp) error
// Account contains a privkey, pubkey, address tuple
// eventually more useful data can be placed in here.
// (e.g. number of coins)
Account struct {
PrivKey crypto.PrivKey
PubKey crypto.PubKey
Address sdk.AccAddress
}
mockValidator struct {
val abci.Validator
livenessState int
@ -70,3 +79,8 @@ func PeriodicInvariant(invariant Invariant, period int, offset int) Invariant {
return nil
}
}
// nolint
func (acc Account) Equals(acc2 Account) bool {
return acc.Address.Equals(acc2.Address)
}

View File

@ -9,10 +9,12 @@ import (
"testing"
"time"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/secp256k1"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/mock"
)
// shamelessly copied from https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang#31832326
@ -56,10 +58,10 @@ func DisplayEvents(events map[string]uint) {
}
}
// Pick a random key from an array
func RandomKey(r *rand.Rand, keys []crypto.PrivKey) crypto.PrivKey {
return keys[r.Intn(
len(keys),
// RandomAcc pick a random account from an array
func RandomAcc(r *rand.Rand, accs []Account) Account {
return accs[r.Intn(
len(accs),
)]
}
@ -68,6 +70,25 @@ func RandomAmount(r *rand.Rand, max sdk.Int) sdk.Int {
return sdk.NewInt(int64(r.Intn(int(max.Int64()))))
}
// RandomAccounts generates n random accounts
func RandomAccounts(r *rand.Rand, n int) []Account {
accs := make([]Account, n)
for i := 0; i < n; i++ {
// don't need that much entropy for simulation
privkeySeed := make([]byte, 15)
r.Read(privkeySeed)
useSecp := r.Int63()%2 == 0
if useSecp {
accs[i].PrivKey = secp256k1.GenPrivKeySecp256k1(privkeySeed)
} else {
accs[i].PrivKey = ed25519.GenPrivKeyFromSecret(privkeySeed)
}
accs[i].PubKey = accs[i].PrivKey.PubKey()
accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address())
}
return accs
}
// Builds a function to add logs for this particular block
func addLogMessage(testingmode bool, blockLogBuilders []*strings.Builder, height int) func(string) {
if testingmode {
@ -92,6 +113,15 @@ func assertAllInvariants(t *testing.T, app *baseapp.BaseApp, invariants []Invari
}
}
// RandomSetGenesis wraps mock.RandomSetGenesis, but using simulation accounts
func RandomSetGenesis(r *rand.Rand, app *mock.App, accs []Account, denoms []string) {
addrs := make([]sdk.AccAddress, len(accs))
for i := 0; i < len(accs); i++ {
addrs[i] = accs[i].Address
}
mock.RandomSetGenesis(r, app, addrs, denoms)
}
// Creates a function to print out the logs
func logPrinter(testingmode bool, logs []*strings.Builder) func() {
if testingmode {

View File

@ -4,8 +4,6 @@ import (
"fmt"
"math/rand"
"github.com/tendermint/tendermint/crypto"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
@ -14,9 +12,9 @@ import (
// SimulateMsgUnjail
func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
key := simulation.RandomKey(r, keys)
address := sdk.ValAddress(key.PubKey().Address())
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
acc := simulation.RandomAcc(r, accs)
address := sdk.ValAddress(acc.Address)
msg := slashing.NewMsgUnjail(address)
if msg.ValidateBasic() != nil {
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())

View File

@ -11,13 +11,12 @@ import (
"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"
)
// SimulateMsgCreateValidator
func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
handler := stake.NewHandler(k)
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
denom := k.GetParams(ctx).BondDenom
description := stake.Description{
@ -31,11 +30,9 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
sdk.NewDecWithPrec(simulation.RandomAmount(r, maxCommission).Int64(), 1),
)
key := simulation.RandomKey(r, keys)
pubkey := key.PubKey()
address := sdk.ValAddress(pubkey.Address())
amount := m.GetAccount(ctx, sdk.AccAddress(address)).GetCoins().AmountOf(denom)
acc := simulation.RandomAcc(r, accs)
address := sdk.ValAddress(acc.Address)
amount := m.GetAccount(ctx, acc.Address).GetCoins().AmountOf(denom)
if amount.GT(sdk.ZeroInt()) {
amount = simulation.RandomAmount(r, amount)
}
@ -48,8 +45,8 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
Description: description,
Commission: commission,
ValidatorAddr: address,
DelegatorAddr: sdk.AccAddress(address),
PubKey: pubkey,
DelegatorAddr: acc.Address,
PubKey: acc.PubKey,
Delegation: sdk.NewCoin(denom, amount),
}
@ -74,7 +71,7 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
// SimulateMsgEditValidator
func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
handler := stake.NewHandler(k)
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
description := stake.Description{
Moniker: simulation.RandStringOfLength(r, 10),
@ -86,10 +83,8 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
maxCommission := sdk.NewInt(10)
newCommissionRate := sdk.NewDecWithPrec(simulation.RandomAmount(r, maxCommission).Int64(), 1)
key := simulation.RandomKey(r, keys)
pubkey := key.PubKey()
address := sdk.ValAddress(pubkey.Address())
acc := simulation.RandomAcc(r, accs)
address := sdk.ValAddress(acc.Address)
msg := stake.MsgEditValidator{
Description: description,
ValidatorAddr: address,
@ -114,13 +109,13 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
// SimulateMsgDelegate
func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
handler := stake.NewHandler(k)
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
denom := k.GetParams(ctx).BondDenom
validatorKey := simulation.RandomKey(r, keys)
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
delegatorKey := simulation.RandomKey(r, keys)
delegatorAddress := sdk.AccAddress(delegatorKey.PubKey().Address())
validatorAcc := simulation.RandomAcc(r, accs)
validatorAddress := sdk.ValAddress(validatorAcc.Address)
delegatorAcc := simulation.RandomAcc(r, accs)
delegatorAddress := delegatorAcc.Address
amount := m.GetAccount(ctx, delegatorAddress).GetCoins().AmountOf(denom)
if amount.GT(sdk.ZeroInt()) {
amount = simulation.RandomAmount(r, amount)
@ -150,13 +145,13 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat
// SimulateMsgBeginUnbonding
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
handler := stake.NewHandler(k)
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
denom := k.GetParams(ctx).BondDenom
validatorKey := simulation.RandomKey(r, keys)
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
delegatorKey := simulation.RandomKey(r, keys)
delegatorAddress := sdk.AccAddress(delegatorKey.PubKey().Address())
validatorAcc := simulation.RandomAcc(r, accs)
validatorAddress := sdk.ValAddress(validatorAcc.Address)
delegatorAcc := simulation.RandomAcc(r, accs)
delegatorAddress := delegatorAcc.Address
amount := m.GetAccount(ctx, delegatorAddress).GetCoins().AmountOf(denom)
if amount.GT(sdk.ZeroInt()) {
amount = simulation.RandomAmount(r, amount)
@ -186,12 +181,12 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
// SimulateMsgCompleteUnbonding
func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
handler := stake.NewHandler(k)
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
validatorKey := simulation.RandomKey(r, keys)
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
delegatorKey := simulation.RandomKey(r, keys)
delegatorAddress := sdk.AccAddress(delegatorKey.PubKey().Address())
validatorAcc := simulation.RandomAcc(r, accs)
validatorAddress := sdk.ValAddress(validatorAcc.Address)
delegatorAcc := simulation.RandomAcc(r, accs)
delegatorAddress := delegatorAcc.Address
msg := stake.MsgCompleteUnbonding{
DelegatorAddr: delegatorAddress,
ValidatorAddr: validatorAddress,
@ -213,15 +208,15 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
// SimulateMsgBeginRedelegate
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
handler := stake.NewHandler(k)
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
denom := k.GetParams(ctx).BondDenom
sourceValidatorKey := simulation.RandomKey(r, keys)
sourceValidatorAddress := sdk.ValAddress(sourceValidatorKey.PubKey().Address())
destValidatorKey := simulation.RandomKey(r, keys)
destValidatorAddress := sdk.ValAddress(destValidatorKey.PubKey().Address())
delegatorKey := simulation.RandomKey(r, keys)
delegatorAddress := sdk.AccAddress(delegatorKey.PubKey().Address())
sourceValidatorAcc := simulation.RandomAcc(r, accs)
sourceValidatorAddress := sdk.ValAddress(sourceValidatorAcc.Address)
destValidatorAcc := simulation.RandomAcc(r, accs)
destValidatorAddress := sdk.ValAddress(destValidatorAcc.Address)
delegatorAcc := simulation.RandomAcc(r, accs)
delegatorAddress := delegatorAcc.Address
// TODO
amount := m.GetAccount(ctx, delegatorAddress).GetCoins().AmountOf(denom)
if amount.GT(sdk.ZeroInt()) {
@ -253,14 +248,14 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
// SimulateMsgCompleteRedelegate
func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
handler := stake.NewHandler(k)
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
validatorSrcKey := simulation.RandomKey(r, keys)
validatorSrcAddress := sdk.ValAddress(validatorSrcKey.PubKey().Address())
validatorDstKey := simulation.RandomKey(r, keys)
validatorDstAddress := sdk.ValAddress(validatorDstKey.PubKey().Address())
delegatorKey := simulation.RandomKey(r, keys)
delegatorAddress := sdk.AccAddress(delegatorKey.PubKey().Address())
validatorSrcAcc := simulation.RandomAcc(r, accs)
validatorSrcAddress := sdk.ValAddress(validatorSrcAcc.Address)
validatorDstAcc := simulation.RandomAcc(r, accs)
validatorDstAddress := sdk.ValAddress(validatorDstAcc.Address)
delegatorAcc := simulation.RandomAcc(r, accs)
delegatorAddress := delegatorAcc.Address
msg := stake.MsgCompleteRedelegate{
DelegatorAddr: delegatorAddress,
ValidatorSrcAddr: validatorSrcAddress,
@ -283,7 +278,7 @@ func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
// Setup
// nolint: errcheck
func Setup(mapp *mock.App, k stake.Keeper) simulation.RandSetup {
return func(r *rand.Rand, privKeys []crypto.PrivKey) {
return func(r *rand.Rand, accs []simulation.Account) {
ctx := mapp.NewContext(false, abci.Header{})
gen := stake.DefaultGenesisState()
gen.Params.InflationMax = sdk.NewDec(0)

View File

@ -6,7 +6,6 @@ import (
"testing"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank"
@ -38,8 +37,8 @@ func TestStakeWithRandomMessages(t *testing.T) {
panic(err)
}
appStateFn := func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage {
mock.RandomSetGenesis(r, mapp, accs, []string{"stake"})
appStateFn := func(r *rand.Rand, accs []simulation.Account) json.RawMessage {
simulation.RandomSetGenesis(r, mapp, accs, []string{"stake"})
return json.RawMessage("{}")
}