Merge PR #2282: simulation: Switch the log method from a single string to string builders
This commit is contained in:
parent
8b8028e0dd
commit
173ed6a63d
2
Makefile
2
Makefile
|
@ -157,7 +157,7 @@ test_sim_gaia_nondeterminism:
|
||||||
|
|
||||||
test_sim_gaia_fast:
|
test_sim_gaia_fast:
|
||||||
@echo "Running quick Gaia simulation. This may take several minutes..."
|
@echo "Running quick Gaia simulation. This may take several minutes..."
|
||||||
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=150 -v -timeout 24h
|
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=200 -v -timeout 24h
|
||||||
|
|
||||||
test_sim_gaia_slow:
|
test_sim_gaia_slow:
|
||||||
@echo "Running full Gaia simulation. This may take awhile!"
|
@echo "Running full Gaia simulation. This may take awhile!"
|
||||||
|
|
|
@ -40,6 +40,7 @@ BREAKING CHANGES
|
||||||
* [x/slashing] [#2122](https://github.com/cosmos/cosmos-sdk/pull/2122) - Implement slashing period
|
* [x/slashing] [#2122](https://github.com/cosmos/cosmos-sdk/pull/2122) - Implement slashing period
|
||||||
* [types] [\#2119](https://github.com/cosmos/cosmos-sdk/issues/2119) Parsed error messages and ABCI log errors to make them more human readable.
|
* [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] 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
|
||||||
* [tools] Removed gocyclo [#2211](https://github.com/cosmos/cosmos-sdk/issues/2211)
|
* [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] Remove `SetTxDecoder` in favor of requiring the decoder be set in baseapp initialization. [#1441](https://github.com/cosmos/cosmos-sdk/issues/1441)
|
||||||
|
|
||||||
|
@ -104,6 +105,7 @@ IMPROVEMENTS
|
||||||
* [store] Speedup IAVL iteration, and consequently everything that requires IAVL iteration. [#2143](https://github.com/cosmos/cosmos-sdk/issues/2143)
|
* [store] Speedup IAVL iteration, and consequently everything that requires IAVL iteration. [#2143](https://github.com/cosmos/cosmos-sdk/issues/2143)
|
||||||
* [store] \#1952, \#2281 Update IAVL dependency to v0.11.0
|
* [store] \#1952, \#2281 Update IAVL dependency to v0.11.0
|
||||||
* [simulation] Make timestamps randomized [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
|
* [simulation] Make timestamps randomized [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
|
||||||
|
* [simulation] Make logs not just pure strings, speeding it up by a large factor at greater block heights \#2282
|
||||||
|
|
||||||
* Tendermint
|
* Tendermint
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ import (
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation"
|
banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation"
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
|
@ -108,12 +107,10 @@ func testAndRunTxs(app *GaiaApp) []simulation.Operation {
|
||||||
|
|
||||||
func invariants(app *GaiaApp) []simulation.Invariant {
|
func invariants(app *GaiaApp) []simulation.Invariant {
|
||||||
return []simulation.Invariant{
|
return []simulation.Invariant{
|
||||||
func(t *testing.T, baseapp *baseapp.BaseApp, log string) {
|
banksim.NonnegativeBalanceInvariant(app.accountMapper),
|
||||||
banksim.NonnegativeBalanceInvariant(app.accountMapper)(t, baseapp, log)
|
govsim.AllInvariants(),
|
||||||
govsim.AllInvariants()(t, baseapp, log)
|
stakesim.AllInvariants(app.bankKeeper, app.stakeKeeper, app.accountMapper),
|
||||||
stakesim.AllInvariants(app.bankKeeper, app.stakeKeeper, app.accountMapper)(t, baseapp, log)
|
slashingsim.AllInvariants(),
|
||||||
slashingsim.AllInvariants()(t, baseapp, log)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package simulation
|
package simulation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
@ -16,25 +14,25 @@ import (
|
||||||
|
|
||||||
// NonnegativeBalanceInvariant checks that all accounts in the application have non-negative balances
|
// NonnegativeBalanceInvariant checks that all accounts in the application have non-negative balances
|
||||||
func NonnegativeBalanceInvariant(mapper auth.AccountMapper) simulation.Invariant {
|
func NonnegativeBalanceInvariant(mapper auth.AccountMapper) simulation.Invariant {
|
||||||
return func(t *testing.T, app *baseapp.BaseApp, log string) {
|
return func(app *baseapp.BaseApp) error {
|
||||||
ctx := app.NewContext(false, abci.Header{})
|
ctx := app.NewContext(false, abci.Header{})
|
||||||
accts := mock.GetAllAccounts(mapper, ctx)
|
accts := mock.GetAllAccounts(mapper, ctx)
|
||||||
for _, acc := range accts {
|
for _, acc := range accts {
|
||||||
coins := acc.GetCoins()
|
coins := acc.GetCoins()
|
||||||
require.True(t, coins.IsNotNegative(),
|
if !coins.IsNotNegative() {
|
||||||
fmt.Sprintf("%s has a negative denomination of %s\n%s",
|
return fmt.Errorf("%s has a negative denomination of %s",
|
||||||
acc.GetAddress().String(),
|
acc.GetAddress().String(),
|
||||||
coins.String(),
|
coins.String())
|
||||||
log),
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalCoinsInvariant checks that the sum of the coins across all accounts
|
// TotalCoinsInvariant checks that the sum of the coins across all accounts
|
||||||
// is what is expected
|
// is what is expected
|
||||||
func TotalCoinsInvariant(mapper auth.AccountMapper, totalSupplyFn func() sdk.Coins) simulation.Invariant {
|
func TotalCoinsInvariant(mapper auth.AccountMapper, totalSupplyFn func() sdk.Coins) simulation.Invariant {
|
||||||
return func(t *testing.T, app *baseapp.BaseApp, log string) {
|
return func(app *baseapp.BaseApp) error {
|
||||||
ctx := app.NewContext(false, abci.Header{})
|
ctx := app.NewContext(false, abci.Header{})
|
||||||
totalCoins := sdk.Coins{}
|
totalCoins := sdk.Coins{}
|
||||||
|
|
||||||
|
@ -45,6 +43,9 @@ func TotalCoinsInvariant(mapper auth.AccountMapper, totalSupplyFn func() sdk.Coi
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper.IterateAccounts(ctx, chkAccount)
|
mapper.IterateAccounts(ctx, chkAccount)
|
||||||
require.Equal(t, totalSupplyFn(), totalCoins, log)
|
if !totalSupplyFn().IsEqual(totalCoins) {
|
||||||
|
return errors.New("total calculated coins doesn't equal expected coins")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
@ -21,7 +18,7 @@ import (
|
||||||
// SimulateSingleInputMsgSend tests and runs a single msg send, with one input and one output, where both
|
// SimulateSingleInputMsgSend tests and runs a single msg send, with one input and one output, where both
|
||||||
// accounts already exist.
|
// accounts already exist.
|
||||||
func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation {
|
func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation {
|
||||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOps []simulation.FutureOperation, err sdk.Error) {
|
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)
|
fromKey := simulation.RandomKey(r, keys)
|
||||||
fromAddr := sdk.AccAddress(fromKey.PubKey().Address())
|
fromAddr := sdk.AccAddress(fromKey.PubKey().Address())
|
||||||
toKey := simulation.RandomKey(r, keys)
|
toKey := simulation.RandomKey(r, keys)
|
||||||
|
@ -51,14 +48,16 @@ func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation
|
||||||
initFromCoins[denomIndex].Denom,
|
initFromCoins[denomIndex].Denom,
|
||||||
toAddr.String(),
|
toAddr.String(),
|
||||||
)
|
)
|
||||||
log = fmt.Sprintf("%s\n%s", log, action)
|
|
||||||
|
|
||||||
coins := sdk.Coins{{initFromCoins[denomIndex].Denom, amt}}
|
coins := sdk.Coins{{initFromCoins[denomIndex].Denom, amt}}
|
||||||
var msg = bank.MsgSend{
|
var msg = bank.MsgSend{
|
||||||
Inputs: []bank.Input{bank.NewInput(fromAddr, coins)},
|
Inputs: []bank.Input{bank.NewInput(fromAddr, coins)},
|
||||||
Outputs: []bank.Output{bank.NewOutput(toAddr, coins)},
|
Outputs: []bank.Output{bank.NewOutput(toAddr, coins)},
|
||||||
}
|
}
|
||||||
sendAndVerifyMsgSend(tb, app, mapper, msg, ctx, log, []crypto.PrivKey{fromKey})
|
goErr = sendAndVerifyMsgSend(app, mapper, msg, ctx, []crypto.PrivKey{fromKey})
|
||||||
|
if goErr != nil {
|
||||||
|
return "", nil, goErr
|
||||||
|
}
|
||||||
event("bank/sendAndVerifyMsgSend/ok")
|
event("bank/sendAndVerifyMsgSend/ok")
|
||||||
|
|
||||||
return action, nil, nil
|
return action, nil, nil
|
||||||
|
@ -66,7 +65,7 @@ func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sends and verifies the transition of a msg send. This fails if there are repeated inputs or outputs
|
// Sends and verifies the transition of a msg send. This fails if there are repeated inputs or outputs
|
||||||
func sendAndVerifyMsgSend(tb testing.TB, app *baseapp.BaseApp, mapper auth.AccountMapper, msg bank.MsgSend, ctx sdk.Context, log string, privkeys []crypto.PrivKey) {
|
func sendAndVerifyMsgSend(app *baseapp.BaseApp, mapper auth.AccountMapper, msg bank.MsgSend, ctx sdk.Context, privkeys []crypto.PrivKey) error {
|
||||||
initialInputAddrCoins := make([]sdk.Coins, len(msg.Inputs))
|
initialInputAddrCoins := make([]sdk.Coins, len(msg.Inputs))
|
||||||
initialOutputAddrCoins := make([]sdk.Coins, len(msg.Outputs))
|
initialOutputAddrCoins := make([]sdk.Coins, len(msg.Outputs))
|
||||||
AccountNumbers := make([]int64, len(msg.Inputs))
|
AccountNumbers := make([]int64, len(msg.Inputs))
|
||||||
|
@ -89,25 +88,22 @@ func sendAndVerifyMsgSend(tb testing.TB, app *baseapp.BaseApp, mapper auth.Accou
|
||||||
res := app.Deliver(tx)
|
res := app.Deliver(tx)
|
||||||
if !res.IsOK() {
|
if !res.IsOK() {
|
||||||
// TODO: Do this in a more 'canonical' way
|
// TODO: Do this in a more 'canonical' way
|
||||||
fmt.Println(res)
|
return fmt.Errorf("Deliver failed %v", res)
|
||||||
fmt.Println(log)
|
|
||||||
tb.FailNow()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(msg.Inputs); i++ {
|
for i := 0; i < len(msg.Inputs); i++ {
|
||||||
terminalInputCoins := mapper.GetAccount(ctx, msg.Inputs[i].Address).GetCoins()
|
terminalInputCoins := mapper.GetAccount(ctx, msg.Inputs[i].Address).GetCoins()
|
||||||
require.Equal(tb,
|
if !initialInputAddrCoins[i].Minus(msg.Inputs[i].Coins).IsEqual(terminalInputCoins) {
|
||||||
initialInputAddrCoins[i].Minus(msg.Inputs[i].Coins),
|
return fmt.Errorf("input #%d had an incorrect amount of coins", i)
|
||||||
terminalInputCoins,
|
}
|
||||||
fmt.Sprintf("Input #%d had an incorrect amount of coins\n%s", i, log),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
for i := 0; i < len(msg.Outputs); i++ {
|
for i := 0; i < len(msg.Outputs); i++ {
|
||||||
terminalOutputCoins := mapper.GetAccount(ctx, msg.Outputs[i].Address).GetCoins()
|
terminalOutputCoins := mapper.GetAccount(ctx, msg.Outputs[i].Address).GetCoins()
|
||||||
if !terminalOutputCoins.IsEqual(initialOutputAddrCoins[i].Plus(msg.Outputs[i].Coins)) {
|
if !terminalOutputCoins.IsEqual(initialOutputAddrCoins[i].Plus(msg.Outputs[i].Coins)) {
|
||||||
tb.Fatalf("Output #%d had an incorrect amount of coins\n%s", i, log)
|
return fmt.Errorf("output #%d had an incorrect amount of coins", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func randPositiveInt(r *rand.Rand, max sdk.Int) (sdk.Int, error) {
|
func randPositiveInt(r *rand.Rand, max sdk.Int) (sdk.Int, error) {
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
package simulation
|
package simulation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AllInvariants tests all governance invariants
|
// AllInvariants tests all governance invariants
|
||||||
func AllInvariants() simulation.Invariant {
|
func AllInvariants() simulation.Invariant {
|
||||||
return func(t *testing.T, app *baseapp.BaseApp, log string) {
|
return func(app *baseapp.BaseApp) error {
|
||||||
// TODO Add some invariants!
|
// TODO Add some invariants!
|
||||||
// Checking proposal queues, no passed-but-unexecuted proposals, etc.
|
// Checking proposal queues, no passed-but-unexecuted proposals, etc.
|
||||||
require.Nil(t, nil)
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
|
|
||||||
|
@ -45,10 +44,13 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe
|
||||||
})
|
})
|
||||||
statePercentageArray := []float64{1, .9, .75, .4, .15, 0}
|
statePercentageArray := []float64{1, .9, .75, .4, .15, 0}
|
||||||
curNumVotesState := 1
|
curNumVotesState := 1
|
||||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOps []simulation.FutureOperation, err sdk.Error) {
|
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, err error) {
|
||||||
// 1) submit proposal now
|
// 1) submit proposal now
|
||||||
sender := simulation.RandomKey(r, keys)
|
sender := simulation.RandomKey(r, keys)
|
||||||
msg := simulationCreateMsgSubmitProposal(tb, r, sender, log)
|
msg, err := simulationCreateMsgSubmitProposal(r, sender)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
action = simulateHandleMsgSubmitProposal(msg, sk, handler, ctx, event)
|
action = simulateHandleMsgSubmitProposal(msg, sk, handler, ctx, event)
|
||||||
proposalID := k.GetLastProposalID(ctx)
|
proposalID := k.GetLastProposalID(ctx)
|
||||||
// 2) Schedule operations for votes
|
// 2) Schedule operations for votes
|
||||||
|
@ -77,9 +79,12 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe
|
||||||
// Note: Currently doesn't ensure that the proposal txt is in JSON form
|
// Note: Currently doesn't ensure that the proposal txt is in JSON form
|
||||||
func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
||||||
handler := gov.NewHandler(k)
|
handler := gov.NewHandler(k)
|
||||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOps []simulation.FutureOperation, err sdk.Error) {
|
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)
|
sender := simulation.RandomKey(r, keys)
|
||||||
msg := simulationCreateMsgSubmitProposal(tb, r, sender, log)
|
msg, err := simulationCreateMsgSubmitProposal(r, sender)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
action = simulateHandleMsgSubmitProposal(msg, sk, handler, ctx, event)
|
action = simulateHandleMsgSubmitProposal(msg, sk, handler, ctx, event)
|
||||||
return action, nil, nil
|
return action, nil, nil
|
||||||
}
|
}
|
||||||
|
@ -100,10 +105,10 @@ func simulateHandleMsgSubmitProposal(msg gov.MsgSubmitProposal, sk stake.Keeper,
|
||||||
return action
|
return action
|
||||||
}
|
}
|
||||||
|
|
||||||
func simulationCreateMsgSubmitProposal(tb testing.TB, r *rand.Rand, sender crypto.PrivKey, log string) gov.MsgSubmitProposal {
|
func simulationCreateMsgSubmitProposal(r *rand.Rand, sender crypto.PrivKey) (msg gov.MsgSubmitProposal, err error) {
|
||||||
addr := sdk.AccAddress(sender.PubKey().Address())
|
addr := sdk.AccAddress(sender.PubKey().Address())
|
||||||
deposit := randomDeposit(r)
|
deposit := randomDeposit(r)
|
||||||
msg := gov.NewMsgSubmitProposal(
|
msg = gov.NewMsgSubmitProposal(
|
||||||
simulation.RandStringOfLength(r, 5),
|
simulation.RandStringOfLength(r, 5),
|
||||||
simulation.RandStringOfLength(r, 5),
|
simulation.RandStringOfLength(r, 5),
|
||||||
gov.ProposalTypeText,
|
gov.ProposalTypeText,
|
||||||
|
@ -111,14 +116,14 @@ func simulationCreateMsgSubmitProposal(tb testing.TB, r *rand.Rand, sender crypt
|
||||||
deposit,
|
deposit,
|
||||||
)
|
)
|
||||||
if msg.ValidateBasic() != nil {
|
if msg.ValidateBasic() != nil {
|
||||||
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
err = fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||||
}
|
}
|
||||||
return msg
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateMsgDeposit
|
// SimulateMsgDeposit
|
||||||
func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
||||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
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)
|
key := simulation.RandomKey(r, keys)
|
||||||
addr := sdk.AccAddress(key.PubKey().Address())
|
addr := sdk.AccAddress(key.PubKey().Address())
|
||||||
proposalID, ok := randomProposalID(r, k, ctx)
|
proposalID, ok := randomProposalID(r, k, ctx)
|
||||||
|
@ -128,7 +133,7 @@ func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
||||||
deposit := randomDeposit(r)
|
deposit := randomDeposit(r)
|
||||||
msg := gov.NewMsgDeposit(addr, proposalID, deposit)
|
msg := gov.NewMsgDeposit(addr, proposalID, deposit)
|
||||||
if msg.ValidateBasic() != nil {
|
if msg.ValidateBasic() != nil {
|
||||||
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||||
}
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := gov.NewHandler(k)(ctx, msg)
|
result := gov.NewHandler(k)(ctx, msg)
|
||||||
|
@ -153,7 +158,7 @@ func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
||||||
|
|
||||||
// nolint: unparam
|
// nolint: unparam
|
||||||
func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey, proposalID int64) simulation.Operation {
|
func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey, proposalID int64) simulation.Operation {
|
||||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
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 {
|
if key == nil {
|
||||||
key = simulation.RandomKey(r, keys)
|
key = simulation.RandomKey(r, keys)
|
||||||
}
|
}
|
||||||
|
@ -168,7 +173,7 @@ func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey,
|
||||||
option := randomVotingOption(r)
|
option := randomVotingOption(r)
|
||||||
msg := gov.NewMsgVote(addr, proposalID, option)
|
msg := gov.NewMsgVote(addr, proposalID, option)
|
||||||
if msg.ValidateBasic() != nil {
|
if msg.ValidateBasic() != nil {
|
||||||
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||||
}
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := gov.NewHandler(k)(ctx, msg)
|
result := gov.NewHandler(k)(ctx, msg)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -57,11 +58,10 @@ func SimulateFromSeed(
|
||||||
invariants []Invariant, numBlocks int, blockSize int, commit bool,
|
invariants []Invariant, numBlocks int, blockSize int, commit bool,
|
||||||
) {
|
) {
|
||||||
testingMode, t, b := getTestingMode(tb)
|
testingMode, t, b := getTestingMode(tb)
|
||||||
log := fmt.Sprintf("Starting SimulateFromSeed with randomness created with seed %d", int(seed))
|
fmt.Printf("Starting SimulateFromSeed with randomness created with seed %d\n", int(seed))
|
||||||
r := rand.New(rand.NewSource(seed))
|
r := rand.New(rand.NewSource(seed))
|
||||||
timestamp := randTimestamp(r)
|
timestamp := randTimestamp(r)
|
||||||
log = updateLog(testingMode, log, "Starting the simulation from time %v, unixtime %v", timestamp.UTC().Format(time.UnixDate), timestamp.Unix())
|
fmt.Printf("Starting the simulation from time %v, unixtime %v\n", timestamp.UTC().Format(time.UnixDate), timestamp.Unix())
|
||||||
fmt.Printf("%s\n", log)
|
|
||||||
timeDiff := maxTimePerBlock - minTimePerBlock
|
timeDiff := maxTimePerBlock - minTimePerBlock
|
||||||
|
|
||||||
keys, accs := mock.GeneratePrivKeyAddressPairsFromRand(r, numKeys)
|
keys, accs := mock.GeneratePrivKeyAddressPairsFromRand(r, numKeys)
|
||||||
|
@ -69,7 +69,6 @@ func SimulateFromSeed(
|
||||||
// Setup event stats
|
// Setup event stats
|
||||||
events := make(map[string]uint)
|
events := make(map[string]uint)
|
||||||
event := func(what string) {
|
event := func(what string) {
|
||||||
log = updateLog(testingMode, log, "event - %s", what)
|
|
||||||
events[what]++
|
events[what]++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,14 +90,18 @@ func SimulateFromSeed(
|
||||||
var pastTimes []time.Time
|
var pastTimes []time.Time
|
||||||
var pastSigningValidators [][]abci.SigningValidator
|
var pastSigningValidators [][]abci.SigningValidator
|
||||||
|
|
||||||
request := RandomRequestBeginBlock(r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, pastSigningValidators, event, header, log)
|
request := RandomRequestBeginBlock(r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, pastSigningValidators, event, header)
|
||||||
// These are operations which have been queued by previous operations
|
// These are operations which have been queued by previous operations
|
||||||
operationQueue := make(map[int][]Operation)
|
operationQueue := make(map[int][]Operation)
|
||||||
|
var blockLogBuilders []*strings.Builder
|
||||||
|
|
||||||
if !testingMode {
|
if !testingMode {
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
} else {
|
||||||
|
blockLogBuilders = make([]*strings.Builder, numBlocks)
|
||||||
}
|
}
|
||||||
blockSimulator := createBlockSimulator(testingMode, tb, t, event, invariants, ops, operationQueue, numBlocks)
|
displayLogs := logPrinter(testingMode, blockLogBuilders)
|
||||||
|
blockSimulator := createBlockSimulator(testingMode, tb, t, event, invariants, ops, operationQueue, numBlocks, displayLogs)
|
||||||
|
|
||||||
for i := 0; i < numBlocks; i++ {
|
for i := 0; i < numBlocks; i++ {
|
||||||
// Log the header time for future lookup
|
// Log the header time for future lookup
|
||||||
|
@ -107,38 +110,38 @@ func SimulateFromSeed(
|
||||||
|
|
||||||
// Run the BeginBlock handler
|
// Run the BeginBlock handler
|
||||||
app.BeginBlock(request)
|
app.BeginBlock(request)
|
||||||
log = updateLog(testingMode, log, "BeginBlock")
|
|
||||||
|
|
||||||
if testingMode {
|
if testingMode {
|
||||||
// Make sure invariants hold at beginning of block
|
// Make sure invariants hold at beginning of block
|
||||||
AssertAllInvariants(t, app, invariants, log)
|
assertAllInvariants(t, app, invariants, displayLogs)
|
||||||
}
|
}
|
||||||
|
logWriter := addLogMessage(testingMode, blockLogBuilders, i)
|
||||||
|
|
||||||
ctx := app.NewContext(false, header)
|
ctx := app.NewContext(false, header)
|
||||||
thisBlockSize := getBlockSize(r, blockSize)
|
thisBlockSize := getBlockSize(r, blockSize)
|
||||||
|
|
||||||
// Run queued operations. Ignores blocksize if blocksize is too small
|
// Run queued operations. Ignores blocksize if blocksize is too small
|
||||||
log, numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), tb, r, app, ctx, keys, log, event)
|
numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), tb, r, app, ctx, keys, logWriter, displayLogs, event)
|
||||||
opCount += numQueuedOpsRan
|
opCount += numQueuedOpsRan
|
||||||
thisBlockSize -= numQueuedOpsRan
|
thisBlockSize -= numQueuedOpsRan
|
||||||
log, operations := blockSimulator(thisBlockSize, r, app, ctx, keys, log, header)
|
operations := blockSimulator(thisBlockSize, r, app, ctx, keys, header, logWriter)
|
||||||
opCount += operations
|
opCount += operations
|
||||||
|
|
||||||
res := app.EndBlock(abci.RequestEndBlock{})
|
res := app.EndBlock(abci.RequestEndBlock{})
|
||||||
header.Height++
|
header.Height++
|
||||||
header.Time = header.Time.Add(time.Duration(minTimePerBlock) * time.Second).Add(time.Duration(int64(r.Intn(int(timeDiff)))) * time.Second)
|
header.Time = header.Time.Add(time.Duration(minTimePerBlock) * time.Second).Add(time.Duration(int64(r.Intn(int(timeDiff)))) * time.Second)
|
||||||
log = updateLog(testingMode, log, "EndBlock")
|
logWriter("EndBlock")
|
||||||
|
|
||||||
if testingMode {
|
if testingMode {
|
||||||
// Make sure invariants hold at end of block
|
// Make sure invariants hold at end of block
|
||||||
AssertAllInvariants(t, app, invariants, log)
|
assertAllInvariants(t, app, invariants, displayLogs)
|
||||||
}
|
}
|
||||||
if commit {
|
if commit {
|
||||||
app.Commit()
|
app.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a random RequestBeginBlock with the current validator set for the next block
|
// Generate a random RequestBeginBlock with the current validator set for the next block
|
||||||
request = RandomRequestBeginBlock(r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, pastSigningValidators, event, header, log)
|
request = RandomRequestBeginBlock(r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, pastSigningValidators, event, header)
|
||||||
|
|
||||||
// Update the validator set
|
// Update the validator set
|
||||||
validators = updateValidators(tb, r, validators, res.ValidatorUpdates, event)
|
validators = updateValidators(tb, r, validators, res.ValidatorUpdates, event)
|
||||||
|
@ -150,21 +153,22 @@ func SimulateFromSeed(
|
||||||
|
|
||||||
// Returns a function to simulate blocks. Written like this to avoid constant parameters being passed everytime, to minimize
|
// Returns a function to simulate blocks. Written like this to avoid constant parameters being passed everytime, to minimize
|
||||||
// memory overhead
|
// memory overhead
|
||||||
func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event func(string), invariants []Invariant, ops []Operation, operationQueue map[int][]Operation, totalNumBlocks int) func(
|
func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event func(string), invariants []Invariant, ops []Operation, operationQueue map[int][]Operation, totalNumBlocks int, displayLogs func()) func(
|
||||||
blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, privKeys []crypto.PrivKey, log string, header abci.Header) (updatedLog string, opCount int) {
|
blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, privKeys []crypto.PrivKey, header abci.Header, logWriter func(string)) (opCount int) {
|
||||||
return func(blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
return func(blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||||
keys []crypto.PrivKey, log string, header abci.Header) (updatedLog string, opCount int) {
|
keys []crypto.PrivKey, header abci.Header, logWriter func(string)) (opCount int) {
|
||||||
for j := 0; j < blocksize; j++ {
|
for j := 0; j < blocksize; j++ {
|
||||||
logUpdate, futureOps, err := ops[r.Intn(len(ops))](tb, r, app, ctx, keys, log, event)
|
logUpdate, futureOps, err := ops[r.Intn(len(ops))](r, app, ctx, keys, event)
|
||||||
log = updateLog(testingMode, log, logUpdate)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tb.Fatalf("error on operation %d within block %d, %v, log %s", header.Height, opCount, err, log)
|
displayLogs()
|
||||||
|
tb.Fatalf("error on operation %d within block %d, %v", header.Height, opCount, err)
|
||||||
}
|
}
|
||||||
|
logWriter(logUpdate)
|
||||||
|
|
||||||
queueOperations(operationQueue, futureOps)
|
queueOperations(operationQueue, futureOps)
|
||||||
if testingMode {
|
if testingMode {
|
||||||
if onOperation {
|
if onOperation {
|
||||||
AssertAllInvariants(t, app, invariants, log)
|
assertAllInvariants(t, app, invariants, displayLogs)
|
||||||
}
|
}
|
||||||
if opCount%50 == 0 {
|
if opCount%50 == 0 {
|
||||||
fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ", header.Height, totalNumBlocks, opCount, blocksize)
|
fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ", header.Height, totalNumBlocks, opCount, blocksize)
|
||||||
|
@ -172,7 +176,7 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event f
|
||||||
}
|
}
|
||||||
opCount++
|
opCount++
|
||||||
}
|
}
|
||||||
return log, opCount
|
return opCount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,14 +191,6 @@ func getTestingMode(tb testing.TB) (testingMode bool, t *testing.T, b *testing.B
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLog(testingMode bool, log string, update string, args ...interface{}) (updatedLog string) {
|
|
||||||
if testingMode {
|
|
||||||
update = fmt.Sprintf(update, args...)
|
|
||||||
return fmt.Sprintf("%s\n%s", log, update)
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBlockSize(r *rand.Rand, blockSize int) int {
|
func getBlockSize(r *rand.Rand, blockSize int) int {
|
||||||
load := r.Float64()
|
load := r.Float64()
|
||||||
switch {
|
switch {
|
||||||
|
@ -223,25 +219,24 @@ func queueOperations(queuedOperations map[int][]Operation, futureOperations []Fu
|
||||||
|
|
||||||
// nolint: errcheck
|
// nolint: errcheck
|
||||||
func runQueuedOperations(queueOperations map[int][]Operation, height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
func runQueuedOperations(queueOperations map[int][]Operation, height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||||
privKeys []crypto.PrivKey, log string, event func(string)) (updatedLog string, numOpsRan int) {
|
privKeys []crypto.PrivKey, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) {
|
||||||
updatedLog = log
|
|
||||||
if queuedOps, ok := queueOperations[height]; ok {
|
if queuedOps, ok := queueOperations[height]; ok {
|
||||||
numOps := len(queuedOps)
|
numOps := len(queuedOps)
|
||||||
for i := 0; i < numOps; i++ {
|
for i := 0; i < numOps; i++ {
|
||||||
// For now, queued operations cannot queue more operations.
|
// For now, queued operations cannot queue more operations.
|
||||||
// If a need arises for us to support queued messages to queue more messages, this can
|
// If a need arises for us to support queued messages to queue more messages, this can
|
||||||
// be changed.
|
// be changed.
|
||||||
logUpdate, _, err := queuedOps[i](tb, r, app, ctx, privKeys, updatedLog, event)
|
logUpdate, _, err := queuedOps[i](r, app, ctx, privKeys, event)
|
||||||
updatedLog = fmt.Sprintf("%s\n%s", updatedLog, logUpdate)
|
logWriter(logUpdate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprint(os.Stderr, updatedLog)
|
displayLogs()
|
||||||
tb.FailNow()
|
tb.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(queueOperations, height)
|
delete(queueOperations, height)
|
||||||
return updatedLog, numOps
|
return numOps
|
||||||
}
|
}
|
||||||
return log, 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func getKeys(validators map[string]mockValidator) []string {
|
func getKeys(validators map[string]mockValidator) []string {
|
||||||
|
@ -258,7 +253,7 @@ func getKeys(validators map[string]mockValidator) []string {
|
||||||
// RandomRequestBeginBlock generates a list of signing validators according to the provided list of validators, signing fraction, and evidence fraction
|
// RandomRequestBeginBlock generates a list of signing validators according to the provided list of validators, signing fraction, and evidence fraction
|
||||||
// nolint: unparam
|
// nolint: unparam
|
||||||
func RandomRequestBeginBlock(r *rand.Rand, validators map[string]mockValidator, livenessTransitions TransitionMatrix, evidenceFraction float64,
|
func RandomRequestBeginBlock(r *rand.Rand, validators map[string]mockValidator, livenessTransitions TransitionMatrix, evidenceFraction float64,
|
||||||
pastTimes []time.Time, pastSigningValidators [][]abci.SigningValidator, event func(string), header abci.Header, log string) abci.RequestBeginBlock {
|
pastTimes []time.Time, pastSigningValidators [][]abci.SigningValidator, event func(string), header abci.Header) abci.RequestBeginBlock {
|
||||||
if len(validators) == 0 {
|
if len(validators) == 0 {
|
||||||
return abci.RequestBeginBlock{Header: header}
|
return abci.RequestBeginBlock{Header: header}
|
||||||
}
|
}
|
||||||
|
@ -326,13 +321,6 @@ func RandomRequestBeginBlock(r *rand.Rand, validators map[string]mockValidator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssertAllInvariants asserts a list of provided invariants against application state
|
|
||||||
func AssertAllInvariants(t *testing.T, app *baseapp.BaseApp, tests []Invariant, log string) {
|
|
||||||
for i := 0; i < len(tests); i++ {
|
|
||||||
tests[i](t, app, log)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateValidators mimicks Tendermint's update logic
|
// updateValidators mimicks Tendermint's update logic
|
||||||
// nolint: unparam
|
// nolint: unparam
|
||||||
func updateValidators(tb testing.TB, r *rand.Rand, current map[string]mockValidator, updates []abci.Validator, event func(string)) map[string]mockValidator {
|
func updateValidators(tb testing.TB, r *rand.Rand, current map[string]mockValidator, updates []abci.Validator, event func(string)) map[string]mockValidator {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package simulation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
@ -22,18 +21,18 @@ type (
|
||||||
//
|
//
|
||||||
// Operations can optionally provide a list of "FutureOperations" to run later
|
// Operations can optionally provide a list of "FutureOperations" to run later
|
||||||
// These will be ran at the beginning of the corresponding block.
|
// These will be ran at the beginning of the corresponding block.
|
||||||
Operation func(
|
Operation func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||||
tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
privKeys []crypto.PrivKey, event func(string),
|
||||||
privKeys []crypto.PrivKey, log string, event func(string),
|
) (action string, futureOperations []FutureOperation, err error)
|
||||||
) (action string, futureOperations []FutureOperation, err sdk.Error)
|
|
||||||
|
|
||||||
// RandSetup performs the random setup the mock module needs.
|
// RandSetup performs the random setup the mock module needs.
|
||||||
RandSetup func(r *rand.Rand, privKeys []crypto.PrivKey)
|
RandSetup func(r *rand.Rand, privKeys []crypto.PrivKey)
|
||||||
|
|
||||||
// An Invariant is a function which tests a particular invariant.
|
// An Invariant is a function which tests a particular invariant.
|
||||||
// If the invariant has been broken, the function should halt the
|
// If the invariant has been broken, it should return an error
|
||||||
// test and output the log.
|
// containing a descriptive message about what happened.
|
||||||
Invariant func(t *testing.T, app *baseapp.BaseApp, log string)
|
// The simulator will then halt and print the logs.
|
||||||
|
Invariant func(app *baseapp.BaseApp) error
|
||||||
|
|
||||||
mockValidator struct {
|
mockValidator struct {
|
||||||
val abci.Validator
|
val abci.Validator
|
||||||
|
@ -54,9 +53,10 @@ type (
|
||||||
// a given invariant if the mock application's last block modulo the given
|
// a given invariant if the mock application's last block modulo the given
|
||||||
// period is congruent to the given offset.
|
// period is congruent to the given offset.
|
||||||
func PeriodicInvariant(invariant Invariant, period int, offset int) Invariant {
|
func PeriodicInvariant(invariant Invariant, period int, offset int) Invariant {
|
||||||
return func(t *testing.T, app *baseapp.BaseApp, log string) {
|
return func(app *baseapp.BaseApp) error {
|
||||||
if int(app.LastBlockHeight())%period == offset {
|
if int(app.LastBlockHeight())%period == offset {
|
||||||
invariant(t, app, log)
|
return invariant(app)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -62,3 +65,44 @@ func RandomKey(r *rand.Rand, keys []crypto.PrivKey) crypto.PrivKey {
|
||||||
func RandomAmount(r *rand.Rand, max sdk.Int) sdk.Int {
|
func RandomAmount(r *rand.Rand, max sdk.Int) sdk.Int {
|
||||||
return sdk.NewInt(int64(r.Intn(int(max.Int64()))))
|
return sdk.NewInt(int64(r.Intn(int(max.Int64()))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Builds a function to add logs for this particular block
|
||||||
|
func addLogMessage(testingmode bool, blockLogBuilders []*strings.Builder, height int) func(string) {
|
||||||
|
if testingmode {
|
||||||
|
blockLogBuilders[height] = &strings.Builder{}
|
||||||
|
return func(x string) {
|
||||||
|
(*blockLogBuilders[height]).WriteString(x)
|
||||||
|
(*blockLogBuilders[height]).WriteString("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return func(x string) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertAllInvariants asserts a list of provided invariants against application state
|
||||||
|
func assertAllInvariants(t *testing.T, app *baseapp.BaseApp, invariants []Invariant, displayLogs func()) {
|
||||||
|
for i := 0; i < len(invariants); i++ {
|
||||||
|
err := invariants[i](app)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
displayLogs()
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a function to print out the logs
|
||||||
|
func logPrinter(testingmode bool, logs []*strings.Builder) func() {
|
||||||
|
if testingmode {
|
||||||
|
return func() {
|
||||||
|
for i := 0; i < len(logs); i++ {
|
||||||
|
// We're passed the last created block
|
||||||
|
if logs[i] == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("Begin block %d\n", i)
|
||||||
|
fmt.Println((*logs[i]).String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return func() {}
|
||||||
|
}
|
||||||
|
|
|
@ -1,18 +1,14 @@
|
||||||
package simulation
|
package simulation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AllInvariants tests all slashing invariants
|
// AllInvariants tests all slashing invariants
|
||||||
func AllInvariants() simulation.Invariant {
|
func AllInvariants() simulation.Invariant {
|
||||||
return func(t *testing.T, app *baseapp.BaseApp, log string) {
|
return func(app *baseapp.BaseApp) error {
|
||||||
// TODO Any invariants to check here?
|
// TODO Any invariants to check here?
|
||||||
require.Nil(t, nil)
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package simulation
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
|
|
||||||
|
@ -15,12 +14,12 @@ import (
|
||||||
|
|
||||||
// SimulateMsgUnjail
|
// SimulateMsgUnjail
|
||||||
func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation {
|
func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation {
|
||||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
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)
|
key := simulation.RandomKey(r, keys)
|
||||||
address := sdk.ValAddress(key.PubKey().Address())
|
address := sdk.ValAddress(key.PubKey().Address())
|
||||||
msg := slashing.NewMsgUnjail(address)
|
msg := slashing.NewMsgUnjail(address)
|
||||||
if msg.ValidateBasic() != nil {
|
if msg.ValidateBasic() != nil {
|
||||||
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||||
}
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := slashing.NewHandler(k)(ctx, msg)
|
result := slashing.NewHandler(k)(ctx, msg)
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package simulation
|
package simulation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"fmt"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
@ -17,17 +15,24 @@ import (
|
||||||
// AllInvariants runs all invariants of the stake module.
|
// AllInvariants runs all invariants of the stake module.
|
||||||
// Currently: total supply, positive power
|
// Currently: total supply, positive power
|
||||||
func AllInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) simulation.Invariant {
|
func AllInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) simulation.Invariant {
|
||||||
return func(t *testing.T, app *baseapp.BaseApp, log string) {
|
return func(app *baseapp.BaseApp) error {
|
||||||
SupplyInvariants(ck, k, am)(t, app, log)
|
err := SupplyInvariants(ck, k, am)(app)
|
||||||
PositivePowerInvariant(k)(t, app, log)
|
if err != nil {
|
||||||
ValidatorSetInvariant(k)(t, app, log)
|
return err
|
||||||
|
}
|
||||||
|
err = PositivePowerInvariant(k)(app)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = ValidatorSetInvariant(k)(app)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SupplyInvariants 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
|
||||||
// nolint: unparam
|
// nolint: unparam
|
||||||
func SupplyInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) simulation.Invariant {
|
func SupplyInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) simulation.Invariant {
|
||||||
return func(t *testing.T, app *baseapp.BaseApp, log string) {
|
return func(app *baseapp.BaseApp) error {
|
||||||
ctx := app.NewContext(false, abci.Header{})
|
ctx := app.NewContext(false, abci.Header{})
|
||||||
//pool := k.GetPool(ctx)
|
//pool := k.GetPool(ctx)
|
||||||
|
|
||||||
|
@ -64,23 +69,30 @@ func SupplyInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) sim
|
||||||
// pool.BondedTokens.RoundInt64(), bonded.RoundInt64(), log)
|
// pool.BondedTokens.RoundInt64(), bonded.RoundInt64(), log)
|
||||||
|
|
||||||
// TODO Inflation check on total supply
|
// TODO Inflation check on total supply
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PositivePowerInvariant checks that all stored validators have > 0 power
|
// PositivePowerInvariant checks that all stored validators have > 0 power
|
||||||
func PositivePowerInvariant(k stake.Keeper) simulation.Invariant {
|
func PositivePowerInvariant(k stake.Keeper) simulation.Invariant {
|
||||||
return func(t *testing.T, app *baseapp.BaseApp, log string) {
|
return func(app *baseapp.BaseApp) error {
|
||||||
ctx := app.NewContext(false, abci.Header{})
|
ctx := app.NewContext(false, abci.Header{})
|
||||||
|
var err error
|
||||||
k.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) bool {
|
k.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) bool {
|
||||||
require.True(t, validator.GetPower().GT(sdk.ZeroDec()), "validator with non-positive power stored")
|
if !validator.GetPower().GT(sdk.ZeroDec()) {
|
||||||
|
err = fmt.Errorf("validator with non-positive power stored. (pubkey %v)", validator.GetPubKey())
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidatorSetInvariant checks equivalence of Tendermint validator set and SDK validator set
|
// ValidatorSetInvariant checks equivalence of Tendermint validator set and SDK validator set
|
||||||
func ValidatorSetInvariant(k stake.Keeper) simulation.Invariant {
|
func ValidatorSetInvariant(k stake.Keeper) simulation.Invariant {
|
||||||
return func(t *testing.T, app *baseapp.BaseApp, log string) {
|
return func(app *baseapp.BaseApp) error {
|
||||||
// TODO
|
// TODO
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package simulation
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
@ -18,7 +17,7 @@ import (
|
||||||
// SimulateMsgCreateValidator
|
// SimulateMsgCreateValidator
|
||||||
func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||||
handler := stake.NewHandler(k)
|
handler := stake.NewHandler(k)
|
||||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||||
|
|
||||||
denom := k.GetParams(ctx).BondDenom
|
denom := k.GetParams(ctx).BondDenom
|
||||||
description := stake.Description{
|
description := stake.Description{
|
||||||
|
@ -42,7 +41,7 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
|
||||||
Delegation: sdk.NewCoin(denom, amount),
|
Delegation: sdk.NewCoin(denom, amount),
|
||||||
}
|
}
|
||||||
if msg.ValidateBasic() != nil {
|
if msg.ValidateBasic() != nil {
|
||||||
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||||
}
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := handler(ctx, msg)
|
result := handler(ctx, msg)
|
||||||
|
@ -59,7 +58,7 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
|
||||||
// SimulateMsgEditValidator
|
// SimulateMsgEditValidator
|
||||||
func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
||||||
handler := stake.NewHandler(k)
|
handler := stake.NewHandler(k)
|
||||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||||
|
|
||||||
description := stake.Description{
|
description := stake.Description{
|
||||||
Moniker: simulation.RandStringOfLength(r, 10),
|
Moniker: simulation.RandStringOfLength(r, 10),
|
||||||
|
@ -75,7 +74,7 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
||||||
ValidatorAddr: address,
|
ValidatorAddr: address,
|
||||||
}
|
}
|
||||||
if msg.ValidateBasic() != nil {
|
if msg.ValidateBasic() != nil {
|
||||||
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||||
}
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := handler(ctx, msg)
|
result := handler(ctx, msg)
|
||||||
|
@ -91,7 +90,7 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
||||||
// SimulateMsgDelegate
|
// SimulateMsgDelegate
|
||||||
func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||||
handler := stake.NewHandler(k)
|
handler := stake.NewHandler(k)
|
||||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||||
|
|
||||||
denom := k.GetParams(ctx).BondDenom
|
denom := k.GetParams(ctx).BondDenom
|
||||||
validatorKey := simulation.RandomKey(r, keys)
|
validatorKey := simulation.RandomKey(r, keys)
|
||||||
|
@ -111,7 +110,7 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat
|
||||||
Delegation: sdk.NewCoin(denom, amount),
|
Delegation: sdk.NewCoin(denom, amount),
|
||||||
}
|
}
|
||||||
if msg.ValidateBasic() != nil {
|
if msg.ValidateBasic() != nil {
|
||||||
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||||
}
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := handler(ctx, msg)
|
result := handler(ctx, msg)
|
||||||
|
@ -127,7 +126,7 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat
|
||||||
// SimulateMsgBeginUnbonding
|
// SimulateMsgBeginUnbonding
|
||||||
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||||
handler := stake.NewHandler(k)
|
handler := stake.NewHandler(k)
|
||||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||||
|
|
||||||
denom := k.GetParams(ctx).BondDenom
|
denom := k.GetParams(ctx).BondDenom
|
||||||
validatorKey := simulation.RandomKey(r, keys)
|
validatorKey := simulation.RandomKey(r, keys)
|
||||||
|
@ -147,7 +146,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
|
||||||
SharesAmount: sdk.NewDecFromInt(amount),
|
SharesAmount: sdk.NewDecFromInt(amount),
|
||||||
}
|
}
|
||||||
if msg.ValidateBasic() != nil {
|
if msg.ValidateBasic() != nil {
|
||||||
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||||
}
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := handler(ctx, msg)
|
result := handler(ctx, msg)
|
||||||
|
@ -163,7 +162,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
|
||||||
// SimulateMsgCompleteUnbonding
|
// SimulateMsgCompleteUnbonding
|
||||||
func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
||||||
handler := stake.NewHandler(k)
|
handler := stake.NewHandler(k)
|
||||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||||
|
|
||||||
validatorKey := simulation.RandomKey(r, keys)
|
validatorKey := simulation.RandomKey(r, keys)
|
||||||
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
|
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
|
||||||
|
@ -174,7 +173,7 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
||||||
ValidatorAddr: validatorAddress,
|
ValidatorAddr: validatorAddress,
|
||||||
}
|
}
|
||||||
if msg.ValidateBasic() != nil {
|
if msg.ValidateBasic() != nil {
|
||||||
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||||
}
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := handler(ctx, msg)
|
result := handler(ctx, msg)
|
||||||
|
@ -190,7 +189,7 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
||||||
// SimulateMsgBeginRedelegate
|
// SimulateMsgBeginRedelegate
|
||||||
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||||
handler := stake.NewHandler(k)
|
handler := stake.NewHandler(k)
|
||||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||||
|
|
||||||
denom := k.GetParams(ctx).BondDenom
|
denom := k.GetParams(ctx).BondDenom
|
||||||
sourceValidatorKey := simulation.RandomKey(r, keys)
|
sourceValidatorKey := simulation.RandomKey(r, keys)
|
||||||
|
@ -214,7 +213,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
|
||||||
SharesAmount: sdk.NewDecFromInt(amount),
|
SharesAmount: sdk.NewDecFromInt(amount),
|
||||||
}
|
}
|
||||||
if msg.ValidateBasic() != nil {
|
if msg.ValidateBasic() != nil {
|
||||||
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||||
}
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := handler(ctx, msg)
|
result := handler(ctx, msg)
|
||||||
|
@ -230,7 +229,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
|
||||||
// SimulateMsgCompleteRedelegate
|
// SimulateMsgCompleteRedelegate
|
||||||
func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
|
func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
|
||||||
handler := stake.NewHandler(k)
|
handler := stake.NewHandler(k)
|
||||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||||
|
|
||||||
validatorSrcKey := simulation.RandomKey(r, keys)
|
validatorSrcKey := simulation.RandomKey(r, keys)
|
||||||
validatorSrcAddress := sdk.ValAddress(validatorSrcKey.PubKey().Address())
|
validatorSrcAddress := sdk.ValAddress(validatorSrcKey.PubKey().Address())
|
||||||
|
@ -244,7 +243,7 @@ func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
|
||||||
ValidatorDstAddr: validatorDstAddress,
|
ValidatorDstAddr: validatorDstAddress,
|
||||||
}
|
}
|
||||||
if msg.ValidateBasic() != nil {
|
if msg.ValidateBasic() != nil {
|
||||||
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||||
}
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := handler(ctx, msg)
|
result := handler(ctx, msg)
|
||||||
|
|
Loading…
Reference in New Issue