Merge branch 'develop' into dev/speedup_iavl_iterator
This commit is contained in:
commit
2c3a4fc025
|
@ -23,6 +23,7 @@ BREAKING CHANGES
|
|||
* [core] \#1807 Switch from use of rational to decimal
|
||||
* [types] \#1901 Validator interface's GetOwner() renamed to GetOperator()
|
||||
* [types] \#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)
|
||||
|
||||
* Tendermint
|
||||
|
||||
|
@ -51,6 +52,7 @@ IMPROVEMENTS
|
|||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
* [cli] #2060 removed `--select` from `block` command
|
||||
* [cli] #2128 fixed segfault when exporting directly after `gaiad init`
|
||||
|
||||
* Gaia
|
||||
* [x/stake] [#2023](https://github.com/cosmos/cosmos-sdk/pull/2023) Terminate iteration loop in `UpdateBondedValidators` and `UpdateBondedValidatorsFull` when the first revoked validator is encountered and perform a sanity check.
|
||||
|
@ -60,6 +62,7 @@ IMPROVEMENTS
|
|||
* [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present.
|
||||
* [cli] \#1632 Add integration tests to ensure `basecoind init && basecoind` start sequences run successfully for both `democoin` and `basecoin` examples.
|
||||
* [store] Speedup IAVL iteration, and consequently everything that requires IAVL iteration. [#2143](https://github.com/cosmos/cosmos-sdk/issues/2143)
|
||||
* [simulation] Make timestamps randomized [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
|
||||
|
||||
* Tendermint
|
||||
|
||||
|
|
|
@ -85,8 +85,8 @@ func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json
|
|||
return appState
|
||||
}
|
||||
|
||||
func testAndRunTxs(app *GaiaApp) []simulation.TestAndRunTx {
|
||||
return []simulation.TestAndRunTx{
|
||||
func testAndRunTxs(app *GaiaApp) []simulation.Operation {
|
||||
return []simulation.Operation{
|
||||
banksim.TestAndRunSingleInputMsgSend(app.accountMapper),
|
||||
govsim.SimulateMsgSubmitProposal(app.govKeeper, app.stakeKeeper),
|
||||
govsim.SimulateMsgDeposit(app.govKeeper, app.stakeKeeper),
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
- [ ] 2. Add commits/PRs that are desired for this release **that haven’t already been added to develop**
|
||||
- [ ] 3. Merge items in `PENDING.md` into the `CHANGELOG.md`. While doing this make sure that each entry contains links to issues/PRs for each item
|
||||
- [ ] 4. Summarize breaking API changes section under “Breaking Changes” section to the `CHANGELOG.md` to bring attention to any breaking API changes that affect RPC consumers.
|
||||
- [ ] 5. Tag the commit `{{ .Release.Name }}-rcN`
|
||||
- [ ] 5. Tag the commit `{ .Release.Name }-rcN`
|
||||
- [ ] 6. Kick off 1 day of automated fuzz testing
|
||||
- [ ] 7. Release Lead assigns 2 people to perform [buddy testing script](/docs/RELEASE_TEST_SCRIPT.md) and update the relevant documentation
|
||||
- [ ] 8. If errors are found in either #6 or #7 go back to #2 (*NOTE*: be sure to increment the `rcN`)
|
||||
|
|
|
@ -7,12 +7,12 @@ In the Cosmos network, keys and addresses may refer to a number of different rol
|
|||
|
||||
## HRP table
|
||||
|
||||
| HRP | Definition |
|
||||
| HRP | Definition |
|
||||
| ------------- |:-------------:|
|
||||
| `cosmosaccaddr` | Cosmos Account Address |
|
||||
| `cosmosaccpub` | Cosmos Account Public Key |
|
||||
| `cosmosvaladdr` | Cosmos Consensus Address |
|
||||
| `cosmosvalpub` | Cosmos Consensus Public Key|
|
||||
| `cosmos` | Cosmos Account Address |
|
||||
| `cosmospub` | Cosmos Account Public Key |
|
||||
| `cosmosval` | Cosmos Validator Consensus Address |
|
||||
| `cosmosvalpub`| Cosmos Validator Consensus Public Key|
|
||||
|
||||
## Encoding
|
||||
|
||||
|
@ -22,4 +22,4 @@ To covert between other binary reprsentation of addresses and keys, it is import
|
|||
|
||||
A complete implementation of the Amino serialization format is unncessary in most cases. Simply prepending bytes from this [table](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md#public-key-cryptography) to the bytestring payload before bech32 encoding will sufficient for compatible representation.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
)
|
||||
|
||||
// ExportCmd dumps app state to JSON.
|
||||
|
@ -19,6 +21,21 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co
|
|||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
home := viper.GetString("home")
|
||||
traceStore := viper.GetString(flagTraceStore)
|
||||
emptyState, err := isEmptyState(home)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if emptyState {
|
||||
fmt.Println("WARNING: State is not initialized. Returning genesis file.")
|
||||
genesisFile := path.Join(home, "config", "genesis.json")
|
||||
genesis, err := ioutil.ReadFile(genesisFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(genesis))
|
||||
return nil
|
||||
}
|
||||
|
||||
appState, validators, err := appExporter(home, ctx.Logger, traceStore)
|
||||
if err != nil {
|
||||
|
@ -43,3 +60,12 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
func isEmptyState(home string) (bool, error) {
|
||||
files, err := ioutil.ReadDir(path.Join(home, "data"))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return len(files) == 0, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"os"
|
||||
"bytes"
|
||||
"io"
|
||||
"github.com/cosmos/cosmos-sdk/server/mock"
|
||||
)
|
||||
|
||||
func TestEmptyState(t *testing.T) {
|
||||
defer setupViper(t)()
|
||||
logger := log.NewNopLogger()
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := NewContext(cfg, logger)
|
||||
cdc := wire.NewCodec()
|
||||
appInit := AppInit{
|
||||
AppGenTx: mock.AppGenTx,
|
||||
AppGenState: mock.AppGenStateEmpty,
|
||||
}
|
||||
cmd := InitCmd(ctx, cdc, appInit)
|
||||
err = cmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
cmd = ExportCmd(ctx, cdc, nil)
|
||||
err = cmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
outC := make(chan string)
|
||||
go func() {
|
||||
var buf bytes.Buffer
|
||||
io.Copy(&buf, r)
|
||||
outC <- buf.String()
|
||||
}()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
out := <-outC
|
||||
require.Contains(t, out, "WARNING: State is not initialized")
|
||||
require.Contains(t, out, "genesis_time")
|
||||
require.Contains(t, out, "chain_id")
|
||||
require.Contains(t, out, "consensus_params")
|
||||
require.Contains(t, out, "validators")
|
||||
require.Contains(t, out, "app_hash")
|
||||
}
|
|
@ -121,9 +121,15 @@ func AppGenState(_ *wire.Codec, _ []json.RawMessage) (appState json.RawMessage,
|
|||
return
|
||||
}
|
||||
|
||||
// AppGenStateEmpty returns an empty transaction state for mocking.
|
||||
func AppGenStateEmpty(_ *wire.Codec, _ []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
appState = json.RawMessage(``)
|
||||
return
|
||||
}
|
||||
|
||||
// Return a validator, not much else
|
||||
func AppGenTx(_ *wire.Codec, pk crypto.PubKey, genTxConfig gc.GenTx) (
|
||||
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
||||
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
||||
|
||||
validator = tmtypes.GenesisValidator{
|
||||
PubKey: pk,
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
|
||||
// TestAndRunSingleInputMsgSend tests and runs a single msg send, with one input and one output, where both
|
||||
// accounts already exist.
|
||||
func TestAndRunSingleInputMsgSend(mapper auth.AccountMapper) simulation.TestAndRunTx {
|
||||
func TestAndRunSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) {
|
||||
fromKey := simulation.RandomKey(r, keys)
|
||||
fromAddr := sdk.AccAddress(fromKey.PubKey().Address())
|
||||
|
|
|
@ -33,7 +33,7 @@ func TestBankWithRandomMessages(t *testing.T) {
|
|||
|
||||
simulation.Simulate(
|
||||
t, mapp.BaseApp, appStateFn,
|
||||
[]simulation.TestAndRunTx{
|
||||
[]simulation.Operation{
|
||||
TestAndRunSingleInputMsgSend(mapper),
|
||||
},
|
||||
[]simulation.RandSetup{},
|
||||
|
|
|
@ -21,7 +21,7 @@ const (
|
|||
)
|
||||
|
||||
// SimulateMsgSubmitProposal
|
||||
func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.TestAndRunTx {
|
||||
func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) {
|
||||
key := simulation.RandomKey(r, keys)
|
||||
addr := sdk.AccAddress(key.PubKey().Address())
|
||||
|
@ -50,7 +50,7 @@ func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.TestAnd
|
|||
}
|
||||
|
||||
// SimulateMsgDeposit
|
||||
func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.TestAndRunTx {
|
||||
func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) {
|
||||
key := simulation.RandomKey(r, keys)
|
||||
addr := sdk.AccAddress(key.PubKey().Address())
|
||||
|
@ -77,7 +77,7 @@ func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.TestAndRunTx {
|
|||
}
|
||||
|
||||
// SimulateMsgVote
|
||||
func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.TestAndRunTx {
|
||||
func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) {
|
||||
key := simulation.RandomKey(r, keys)
|
||||
addr := sdk.AccAddress(key.PubKey().Address())
|
||||
|
|
|
@ -55,7 +55,7 @@ func TestGovWithRandomMessages(t *testing.T) {
|
|||
|
||||
simulation.Simulate(
|
||||
t, mapp.BaseApp, appStateFn,
|
||||
[]simulation.TestAndRunTx{
|
||||
[]simulation.Operation{
|
||||
SimulateMsgSubmitProposal(govKeeper, stakeKeeper),
|
||||
SimulateMsgDeposit(govKeeper, stakeKeeper),
|
||||
SimulateMsgVote(govKeeper, stakeKeeper),
|
||||
|
|
|
@ -3,6 +3,7 @@ package simulation
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"testing"
|
||||
|
@ -20,7 +21,7 @@ import (
|
|||
|
||||
// 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, ops []TestAndRunTx, setups []RandSetup,
|
||||
t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, ops []Operation, setups []RandSetup,
|
||||
invariants []Invariant, numBlocks int, blockSize int, commit bool,
|
||||
) {
|
||||
time := time.Now().UnixNano()
|
||||
|
@ -30,12 +31,20 @@ func Simulate(
|
|||
// SimulateFromSeed tests an application by running the provided
|
||||
// operations, testing the provided invariants, but using the provided seed.
|
||||
func SimulateFromSeed(
|
||||
t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, seed int64, ops []TestAndRunTx, setups []RandSetup,
|
||||
t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, seed int64, ops []Operation, setups []RandSetup,
|
||||
invariants []Invariant, numBlocks int, blockSize int, commit bool,
|
||||
) {
|
||||
log := fmt.Sprintf("Starting SimulateFromSeed with randomness created with seed %d", int(seed))
|
||||
fmt.Printf("%s\n", log)
|
||||
r := rand.New(rand.NewSource(seed))
|
||||
|
||||
unixTime := r.Int63n(int64(math.Pow(2, 40)))
|
||||
|
||||
// Set the timestamp for simulation
|
||||
timestamp := time.Unix(unixTime, 0)
|
||||
log = fmt.Sprintf("%s\nStarting the simulation from time %v, unixtime %v", log, timestamp.UTC().Format(time.UnixDate), timestamp.Unix())
|
||||
fmt.Printf("%s\n", log)
|
||||
timeDiff := maxTimePerBlock - minTimePerBlock
|
||||
|
||||
keys, accs := mock.GeneratePrivKeyAddressPairsFromRand(r, numKeys)
|
||||
|
||||
// Setup event stats
|
||||
|
@ -45,9 +54,6 @@ func SimulateFromSeed(
|
|||
events[what]++
|
||||
}
|
||||
|
||||
timestamp := time.Unix(0, 0)
|
||||
timeDiff := maxTimePerBlock - minTimePerBlock
|
||||
|
||||
res := app.InitChain(abci.RequestInitChain{AppStateBytes: appStateFn(r, keys, accs)})
|
||||
validators := make(map[string]mockValidator)
|
||||
for _, validator := range res.Validators {
|
||||
|
|
|
@ -11,10 +11,15 @@ import (
|
|||
)
|
||||
|
||||
type (
|
||||
// TestAndRunTx produces a fuzzed transaction, and ensures the state
|
||||
// transition was as expected. It returns a descriptive message "action"
|
||||
// about what this fuzzed tx actually did, for ease of debugging.
|
||||
TestAndRunTx func(
|
||||
// Operation runs a state machine transition,
|
||||
// and ensures the transition happened as expected.
|
||||
// The operation could be running and testing a fuzzed transaction,
|
||||
// or doing the same for a message.
|
||||
//
|
||||
// For ease of debugging,
|
||||
// an operation returns a descriptive message "action",
|
||||
// which details what this fuzzed state machine transition actually did.
|
||||
Operation func(
|
||||
t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
privKeys []crypto.PrivKey, log string, event func(string),
|
||||
) (action string, err sdk.Error)
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
)
|
||||
|
||||
// SimulateMsgUnjail
|
||||
func SimulateMsgUnjail(k slashing.Keeper) simulation.TestAndRunTx {
|
||||
func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) {
|
||||
key := simulation.RandomKey(r, keys)
|
||||
address := sdk.AccAddress(key.PubKey().Address())
|
||||
|
|
|
@ -18,7 +18,7 @@ import (
|
|||
)
|
||||
|
||||
// SimulateMsgCreateValidator
|
||||
func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.TestAndRunTx {
|
||||
func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) {
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
description := stake.Description{
|
||||
|
@ -55,7 +55,7 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
|
|||
}
|
||||
|
||||
// SimulateMsgEditValidator
|
||||
func SimulateMsgEditValidator(k stake.Keeper) simulation.TestAndRunTx {
|
||||
func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) {
|
||||
description := stake.Description{
|
||||
Moniker: simulation.RandStringOfLength(r, 10),
|
||||
|
@ -83,7 +83,7 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.TestAndRunTx {
|
|||
}
|
||||
|
||||
// SimulateMsgDelegate
|
||||
func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.TestAndRunTx {
|
||||
func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) {
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
validatorKey := simulation.RandomKey(r, keys)
|
||||
|
@ -115,7 +115,7 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.TestAn
|
|||
}
|
||||
|
||||
// SimulateMsgBeginUnbonding
|
||||
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.TestAndRunTx {
|
||||
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) {
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
validatorKey := simulation.RandomKey(r, keys)
|
||||
|
@ -147,7 +147,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
|
|||
}
|
||||
|
||||
// SimulateMsgCompleteUnbonding
|
||||
func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.TestAndRunTx {
|
||||
func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) {
|
||||
validatorKey := simulation.RandomKey(r, keys)
|
||||
validatorAddress := sdk.AccAddress(validatorKey.PubKey().Address())
|
||||
|
@ -170,7 +170,7 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.TestAndRunTx {
|
|||
}
|
||||
|
||||
// SimulateMsgBeginRedelegate
|
||||
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.TestAndRunTx {
|
||||
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) {
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
sourceValidatorKey := simulation.RandomKey(r, keys)
|
||||
|
@ -206,7 +206,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
|
|||
}
|
||||
|
||||
// SimulateMsgCompleteRedelegate
|
||||
func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.TestAndRunTx {
|
||||
func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) {
|
||||
validatorSrcKey := simulation.RandomKey(r, keys)
|
||||
validatorSrcAddress := sdk.AccAddress(validatorSrcKey.PubKey().Address())
|
||||
|
|
|
@ -44,7 +44,7 @@ func TestStakeWithRandomMessages(t *testing.T) {
|
|||
|
||||
simulation.Simulate(
|
||||
t, mapp.BaseApp, appStateFn,
|
||||
[]simulation.TestAndRunTx{
|
||||
[]simulation.Operation{
|
||||
SimulateMsgCreateValidator(mapper, stakeKeeper),
|
||||
SimulateMsgEditValidator(stakeKeeper),
|
||||
SimulateMsgDelegate(mapper, stakeKeeper),
|
||||
|
|
Loading…
Reference in New Issue