Merge pull request #346 from CosmWasm/genesis_contract_msg_326

Improve Contract initialization in genesis and tooling
This commit is contained in:
Ethan Frey
2021-01-07 15:02:41 +01:00
committed by GitHub
25 changed files with 2219 additions and 187 deletions

View File

@@ -6,6 +6,7 @@
**Features:**
- Make it easy to initialize contracts in genesis file with new CLI commands[\#326](https://github.com/CosmWasm/wasmd/issues/326)
- Upgrade to WasmVM v0.13.0 [\#358](https://github.com/CosmWasm/wasmd/pull/358)
- Upgrade to cosmos-sdk v0.40.0-rc6 [\#354](https://github.com/CosmWasm/wasmd/pull/354)
- Upgrade to cosmos-sdk v0.40.0-rc5 [\#344](https://github.com/CosmWasm/wasmd/issues/344)

View File

@@ -411,7 +411,7 @@ func NewWasmApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
distr.NewAppModule(appCodec, app.distrKeeper, app.accountKeeper, app.bankKeeper, app.stakingKeeper),
staking.NewAppModule(appCodec, app.stakingKeeper, app.accountKeeper, app.bankKeeper),
upgrade.NewAppModule(app.upgradeKeeper),
wasm.NewAppModule(&app.wasmKeeper),
wasm.NewAppModule(&app.wasmKeeper, app.stakingKeeper),
evidence.NewAppModule(app.evidenceKeeper),
ibc.NewAppModule(app.ibcKeeper),
params.NewAppModule(app.paramsKeeper),
@@ -433,6 +433,8 @@ func NewWasmApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
// NOTE: Capability module must occur first so that it can initialize any capabilities
// so that other modules that want to create or claim capabilities afterwards in InitChain
// can do so safely.
// wasm module should be a the end as it can call other modules functionality direct or via message dispatching during
// genesis phase. For example bank transfer, auth account check, staking, ...
app.mm.SetOrderInitGenesis(
capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName, stakingtypes.ModuleName,
slashingtypes.ModuleName, govtypes.ModuleName, minttypes.ModuleName, crisistypes.ModuleName,
@@ -461,7 +463,7 @@ func NewWasmApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
distr.NewAppModule(appCodec, app.distrKeeper, app.accountKeeper, app.bankKeeper, app.stakingKeeper),
slashing.NewAppModule(appCodec, app.slashingKeeper, app.accountKeeper, app.bankKeeper, app.stakingKeeper),
params.NewAppModule(app.paramsKeeper),
wasm.NewAppModule(&app.wasmKeeper),
wasm.NewAppModule(&app.wasmKeeper, app.stakingKeeper),
evidence.NewAppModule(app.evidenceKeeper),
ibc.NewAppModule(app.ibcKeeper),
transferModule,

26
cmd/wasmd/genwasm.go Normal file
View File

@@ -0,0 +1,26 @@
package main
import (
wasmcli "github.com/CosmWasm/wasmd/x/wasm/client/cli"
"github.com/cosmos/cosmos-sdk/client"
"github.com/spf13/cobra"
)
func AddGenesisWasmMsgCmd(defaultNodeHome string) *cobra.Command {
txCmd := &cobra.Command{
Use: "add-wasm-genesis-message",
Short: "Wasm genesis subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
txCmd.AddCommand(
wasmcli.GenesisStoreCodeCmd(defaultNodeHome),
wasmcli.GenesisInstantiateContractCmd(defaultNodeHome),
wasmcli.GenesisExecuteContractCmd(defaultNodeHome),
wasmcli.GenesisListContractsCmd(defaultNodeHome),
wasmcli.GenesisListCodesCmd(defaultNodeHome),
)
return txCmd
}

View File

@@ -84,6 +84,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig app.EncodingConfig) {
genutilcli.GenTxCmd(app.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome),
genutilcli.ValidateGenesisCmd(app.ModuleBasics),
AddGenesisAccountCmd(app.DefaultNodeHome),
AddGenesisWasmMsgCmd(app.DefaultNodeHome),
tmcli.NewCompletionCmd(rootCmd, true),
// testnetCmd(app.ModuleBasics, banktypes.GenesisBalancesIterator{}),
debug.Cmd(),

28
contrib/local/00-genesis.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/bin/bash
set -o errexit -o nounset -o pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
BASE_ACCOUNT=$(wasmd keys show validator -a)
echo "-----------------------"
echo "## Genesis CosmWasm contract"
wasmd add-wasm-genesis-message store "$DIR/../../x/wasm/internal/keeper/testdata/hackatom.wasm" --instantiate-everybody true --builder=foo/bar:latest --run-as validator
echo "-----------------------"
echo "## Genesis CosmWasm instance"
INIT="{\"verifier\":\"$(wasmd keys show validator -a)\", \"beneficiary\":\"$(wasmd keys show fred -a)\"}"
wasmd add-wasm-genesis-message instantiate-contract 1 "$INIT" --run-as validator --label=foobar --amount=100ustake --admin $BASE_ACCOUNT
echo "-----------------------"
echo "## Genesis CosmWasm execute"
FIRST_CONTRACT_ADDR=wasm18vd8fpwxzck93qlwghaj6arh4p7c5n89k7fvsl
MSG='{"release":{}}'
wasmd add-wasm-genesis-message execute $FIRST_CONTRACT_ADDR "$MSG" --run-as validator --amount=1ustake
echo "-----------------------"
echo "## List Genesis CosmWasm codes"
wasmd add-wasm-genesis-message list-codes
echo "-----------------------"
echo "## List Genesis CosmWasm contracts"
wasmd add-wasm-genesis-message list-contracts

View File

@@ -7,6 +7,7 @@
- [Code](#cosmwasm.wasm.v1beta1.Code)
- [Contract](#cosmwasm.wasm.v1beta1.Contract)
- [GenesisState](#cosmwasm.wasm.v1beta1.GenesisState)
- [GenesisState.GenMsgs](#cosmwasm.wasm.v1beta1.GenesisState.GenMsgs)
- [Sequence](#cosmwasm.wasm.v1beta1.Sequence)
- [x/wasm/internal/types/msg.proto](#x/wasm/internal/types/msg.proto)
@@ -116,6 +117,25 @@ GenesisState - genesis state of x/wasm
| codes | [Code](#cosmwasm.wasm.v1beta1.Code) | repeated | |
| contracts | [Contract](#cosmwasm.wasm.v1beta1.Contract) | repeated | |
| sequences | [Sequence](#cosmwasm.wasm.v1beta1.Sequence) | repeated | |
| gen_msgs | [GenesisState.GenMsgs](#cosmwasm.wasm.v1beta1.GenesisState.GenMsgs) | repeated | |
<a name="cosmwasm.wasm.v1beta1.GenesisState.GenMsgs"></a>
### GenesisState.GenMsgs
GenMsgs define the messages that can be executed during genesis phase.
The intention is to have more human readable data that is auditable.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| store_code | [MsgStoreCode](#cosmwasm.wasm.v1beta1.MsgStoreCode) | | |
| instantiate_contract | [MsgInstantiateContract](#cosmwasm.wasm.v1beta1.MsgInstantiateContract) | | |
| execute_contract | [MsgExecuteContract](#cosmwasm.wasm.v1beta1.MsgExecuteContract) | | |

View File

@@ -0,0 +1,489 @@
package cli
import (
"bufio"
"bytes"
"crypto/sha256"
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/crypto"
tmtypes "github.com/tendermint/tendermint/types"
)
// GenesisStoreCodeCmd cli command to add a `MsgStoreCode` to the wasm section of the genesis
// that is executed on block 0.
func GenesisStoreCodeCmd(defaultNodeHome string) *cobra.Command {
cmd := &cobra.Command{
Use: "store [wasm file] --source [source] --builder [builder] --run-as [owner_address_or_key_name]\",",
Short: "Upload a wasm binary",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
senderAddr, err := getActorAddress(cmd)
if err != nil {
return err
}
msg, err := parseStoreCodeArgs(args[0], senderAddr, cmd.Flags())
if err != nil {
return err
}
if err = msg.ValidateBasic(); err != nil {
return err
}
return alterModuleState(cmd, func(s *types.GenesisState, _ map[string]json.RawMessage) error {
s.GenMsgs = append(s.GenMsgs, types.GenesisState_GenMsgs{
Sum: &types.GenesisState_GenMsgs_StoreCode{StoreCode: &msg},
})
return nil
})
},
}
cmd.Flags().String(flagSource, "", "A valid URI reference to the contract's source code, optional")
cmd.Flags().String(flagBuilder, "", "A valid docker tag for the build system, optional")
cmd.Flags().String(flagRunAs, "", "The address that is stored as code creator")
cmd.Flags().String(flagInstantiateByEverybody, "", "Everybody can instantiate a contract from the code, optional")
cmd.Flags().String(flagInstantiateByAddress, "", "Only this address can instantiate a contract instance from the code, optional")
cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory")
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)")
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GenesisInstantiateContractCmd cli command to add a `MsgInstantiateContract` to the wasm section of the genesis
// that is executed on block 0.
func GenesisInstantiateContractCmd(defaultNodeHome string) *cobra.Command {
cmd := &cobra.Command{
Use: "instantiate-contract [code_id_int64] [json_encoded_init_args] --label [text] --run-as [address] --admin [address,optional] --amount [coins,optional]",
Short: "Instantiate a wasm contract",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
senderAddr, err := getActorAddress(cmd)
if err != nil {
return err
}
msg, err := parseInstantiateArgs(args[0], args[1], senderAddr, cmd.Flags())
if err != nil {
return err
}
if err = msg.ValidateBasic(); err != nil {
return err
}
return alterModuleState(cmd, func(s *types.GenesisState, a map[string]json.RawMessage) error {
// simple sanity check that sender has some balance although it may be consumed by a previous message already
switch ok, err := hasAccountBalance(cmd, a, senderAddr, msg.InitFunds); {
case err != nil:
return err
case !ok:
return errors.New("sender has not enough account balance")
}
// does code id exists?
codeInfos, err := getAllCodes(s)
if err != nil {
return err
}
var codeInfo *codeMeta
for i := range codeInfos {
if codeInfos[i].CodeID == msg.CodeID {
codeInfo = &codeInfos[i]
break
}
}
if codeInfo == nil {
return fmt.Errorf("unknown code id: %d", msg.CodeID)
}
// permissions correct?
if !codeInfo.Info.InstantiateConfig.Allowed(senderAddr) {
return fmt.Errorf("permissions were not granted for %s", senderAddr)
}
s.GenMsgs = append(s.GenMsgs, types.GenesisState_GenMsgs{
Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &msg},
})
return nil
})
},
}
cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation")
cmd.Flags().String(flagLabel, "", "A human-readable name for this contract in lists")
cmd.Flags().String(flagAdmin, "", "Address of an admin")
cmd.Flags().String(flagRunAs, "", "The address that pays the init funds. It is the creator of the contract.")
cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory")
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)")
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GenesisInstantiateContractCmd cli command to add a `MsgExecuteContract` to the wasm section of the genesis
// that is executed on block 0.
func GenesisExecuteContractCmd(defaultNodeHome string) *cobra.Command {
cmd := &cobra.Command{
Use: "execute [contract_addr_bech32] [json_encoded_send_args] --run-as [address] --amount [coins,optional]",
Short: "Execute a command on a wasm contract",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
senderAddr, err := getActorAddress(cmd)
if err != nil {
return err
}
msg, err := parseExecuteArgs(args[0], args[1], senderAddr, cmd.Flags())
if err != nil {
return err
}
if err = msg.ValidateBasic(); err != nil {
return err
}
return alterModuleState(cmd, func(s *types.GenesisState, a map[string]json.RawMessage) error {
// simple sanity check that sender has some balance although it may be consumed by a previous message already
switch ok, err := hasAccountBalance(cmd, a, senderAddr, msg.SentFunds); {
case err != nil:
return err
case !ok:
return errors.New("sender has not enough account balance")
}
// - does contract address exists?
if !hasContract(s, msg.Contract) {
return fmt.Errorf("unknown contract: %s", msg.Contract)
}
s.GenMsgs = append(s.GenMsgs, types.GenesisState_GenMsgs{
Sum: &types.GenesisState_GenMsgs_ExecuteContract{ExecuteContract: &msg},
})
return nil
})
},
}
cmd.Flags().String(flagAmount, "", "Coins to send to the contract along with command")
cmd.Flags().String(flagRunAs, "", "The address that pays the funds.")
cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory")
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)")
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GenesisListCodesCmd cli command to list all codes stored in the genesis wasm.code section
// as well as from messages that are queued in the wasm.genMsgs section.
func GenesisListCodesCmd(defaultNodeHome string) *cobra.Command {
cmd := &cobra.Command{
Use: "list-codes ",
Short: "Lists all codes from genesis code dump and queued messages",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
g, err := readGenesis(cmd)
if err != nil {
return err
}
all, err := getAllCodes(g.wasmModuleState)
if err != nil {
return err
}
return printJsonOutput(cmd, all)
},
}
cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory")
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GenesisListContractsCmd cli command to list all contracts stored in the genesis wasm.contract section
// as well as from messages that are queued in the wasm.genMsgs section.
func GenesisListContractsCmd(defaultNodeHome string) *cobra.Command {
cmd := &cobra.Command{
Use: "list-contracts ",
Short: "Lists all contracts from genesis contract dump and queued messages",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
g, err := readGenesis(cmd)
if err != nil {
return err
}
state := g.wasmModuleState
all := getAllContracts(state)
return printJsonOutput(cmd, all)
},
}
cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory")
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// clientCtx marshaller works only with proto or bytes so we marshal the output ourself
func printJsonOutput(cmd *cobra.Command, obj interface{}) error {
clientCtx := client.GetClientContextFromCmd(cmd)
bz, err := json.MarshalIndent(obj, "", " ")
if err != nil {
return err
}
return clientCtx.PrintString(string(bz))
}
type codeMeta struct {
CodeID uint64 `json:"code_id"`
Info types.CodeInfo `json:"info"`
}
func getAllCodes(state *types.GenesisState) ([]codeMeta, error) {
var all []codeMeta
for _, c := range state.Codes {
all = append(all, codeMeta{
CodeID: c.CodeID,
Info: c.CodeInfo,
})
}
// add inflight
seq := codeSeqValue(state)
for _, m := range state.GenMsgs {
if msg := m.GetStoreCode(); msg != nil {
var accessConfig types.AccessConfig
if msg.InstantiatePermission != nil {
accessConfig = *msg.InstantiatePermission
} else {
// default
creator, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
return nil, fmt.Errorf("sender: %s", err)
}
accessConfig = state.Params.InstantiateDefaultPermission.With(creator)
}
hash := sha256.Sum256(msg.WASMByteCode)
all = append(all, codeMeta{
CodeID: seq,
Info: types.CodeInfo{
CodeHash: hash[:],
Creator: msg.Sender,
Source: msg.Source,
Builder: msg.Builder,
InstantiateConfig: accessConfig,
},
})
seq++
}
}
return all, nil
}
type contractMeta struct {
ContractAddress string `json:"contract_address"`
Info types.ContractInfo `json:"info"`
}
func getAllContracts(state *types.GenesisState) []contractMeta {
var all []contractMeta
for _, c := range state.Contracts {
all = append(all, contractMeta{
ContractAddress: c.ContractAddress,
Info: c.ContractInfo,
})
}
// add inflight
seq := contractSeqValue(state)
for _, m := range state.GenMsgs {
if msg := m.GetInstantiateContract(); msg != nil {
all = append(all, contractMeta{
ContractAddress: contractAddress(msg.CodeID, seq).String(),
Info: types.ContractInfo{
CodeID: msg.CodeID,
Creator: msg.Sender,
Admin: msg.Admin,
Label: msg.Label,
},
})
seq++
}
}
return all
}
func hasAccountBalance(cmd *cobra.Command, a map[string]json.RawMessage, sender sdk.AccAddress, coins sdk.Coins) (bool, error) {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return false, err
}
cdc := clientCtx.JSONMarshaler
var genBalIterator banktypes.GenesisBalancesIterator
err = genutil.ValidateAccountInGenesis(a, genBalIterator, sender, coins, cdc)
if err != nil {
return false, err
}
return true, nil
}
func hasContract(state *types.GenesisState, contractAddr string) bool {
for _, c := range state.Contracts {
if c.ContractAddress == contractAddr {
return true
}
}
seq := contractSeqValue(state)
for _, m := range state.GenMsgs {
if msg := m.GetInstantiateContract(); msg != nil {
if contractAddress(msg.CodeID, seq).String() == contractAddr {
return true
}
seq++
}
}
return false
}
// genesisData contains raw and unmarshalled data from the genesis file
type genesisData struct {
genesisFile string
genDoc *tmtypes.GenesisDoc
appState map[string]json.RawMessage
wasmModuleState *types.GenesisState
}
func readGenesis(cmd *cobra.Command) (*genesisData, error) {
clientCtx := client.GetClientContextFromCmd(cmd)
serverCtx := server.GetServerContextFromCmd(cmd)
config := serverCtx.Config
config.SetRoot(clientCtx.HomeDir)
genFile := config.GenesisFile()
appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal genesis state: %w", err)
}
var wasmGenesisState types.GenesisState
if appState[types.ModuleName] != nil {
clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx.JSONMarshaler.MustUnmarshalJSON(appState[types.ModuleName], &wasmGenesisState)
}
return &genesisData{
genesisFile: genFile,
genDoc: genDoc,
appState: appState,
wasmModuleState: &wasmGenesisState,
}, nil
}
// alterModuleState loads the genesis from the default or set home dir,
// unmarshalls the wasm module section into the object representation
// calls the callback function to modify it
// and marshals the modified state back into the genesis file
func alterModuleState(cmd *cobra.Command, callback func(s *types.GenesisState, a map[string]json.RawMessage) error) error {
g, err := readGenesis(cmd)
if err != nil {
return err
}
if err := callback(g.wasmModuleState, g.appState); err != nil {
return err
}
// and store update
if err := g.wasmModuleState.ValidateBasic(); err != nil {
return err
}
clientCtx := client.GetClientContextFromCmd(cmd)
wasmGenStateBz, err := clientCtx.JSONMarshaler.MarshalJSON(g.wasmModuleState)
if err != nil {
return sdkerrors.Wrap(err, "marshal wasm genesis state")
}
g.appState[types.ModuleName] = wasmGenStateBz
appStateJSON, err := json.Marshal(g.appState)
if err != nil {
return sdkerrors.Wrap(err, "marshal application genesis state")
}
g.genDoc.AppState = appStateJSON
return genutil.ExportGenesisFile(g.genDoc, g.genesisFile)
}
// contractSeqValue reads the contract sequence from the genesis or
// returns default start value used in the keeper
func contractSeqValue(state *types.GenesisState) uint64 {
var seq uint64 = 1
for _, s := range state.Sequences {
if bytes.Equal(s.IDKey, types.KeyLastInstanceID) {
seq = s.Value
break
}
}
return seq
}
// codeSeqValue reads the code sequence from the genesis or
// returns default start value used in the keeper
func codeSeqValue(state *types.GenesisState) uint64 {
var seq uint64 = 1
for _, s := range state.Sequences {
if bytes.Equal(s.IDKey, types.KeyLastCodeID) {
seq = s.Value
break
}
}
return seq
}
// getActorAddress returns the account address for the `--run-as` flag.
// The flag value can either be an address already or a key name where the
// address is read from the keyring instead.
func getActorAddress(cmd *cobra.Command) (sdk.AccAddress, error) {
actorArg, err := cmd.Flags().GetString(flagRunAs)
if err != nil {
return nil, fmt.Errorf("run-as: %s", err.Error())
}
if len(actorArg) == 0 {
return nil, errors.New("run-as address is required")
}
actorAddr, err := sdk.AccAddressFromBech32(actorArg)
if err == nil {
return actorAddr, nil
}
inBuf := bufio.NewReader(cmd.InOrStdin())
keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend)
homeDir := client.GetClientContextFromCmd(cmd).HomeDir
// attempt to lookup address from Keybase if no address was provided
kb, err := keyring.New(sdk.KeyringServiceName(), keyringBackend, homeDir, inBuf)
if err != nil {
return nil, err
}
info, err := kb.Key(actorArg)
if err != nil {
return nil, fmt.Errorf("failed to get address from Keybase: %w", err)
}
return info.GetAddress(), nil
}
// contractAddress builds a contract address. copied from keeper
func contractAddress(codeID, instanceID uint64) sdk.AccAddress {
// NOTE: It is possible to get a duplicate address if either codeID or instanceID
// overflow 32 bits. This is highly improbable, but something that could be refactored.
contractID := codeID<<32 + instanceID
return addrFromUint64(contractID)
}
// addrFromUint64 is a helper for address generation, copied from keeper
func addrFromUint64(id uint64) sdk.AccAddress {
addr := make([]byte, 20)
addr[0] = 'C'
binary.PutUvarint(addr[1:], id)
return sdk.AccAddress(crypto.AddressHash(addr))
}

View File

@@ -0,0 +1,571 @@
package cli
import (
"context"
"encoding/json"
"io/ioutil"
"os"
"path"
"testing"
"github.com/CosmWasm/wasmd/x/wasm/internal/keeper"
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltest "github.com/cosmos/cosmos-sdk/x/genutil/client/testutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
)
var wasmIdent = []byte("\x00\x61\x73\x6D")
var myWellFundedAccount = keeper.RandomBech32AccountAddress(nil)
const defaultTestKeyName = "my-key-name"
func TestGenesisStoreCodeCmd(t *testing.T) {
minimalWasmGenesis := types.GenesisState{
Params: types.DefaultParams(),
}
anyValidWasmFile, err := ioutil.TempFile(t.TempDir(), "wasm")
require.NoError(t, err)
anyValidWasmFile.Write(wasmIdent)
require.NoError(t, anyValidWasmFile.Close())
specs := map[string]struct {
srcGenesis types.GenesisState
mutator func(cmd *cobra.Command)
expError bool
}{
"all good with actor address": {
srcGenesis: minimalWasmGenesis,
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{anyValidWasmFile.Name()})
flagSet := cmd.Flags()
flagSet.Set("source", "https://foo.bar")
flagSet.Set("run-as", keeper.RandomBech32AccountAddress(t))
},
},
"all good with key name": {
srcGenesis: minimalWasmGenesis,
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{anyValidWasmFile.Name()})
flagSet := cmd.Flags()
flagSet.Set("run-as", defaultTestKeyName)
},
},
"with unknown actor key name should fail": {
srcGenesis: minimalWasmGenesis,
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{anyValidWasmFile.Name()})
flagSet := cmd.Flags()
flagSet.Set("run-as", "unknown key")
},
expError: true,
},
"without actor should fail": {
srcGenesis: minimalWasmGenesis,
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{anyValidWasmFile.Name()})
flagSet := cmd.Flags()
flagSet.Set("source", "https://foo.bar")
},
expError: true,
},
"invalid msg data should fail": {
srcGenesis: minimalWasmGenesis,
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{anyValidWasmFile.Name()})
flagSet := cmd.Flags()
flagSet.Set("source", "not an url")
flagSet.Set("run-as", keeper.RandomBech32AccountAddress(t))
},
expError: true,
},
}
for msg, spec := range specs {
t.Run(msg, func(t *testing.T) {
homeDir := setupGenesis(t, spec.srcGenesis)
// when
cmd := GenesisStoreCodeCmd(homeDir)
spec.mutator(cmd)
err := executeCmdWithContext(t, homeDir, cmd)
if spec.expError {
require.Error(t, err)
return
}
require.NoError(t, err)
// then
moduleState := loadModuleState(t, homeDir)
assert.Len(t, moduleState.GenMsgs, 1)
})
}
}
func TestInstantiateContractCmd(t *testing.T) {
minimalWasmGenesis := types.GenesisState{
Params: types.DefaultParams(),
}
anyValidWasmFile, err := ioutil.TempFile(t.TempDir(), "wasm")
require.NoError(t, err)
anyValidWasmFile.Write(wasmIdent)
require.NoError(t, anyValidWasmFile.Close())
specs := map[string]struct {
srcGenesis types.GenesisState
mutator func(cmd *cobra.Command)
expMsgCount int
expError bool
}{
"all good with code id in genesis codes": {
srcGenesis: types.GenesisState{
Params: types.DefaultParams(),
Codes: []types.Code{
{
CodeID: 1,
CodeInfo: types.CodeInfo{
CodeHash: []byte("a-valid-code-hash"),
Creator: keeper.RandomBech32AccountAddress(t),
InstantiateConfig: types.AccessConfig{
Permission: types.AccessTypeEverybody,
},
},
CodeBytes: wasmIdent,
},
},
},
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{"1", `{}`})
flagSet := cmd.Flags()
flagSet.Set("label", "testing")
flagSet.Set("run-as", myWellFundedAccount)
},
expMsgCount: 1,
},
"all good with code id from genesis store messages without initial sequence": {
srcGenesis: types.GenesisState{
Params: types.DefaultParams(),
GenMsgs: []types.GenesisState_GenMsgs{
{Sum: &types.GenesisState_GenMsgs_StoreCode{StoreCode: types.MsgStoreCodeFixture()}},
},
},
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{"1", `{}`})
flagSet := cmd.Flags()
flagSet.Set("label", "testing")
flagSet.Set("run-as", myWellFundedAccount)
},
expMsgCount: 2,
},
"all good with code id from genesis store messages and sequence set": {
srcGenesis: types.GenesisState{
Params: types.DefaultParams(),
GenMsgs: []types.GenesisState_GenMsgs{
{Sum: &types.GenesisState_GenMsgs_StoreCode{StoreCode: types.MsgStoreCodeFixture()}},
},
Sequences: []types.Sequence{
{IDKey: types.KeyLastCodeID, Value: 100},
},
},
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{"100", `{}`})
flagSet := cmd.Flags()
flagSet.Set("label", "testing")
flagSet.Set("run-as", myWellFundedAccount)
},
expMsgCount: 2,
},
"fails with codeID not existing in codes": {
srcGenesis: minimalWasmGenesis,
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{"2", `{}`})
flagSet := cmd.Flags()
flagSet.Set("label", "testing")
flagSet.Set("run-as", myWellFundedAccount)
},
expError: true,
},
"fails when instantiation permissions not granted": {
srcGenesis: types.GenesisState{
Params: types.DefaultParams(),
GenMsgs: []types.GenesisState_GenMsgs{
{Sum: &types.GenesisState_GenMsgs_StoreCode{StoreCode: types.MsgStoreCodeFixture(func(code *types.MsgStoreCode) {
code.InstantiatePermission = &types.AllowNobody
})}},
},
},
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{"1", `{}`})
flagSet := cmd.Flags()
flagSet.Set("label", "testing")
flagSet.Set("run-as", myWellFundedAccount)
},
expError: true,
},
"fails without a sender balance": {
srcGenesis: types.GenesisState{
Params: types.DefaultParams(),
Codes: []types.Code{
{
CodeID: 1,
CodeInfo: types.CodeInfo{
CodeHash: []byte("a-valid-code-hash"),
Creator: keeper.RandomBech32AccountAddress(t),
InstantiateConfig: types.AccessConfig{
Permission: types.AccessTypeEverybody,
},
},
CodeBytes: wasmIdent,
},
},
},
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{"1", `{}`})
flagSet := cmd.Flags()
flagSet.Set("label", "testing")
flagSet.Set("run-as", keeper.RandomBech32AccountAddress(t))
},
expError: true,
},
}
for msg, spec := range specs {
t.Run(msg, func(t *testing.T) {
homeDir := setupGenesis(t, spec.srcGenesis)
// when
cmd := GenesisInstantiateContractCmd(homeDir)
spec.mutator(cmd)
err := executeCmdWithContext(t, homeDir, cmd)
if spec.expError {
require.Error(t, err)
return
}
require.NoError(t, err)
// then
moduleState := loadModuleState(t, homeDir)
assert.Len(t, moduleState.GenMsgs, spec.expMsgCount)
})
}
}
func TestExecuteContractCmd(t *testing.T) {
const firstContractAddress = "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5"
minimalWasmGenesis := types.GenesisState{
Params: types.DefaultParams(),
}
anyValidWasmFile, err := ioutil.TempFile(t.TempDir(), "wasm")
require.NoError(t, err)
anyValidWasmFile.Write(wasmIdent)
require.NoError(t, anyValidWasmFile.Close())
specs := map[string]struct {
srcGenesis types.GenesisState
mutator func(cmd *cobra.Command)
expMsgCount int
expError bool
}{
"all good with contract in genesis contracts": {
srcGenesis: types.GenesisState{
Params: types.DefaultParams(),
Codes: []types.Code{
{
CodeID: 1,
CodeInfo: types.CodeInfoFixture(),
CodeBytes: wasmIdent,
},
},
Contracts: []types.Contract{
{
ContractAddress: firstContractAddress,
ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) {
info.Created = nil
}),
ContractState: []types.Model{},
},
},
},
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{firstContractAddress, `{}`})
flagSet := cmd.Flags()
flagSet.Set("run-as", myWellFundedAccount)
},
expMsgCount: 1,
},
"all good with contract from genesis store messages without initial sequence": {
srcGenesis: types.GenesisState{
Params: types.DefaultParams(),
Codes: []types.Code{
{
CodeID: 1,
CodeInfo: types.CodeInfoFixture(),
CodeBytes: wasmIdent,
},
},
GenMsgs: []types.GenesisState_GenMsgs{
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: types.MsgInstantiateContractFixture()}},
},
},
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{firstContractAddress, `{}`})
flagSet := cmd.Flags()
flagSet.Set("run-as", myWellFundedAccount)
},
expMsgCount: 2,
},
"all good with contract from genesis store messages and contract sequence set": {
srcGenesis: types.GenesisState{
Params: types.DefaultParams(),
Codes: []types.Code{
{
CodeID: 1,
CodeInfo: types.CodeInfoFixture(),
CodeBytes: wasmIdent,
},
},
GenMsgs: []types.GenesisState_GenMsgs{
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: types.MsgInstantiateContractFixture()}},
},
Sequences: []types.Sequence{
{IDKey: types.KeyLastInstanceID, Value: 100},
},
},
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{"cosmos1weh0k0l6t6v4jkmkde8e90tzkw2c59g42ccl62", `{}`})
flagSet := cmd.Flags()
flagSet.Set("run-as", myWellFundedAccount)
},
expMsgCount: 2,
},
"fails with unknown contract address": {
srcGenesis: minimalWasmGenesis,
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{keeper.RandomBech32AccountAddress(t), `{}`})
flagSet := cmd.Flags()
flagSet.Set("run-as", myWellFundedAccount)
},
expError: true,
},
"fails without enough sender balance": {
srcGenesis: types.GenesisState{
Params: types.DefaultParams(),
Codes: []types.Code{
{
CodeID: 1,
CodeInfo: types.CodeInfoFixture(),
CodeBytes: wasmIdent,
},
},
Contracts: []types.Contract{
{
ContractAddress: firstContractAddress,
ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) {
info.Created = nil
}),
ContractState: []types.Model{},
},
},
},
mutator: func(cmd *cobra.Command) {
cmd.SetArgs([]string{firstContractAddress, `{}`})
flagSet := cmd.Flags()
flagSet.Set("run-as", keeper.RandomBech32AccountAddress(t))
},
expError: true,
},
}
for msg, spec := range specs {
t.Run(msg, func(t *testing.T) {
homeDir := setupGenesis(t, spec.srcGenesis)
cmd := GenesisExecuteContractCmd(homeDir)
spec.mutator(cmd)
// when
err := executeCmdWithContext(t, homeDir, cmd)
if spec.expError {
require.Error(t, err)
return
}
require.NoError(t, err)
// then
moduleState := loadModuleState(t, homeDir)
assert.Len(t, moduleState.GenMsgs, spec.expMsgCount)
})
}
}
func TestGetAllContracts(t *testing.T) {
specs := map[string]struct {
src types.GenesisState
exp []contractMeta
}{
"read from contracts state": {
src: types.GenesisState{
Contracts: []types.Contract{
{
ContractAddress: "first-contract",
ContractInfo: types.ContractInfo{Label: "first"},
},
{
ContractAddress: "second-contract",
ContractInfo: types.ContractInfo{Label: "second"},
},
},
},
exp: []contractMeta{
{
ContractAddress: "first-contract",
Info: types.ContractInfo{Label: "first"},
},
{
ContractAddress: "second-contract",
Info: types.ContractInfo{Label: "second"},
},
},
},
"read from message state": {
src: types.GenesisState{
GenMsgs: []types.GenesisState_GenMsgs{
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "first"}}},
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "second"}}},
},
},
exp: []contractMeta{
{
ContractAddress: contractAddress(0, 1).String(),
Info: types.ContractInfo{Label: "first"},
},
{
ContractAddress: contractAddress(0, 2).String(),
Info: types.ContractInfo{Label: "second"},
},
},
},
"read from message state with contract sequence": {
src: types.GenesisState{
Sequences: []types.Sequence{
{IDKey: types.KeyLastInstanceID, Value: 100},
},
GenMsgs: []types.GenesisState_GenMsgs{
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "hundred"}}},
},
},
exp: []contractMeta{
{
ContractAddress: contractAddress(0, 100).String(),
Info: types.ContractInfo{Label: "hundred"},
},
},
},
"read from contract and message state with contract sequence": {
src: types.GenesisState{
Contracts: []types.Contract{
{
ContractAddress: "first-contract",
ContractInfo: types.ContractInfo{Label: "first"},
},
},
Sequences: []types.Sequence{
{IDKey: types.KeyLastInstanceID, Value: 100},
},
GenMsgs: []types.GenesisState_GenMsgs{
{Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "hundred"}}},
},
},
exp: []contractMeta{
{
ContractAddress: "first-contract",
Info: types.ContractInfo{Label: "first"},
},
{
ContractAddress: contractAddress(0, 100).String(),
Info: types.ContractInfo{Label: "hundred"},
},
},
},
}
for msg, spec := range specs {
t.Run(msg, func(t *testing.T) {
got := getAllContracts(&spec.src)
assert.Equal(t, spec.exp, got)
})
}
}
func setupGenesis(t *testing.T, wasmGenesis types.GenesisState) string {
appCodec := keeper.MakeEncodingConfig(t).Marshaler
homeDir := t.TempDir()
require.NoError(t, os.Mkdir(path.Join(homeDir, "config"), 0700))
genFilename := path.Join(homeDir, "config", "genesis.json")
appState := make(map[string]json.RawMessage)
appState[types.ModuleName] = appCodec.MustMarshalJSON(&wasmGenesis)
bankGenesis := banktypes.DefaultGenesisState()
bankGenesis.Balances = append(bankGenesis.Balances, banktypes.Balance{
// add a balance for the default sender account
Address: myWellFundedAccount,
Coins: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(10000000000))),
})
appState[banktypes.ModuleName] = appCodec.MustMarshalJSON(bankGenesis)
appState[stakingtypes.ModuleName] = appCodec.MustMarshalJSON(stakingtypes.DefaultGenesisState())
appStateBz, err := json.Marshal(appState)
require.NoError(t, err)
genDoc := tmtypes.GenesisDoc{
ChainID: "testing",
AppState: appStateBz,
}
err = genutil.ExportGenesisFile(&genDoc, genFilename)
require.NoError(t, err)
return homeDir
}
func executeCmdWithContext(t *testing.T, homeDir string, cmd *cobra.Command) error {
logger := log.NewNopLogger()
cfg, err := genutiltest.CreateDefaultTendermintConfig(homeDir)
require.NoError(t, err)
appCodec := keeper.MakeEncodingConfig(t).Marshaler
serverCtx := server.NewContext(viper.New(), cfg, logger)
clientCtx := client.Context{}.WithJSONMarshaler(appCodec).WithHomeDir(homeDir)
ctx := context.Background()
ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)
ctx = context.WithValue(ctx, server.ServerContextKey, serverCtx)
flagSet := cmd.Flags()
flagSet.Set("home", homeDir)
flagSet.Set(flags.FlagKeyringBackend, keyring.BackendTest)
mockIn := testutil.ApplyMockIODiscardOutErr(cmd)
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, homeDir, mockIn)
require.NoError(t, err)
_, err = kb.NewAccount(defaultTestKeyName, testutil.TestMnemonic, "", sdk.FullFundraiserPath, hd.Secp256k1)
require.NoError(t, err)
return cmd.ExecuteContext(ctx)
}
func loadModuleState(t *testing.T, homeDir string) types.GenesisState {
genFilename := path.Join(homeDir, "config", "genesis.json")
appState, _, err := genutiltypes.GenesisStateFromGenFile(genFilename)
require.NoError(t, err)
require.Contains(t, appState, types.ModuleName)
appCodec := keeper.MakeEncodingConfig(t).Marshaler
var moduleState types.GenesisState
require.NoError(t, appCodec.UnmarshalJSON(appState[types.ModuleName], &moduleState))
return moduleState
}

View File

@@ -1,6 +1,8 @@
package cli
import (
"fmt"
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
@@ -9,7 +11,6 @@ import (
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func ProposalStoreCodeCmd() *cobra.Command {
@@ -23,27 +24,44 @@ func ProposalStoreCodeCmd() *cobra.Command {
return err
}
src, err := parseStoreCodeArgs(args, clientCtx)
src, err := parseStoreCodeArgs(args[0], clientCtx.FromAddress, cmd.Flags())
if err != nil {
return err
}
if len(viper.GetString(flagRunAs)) == 0 {
runAs, err := cmd.Flags().GetString(flagRunAs)
if err != nil {
return fmt.Errorf("run-as: %s", err)
}
if len(runAs) == 0 {
return errors.New("run-as address is required")
}
proposalTitle, err := cmd.Flags().GetString(cli.FlagTitle)
if err != nil {
return fmt.Errorf("proposal title: %s", err)
}
proposalDescr, err := cmd.Flags().GetString(cli.FlagDescription)
if err != nil {
return fmt.Errorf("proposal description: %s", err)
}
depositArg, err := cmd.Flags().GetString(cli.FlagDeposit)
if err != nil {
return err
}
deposit, err := sdk.ParseCoinsNormalized(depositArg)
if err != nil {
return err
}
content := types.StoreCodeProposal{
Title: viper.GetString(cli.FlagTitle),
Description: viper.GetString(cli.FlagDescription),
RunAs: viper.GetString(flagRunAs),
Title: proposalTitle,
Description: proposalDescr,
RunAs: runAs,
WASMByteCode: src.WASMByteCode,
Source: src.Source,
Builder: src.Builder,
InstantiatePermission: src.InstantiatePermission,
}
deposit, err := sdk.ParseCoinsNormalized(viper.GetString(cli.FlagDeposit))
if err != nil {
return err
}
msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
if err != nil {
return err
@@ -83,17 +101,39 @@ func ProposalInstantiateContractCmd() *cobra.Command {
return err
}
src, err := parseInstantiateArgs(args, clientCtx)
src, err := parseInstantiateArgs(args[0], args[1], clientCtx.FromAddress, cmd.Flags())
if err != nil {
return err
}
if len(viper.GetString(flagRunAs)) == 0 {
return errors.New("creator address is required")
runAs, err := cmd.Flags().GetString(flagRunAs)
if err != nil {
return fmt.Errorf("run-as: %s", err)
}
if len(runAs) == 0 {
return errors.New("run-as address is required")
}
proposalTitle, err := cmd.Flags().GetString(cli.FlagTitle)
if err != nil {
return fmt.Errorf("proposal title: %s", err)
}
proposalDescr, err := cmd.Flags().GetString(cli.FlagDescription)
if err != nil {
return fmt.Errorf("proposal description: %s", err)
}
depositArg, err := cmd.Flags().GetString(cli.FlagDeposit)
if err != nil {
return err
}
deposit, err := sdk.ParseCoinsNormalized(depositArg)
if err != nil {
return err
}
content := types.InstantiateContractProposal{
Title: viper.GetString(cli.FlagTitle),
Description: viper.GetString(cli.FlagDescription),
RunAs: viper.GetString(flagRunAs),
Title: proposalTitle,
Description: proposalDescr,
RunAs: runAs,
Admin: src.Admin,
CodeID: src.CodeID,
Label: src.Label,
@@ -101,11 +141,6 @@ func ProposalInstantiateContractCmd() *cobra.Command {
InitFunds: src.InitFunds,
}
deposit, err := sdk.ParseCoinsNormalized(viper.GetString(cli.FlagDeposit))
if err != nil {
return err
}
msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
if err != nil {
return err
@@ -148,22 +183,37 @@ func ProposalMigrateContractCmd() *cobra.Command {
return err
}
if len(viper.GetString(flagRunAs)) == 0 {
runAs, err := cmd.Flags().GetString(flagRunAs)
if err != nil {
return fmt.Errorf("run-as: %s", err)
}
if len(runAs) == 0 {
return errors.New("run-as address is required")
}
proposalTitle, err := cmd.Flags().GetString(cli.FlagTitle)
if err != nil {
return fmt.Errorf("proposal title: %s", err)
}
proposalDescr, err := cmd.Flags().GetString(cli.FlagDescription)
if err != nil {
return fmt.Errorf("proposal description: %s", err)
}
depositArg, err := cmd.Flags().GetString(cli.FlagDeposit)
if err != nil {
return err
}
deposit, err := sdk.ParseCoinsNormalized(depositArg)
if err != nil {
return err
}
content := types.MigrateContractProposal{
Title: viper.GetString(cli.FlagTitle),
Description: viper.GetString(cli.FlagDescription),
Title: proposalTitle,
Description: proposalDescr,
Contract: src.Contract,
CodeID: src.CodeID,
MigrateMsg: src.MigrateMsg,
RunAs: viper.GetString(flagRunAs),
}
deposit, err := sdk.ParseCoinsNormalized(viper.GetString(cli.FlagDeposit))
if err != nil {
return err
RunAs: runAs,
}
msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
@@ -205,18 +255,30 @@ func ProposalUpdateContractAdminCmd() *cobra.Command {
return err
}
content := types.UpdateAdminProposal{
Title: viper.GetString(cli.FlagTitle),
Description: viper.GetString(cli.FlagDescription),
Contract: src.Contract,
NewAdmin: src.NewAdmin,
proposalTitle, err := cmd.Flags().GetString(cli.FlagTitle)
if err != nil {
return fmt.Errorf("proposal title: %s", err)
}
deposit, err := sdk.ParseCoinsNormalized(viper.GetString(cli.FlagDeposit))
proposalDescr, err := cmd.Flags().GetString(cli.FlagDescription)
if err != nil {
return fmt.Errorf("proposal description: %s", err)
}
depositArg, err := cmd.Flags().GetString(cli.FlagDeposit)
if err != nil {
return fmt.Errorf("deposit: %s", err)
}
deposit, err := sdk.ParseCoinsNormalized(depositArg)
if err != nil {
return err
}
content := types.UpdateAdminProposal{
Title: proposalTitle,
Description: proposalDescr,
Contract: src.Contract,
NewAdmin: src.NewAdmin,
}
msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
if err != nil {
return err
@@ -249,17 +311,29 @@ func ProposalClearContractAdminCmd() *cobra.Command {
return err
}
content := types.ClearAdminProposal{
Title: viper.GetString(cli.FlagTitle),
Description: viper.GetString(cli.FlagDescription),
Contract: args[0],
proposalTitle, err := cmd.Flags().GetString(cli.FlagTitle)
if err != nil {
return fmt.Errorf("proposal title: %s", err)
}
deposit, err := sdk.ParseCoinsNormalized(viper.GetString(cli.FlagDeposit))
proposalDescr, err := cmd.Flags().GetString(cli.FlagDescription)
if err != nil {
return fmt.Errorf("proposal description: %s", err)
}
depositArg, err := cmd.Flags().GetString(cli.FlagDeposit)
if err != nil {
return fmt.Errorf("deposit: %s", err)
}
deposit, err := sdk.ParseCoinsNormalized(depositArg)
if err != nil {
return err
}
content := types.ClearAdminProposal{
Title: proposalTitle,
Description: proposalDescr,
Contract: args[0],
}
msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
if err != nil {
return err

View File

@@ -47,7 +47,6 @@ func GetCmdListCode() *cobra.Command {
Long: "List all wasm bytecode on the chain",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
@@ -83,7 +82,6 @@ func GetCmdListContractByCode() *cobra.Command {
Long: "List wasm all bytecode on the chain for given code id",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
@@ -125,7 +123,6 @@ func GetCmdQueryCode() *cobra.Command {
Long: "Downloads wasm bytecode for given code id",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
@@ -218,7 +215,6 @@ func GetCmdGetContractStateAll() *cobra.Command {
Long: "Prints out all internal state of a contract given its address",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
@@ -260,7 +256,6 @@ func GetCmdGetContractStateRaw() *cobra.Command {
Long: "Prints out internal state for of a contract given its address",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
@@ -302,7 +297,6 @@ func GetCmdGetContractStateSmart() *cobra.Command {
Long: "Calls contract with given address with query data and prints the returned result",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err

View File

@@ -1,6 +1,7 @@
package cli
import (
"errors"
"fmt"
"io/ioutil"
"strconv"
@@ -13,7 +14,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
flag "github.com/spf13/pflag"
)
const (
@@ -56,8 +57,7 @@ func StoreCodeCmd() *cobra.Command {
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
msg, err := parseStoreCodeArgs(args, clientCtx)
msg, err := parseStoreCodeArgs(args[0], clientCtx.GetFromAddress(), cmd.Flags())
if err != nil {
return err
}
@@ -76,8 +76,8 @@ func StoreCodeCmd() *cobra.Command {
return cmd
}
func parseStoreCodeArgs(args []string, cliCtx client.Context) (types.MsgStoreCode, error) {
wasm, err := ioutil.ReadFile(args[0])
func parseStoreCodeArgs(file string, sender sdk.AccAddress, flags *flag.FlagSet) (types.MsgStoreCode, error) {
wasm, err := ioutil.ReadFile(file)
if err != nil {
return types.MsgStoreCode{}, err
}
@@ -94,23 +94,48 @@ func parseStoreCodeArgs(args []string, cliCtx client.Context) (types.MsgStoreCod
}
var perm *types.AccessConfig
if onlyAddrStr := viper.GetString(flagInstantiateByAddress); onlyAddrStr != "" {
onlyAddrStr, err := flags.GetString(flagInstantiateByAddress)
if err != nil {
return types.MsgStoreCode{}, fmt.Errorf("instantiate by address: %s", err)
}
if onlyAddrStr != "" {
allowedAddr, err := sdk.AccAddressFromBech32(onlyAddrStr)
if err != nil {
return types.MsgStoreCode{}, sdkerrors.Wrap(err, flagInstantiateByAddress)
}
x := types.AccessTypeOnlyAddress.With(allowedAddr)
perm = &x
} else if everybody := viper.GetBool(flagInstantiateByEverybody); everybody {
perm = &types.AllowEverybody
} else {
everybodyStr, err := flags.GetString(flagInstantiateByEverybody)
if err != nil {
return types.MsgStoreCode{}, fmt.Errorf("instantiate by everybody: %s", err)
}
if everybodyStr != "" {
ok, err := strconv.ParseBool(everybodyStr)
if err != nil {
return types.MsgStoreCode{}, fmt.Errorf("boolean value expected for instantiate by everybody: %s", err)
}
if ok {
perm = &types.AllowEverybody
}
}
}
// build and sign the transaction, then broadcast to Tendermint
source, err := flags.GetString(flagSource)
if err != nil {
return types.MsgStoreCode{}, fmt.Errorf("source: %s", err)
}
builder, err := flags.GetString(flagBuilder)
if err != nil {
return types.MsgStoreCode{}, fmt.Errorf("builder: %s", err)
}
msg := types.MsgStoreCode{
Sender: cliCtx.GetFromAddress().String(),
Sender: sender.String(),
WASMByteCode: wasm,
Source: viper.GetString(flagSource),
Builder: viper.GetString(flagBuilder),
Source: source,
Builder: builder,
InstantiatePermission: perm,
}
return msg, nil
@@ -126,7 +151,7 @@ func InstantiateContractCmd() *cobra.Command {
clientCtx, err := client.GetClientTxContext(cmd)
msg, err := parseInstantiateArgs(args, clientCtx)
msg, err := parseInstantiateArgs(args[0], args[1], clientCtx.GetFromAddress(), cmd.Flags())
if err != nil {
return err
}
@@ -144,29 +169,36 @@ func InstantiateContractCmd() *cobra.Command {
return cmd
}
func parseInstantiateArgs(args []string, cliCtx client.Context) (types.MsgInstantiateContract, error) {
func parseInstantiateArgs(rawCodeID, initMsg string, sender sdk.AccAddress, flags *flag.FlagSet) (types.MsgInstantiateContract, error) {
// get the id of the code to instantiate
codeID, err := strconv.ParseUint(args[0], 10, 64)
codeID, err := strconv.ParseUint(rawCodeID, 10, 64)
if err != nil {
return types.MsgInstantiateContract{}, err
}
amounstStr := viper.GetString(flagAmount)
amount, err := sdk.ParseCoinsNormalized(amounstStr)
amountStr, err := flags.GetString(flagAmount)
if err != nil {
return types.MsgInstantiateContract{}, err
return types.MsgInstantiateContract{}, fmt.Errorf("amount: %s", err)
}
amount, err := sdk.ParseCoinsNormalized(amountStr)
if err != nil {
return types.MsgInstantiateContract{}, fmt.Errorf("amount: %s", err)
}
label, err := flags.GetString(flagLabel)
if err != nil {
return types.MsgInstantiateContract{}, fmt.Errorf("label: %s", err)
}
label := viper.GetString(flagLabel)
if label == "" {
return types.MsgInstantiateContract{}, fmt.Errorf("Label is required on all contracts")
return types.MsgInstantiateContract{}, errors.New("label is required on all contracts")
}
adminStr, err := flags.GetString(flagAdmin)
if err != nil {
return types.MsgInstantiateContract{}, fmt.Errorf("admin: %s", err)
}
initMsg := args[1]
adminStr := viper.GetString(flagAdmin)
// build and sign the transaction, then broadcast to Tendermint
msg := types.MsgInstantiateContract{
Sender: cliCtx.GetFromAddress().String(),
Sender: sender.String(),
CodeID: codeID,
Label: label,
InitFunds: amount,
@@ -179,29 +211,16 @@ func parseInstantiateArgs(args []string, cliCtx client.Context) (types.MsgInstan
// ExecuteContractCmd will instantiate a contract from previously uploaded code.
func ExecuteContractCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "execute [contract_addr_bech32] [json_encoded_send_args]",
Use: "execute [contract_addr_bech32] [json_encoded_send_args] --amount [coins,optional]",
Short: "Execute a command on a wasm contract",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
// get the id of the code to instantiate
amounstStr := viper.GetString(flagAmount)
amount, err := sdk.ParseCoinsNormalized(amounstStr)
msg, err := parseExecuteArgs(args[0], args[1], clientCtx.GetFromAddress(), cmd.Flags())
if err != nil {
return err
}
execMsg := args[1]
// build and sign the transaction, then broadcast to Tendermint
msg := types.MsgExecuteContract{
Sender: clientCtx.GetFromAddress().String(),
Contract: args[0],
SentFunds: amount,
Msg: []byte(execMsg),
}
if err := msg.ValidateBasic(); err != nil {
return err
}
@@ -213,3 +232,22 @@ func ExecuteContractCmd() *cobra.Command {
flags.AddTxFlagsToCmd(cmd)
return cmd
}
func parseExecuteArgs(contractAddr string, execMsg string, sender sdk.AccAddress, flags *flag.FlagSet) (types.MsgExecuteContract, error) {
amountStr, err := flags.GetString(flagAmount)
if err != nil {
return types.MsgExecuteContract{}, fmt.Errorf("amount: %s", err)
}
amount, err := sdk.ParseCoinsNormalized(amountStr)
if err != nil {
return types.MsgExecuteContract{}, err
}
return types.MsgExecuteContract{
Sender: sender.String(),
Contract: contractAddr,
SentFunds: amount,
Msg: []byte(execMsg),
}, nil
}

View File

@@ -30,7 +30,7 @@ func TestGovRestHandlers(t *testing.T) {
"fees": []dict{{"denom": "ustake", "amount": "1000000"}},
}
)
encodingConfig := keeper.MakeEncodingConfig()
encodingConfig := keeper.MakeEncodingConfig(t)
clientCtx := client.Context{}.
WithJSONMarshaler(encodingConfig.Marshaler).
WithTxConfig(encodingConfig.TxConfig).

View File

@@ -79,7 +79,7 @@ func TestInitGenesis(t *testing.T) {
q2 := newData.module.LegacyQuerierHandler(nil)
// initialize new app with genstate
InitGenesis(newData.ctx, &newData.keeper, *genState)
InitGenesis(newData.ctx, &newData.keeper, *genState, newData.stakingKeeper, newData.module.Route().Handler())
// run same checks again on newdata, to make sure it was reinitialized correctly
assertCodeList(t, q2, newData.ctx, 1)

View File

@@ -4,21 +4,25 @@ import (
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
// authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
// "github.com/CosmWasm/wasmd/x/wasm/internal/types"
abci "github.com/tendermint/tendermint/abci/types"
)
// ValidatorSetSource is a subset of the staking keeper
type ValidatorSetSource interface {
ApplyAndReturnValidatorSetUpdates(sdk.Context) (updates []abci.ValidatorUpdate, err error)
}
// InitGenesis sets supply information for genesis.
//
// CONTRACT: all types of accounts must have been already initialized/created
func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState) error {
func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState, stakingKeeper ValidatorSetSource, msgHandler sdk.Handler) ([]abci.ValidatorUpdate, error) {
keeper.setParams(ctx, data.Params)
var maxCodeID uint64
for i, code := range data.Codes {
err := keeper.importCode(ctx, code.CodeID, code.CodeInfo, code.CodeBytes)
if err != nil {
return sdkerrors.Wrapf(err, "code %d with id: %d", i, code.CodeID)
return nil, sdkerrors.Wrapf(err, "code %d with id: %d", i, code.CodeID)
}
if code.CodeID > maxCodeID {
maxCodeID = code.CodeID
@@ -29,11 +33,11 @@ func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState) error
for i, contract := range data.Contracts {
contractAddr, err := sdk.AccAddressFromBech32(contract.ContractAddress)
if err != nil {
return sdkerrors.Wrapf(err, "address in contract number %d", i)
return nil, sdkerrors.Wrapf(err, "address in contract number %d", i)
}
err = keeper.importContract(ctx, contractAddr, &contract.ContractInfo, contract.ContractState)
if err != nil {
return sdkerrors.Wrapf(err, "contract number %d", i)
return nil, sdkerrors.Wrapf(err, "contract number %d", i)
}
maxContractID = i + 1 // not ideal but max(contractID) is not persisted otherwise
}
@@ -41,19 +45,32 @@ func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState) error
for i, seq := range data.Sequences {
err := keeper.importAutoIncrementID(ctx, seq.IDKey, seq.Value)
if err != nil {
return sdkerrors.Wrapf(err, "sequence number %d", i)
return nil, sdkerrors.Wrapf(err, "sequence number %d", i)
}
}
// sanity check seq values
if keeper.peekAutoIncrementID(ctx, types.KeyLastCodeID) <= maxCodeID {
return sdkerrors.Wrapf(types.ErrInvalid, "seq %s must be greater %d ", string(types.KeyLastCodeID), maxCodeID)
return nil, sdkerrors.Wrapf(types.ErrInvalid, "seq %s must be greater %d ", string(types.KeyLastCodeID), maxCodeID)
}
if keeper.peekAutoIncrementID(ctx, types.KeyLastInstanceID) <= uint64(maxContractID) {
return sdkerrors.Wrapf(types.ErrInvalid, "seq %s must be greater %d ", string(types.KeyLastInstanceID), maxContractID)
return nil, sdkerrors.Wrapf(types.ErrInvalid, "seq %s must be greater %d ", string(types.KeyLastInstanceID), maxContractID)
}
return nil
if len(data.GenMsgs) == 0 {
return nil, nil
}
for _, genTx := range data.GenMsgs {
msg := genTx.AsMsg()
if msg == nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "unknown message")
}
_, err := msgHandler(ctx, msg)
if err != nil {
return nil, sdkerrors.Wrap(err, "genesis")
}
}
return stakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
}
// ExportGenesis returns a GenesisState for a given context and keeper.

View File

@@ -5,6 +5,7 @@ import (
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"math/rand"
@@ -24,7 +25,9 @@ import (
fuzz "github.com/google/gofuzz"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/proto/tendermint/crypto"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
dbm "github.com/tendermint/tm-db"
)
@@ -96,7 +99,7 @@ func TestGenesisExportImport(t *testing.T) {
var importState wasmTypes.GenesisState
err = json.Unmarshal(exportedGenesis, &importState)
require.NoError(t, err)
InitGenesis(dstCtx, dstKeeper, importState)
InitGenesis(dstCtx, dstKeeper, importState, &StakingKeeperMock{}, TestHandler(dstKeeper))
// compare whole DB
for j := range srcStoreKeys {
@@ -126,14 +129,16 @@ func TestGenesisExportImport(t *testing.T) {
}
}
func TestFailFastImport(t *testing.T) {
func TestGenesisInit(t *testing.T) {
wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm")
require.NoError(t, err)
myCodeInfo := wasmTypes.CodeInfoFixture(wasmTypes.WithSHA256CodeHash(wasmCode))
specs := map[string]struct {
src types.GenesisState
expSuccess bool
src types.GenesisState
stakingMock StakingKeeperMock
msgHandlerMock MockMsgHandler
expSuccess bool
}{
"happy path: code info correct": {
src: types.GenesisState{
@@ -355,19 +360,51 @@ func TestFailFastImport(t *testing.T) {
Params: types.DefaultParams(),
},
},
"validator set update called for any genesis messages": {
src: wasmTypes.GenesisState{
GenMsgs: []types.GenesisState_GenMsgs{
{Sum: &types.GenesisState_GenMsgs_StoreCode{
StoreCode: types.MsgStoreCodeFixture(),
}},
},
Params: types.DefaultParams(),
},
stakingMock: StakingKeeperMock{expCalls: 1, validatorUpdate: []abci.ValidatorUpdate{
{PubKey: crypto.PublicKey{Sum: &crypto.PublicKey_Ed25519{
Ed25519: []byte("a valid key")}},
Power: 100,
},
}},
msgHandlerMock: MockMsgHandler{expCalls: 1, expMsg: types.MsgStoreCodeFixture()},
expSuccess: true,
},
"validator set update not called on genesis msg handler errors": {
src: wasmTypes.GenesisState{
GenMsgs: []types.GenesisState_GenMsgs{
{Sum: &types.GenesisState_GenMsgs_StoreCode{
StoreCode: types.MsgStoreCodeFixture(),
}},
},
Params: types.DefaultParams(),
},
msgHandlerMock: MockMsgHandler{expCalls: 1, err: errors.New("test error response")},
stakingMock: StakingKeeperMock{expCalls: 0},
},
}
for msg, spec := range specs {
t.Run(msg, func(t *testing.T) {
keeper, ctx, _ := setupKeeper(t)
require.NoError(t, types.ValidateGenesis(spec.src))
got := InitGenesis(ctx, keeper, spec.src)
if spec.expSuccess {
require.NoError(t, got)
gotValidatorSet, gotErr := InitGenesis(ctx, keeper, spec.src, &spec.stakingMock, spec.msgHandlerMock.Handle)
if !spec.expSuccess {
require.Error(t, gotErr)
return
}
require.Error(t, got)
require.NoError(t, gotErr)
spec.msgHandlerMock.verifyCalls(t)
spec.stakingMock.verifyCalls(t)
assert.Equal(t, spec.stakingMock.validatorUpdate, gotValidatorSet)
})
}
}
@@ -433,7 +470,7 @@ func TestImportContractWithCodeHistoryReset(t *testing.T) {
ctx = ctx.WithBlockHeight(0).WithGasMeter(sdk.NewInfiniteGasMeter())
// when
err = InitGenesis(ctx, keeper, importState)
_, err = InitGenesis(ctx, keeper, importState, &StakingKeeperMock{}, TestHandler(keeper))
require.NoError(t, err)
// verify wasm code
@@ -482,6 +519,76 @@ func TestImportContractWithCodeHistoryReset(t *testing.T) {
assert.Equal(t, expHistory, keeper.GetContractHistory(ctx, contractAddr))
}
func TestSupportedGenMsgTypes(t *testing.T) {
wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm")
require.NoError(t, err)
var (
myAddress sdk.AccAddress = bytes.Repeat([]byte{1}, sdk.AddrLen)
verifierAddress sdk.AccAddress = bytes.Repeat([]byte{2}, sdk.AddrLen)
beneficiaryAddress sdk.AccAddress = bytes.Repeat([]byte{3}, sdk.AddrLen)
)
const denom = "stake"
importState := types.GenesisState{
Params: types.DefaultParams(),
GenMsgs: []types.GenesisState_GenMsgs{
{
Sum: &types.GenesisState_GenMsgs_StoreCode{
StoreCode: &types.MsgStoreCode{
Sender: myAddress.String(),
WASMByteCode: wasmCode,
},
},
},
{
Sum: &types.GenesisState_GenMsgs_InstantiateContract{
InstantiateContract: &types.MsgInstantiateContract{
Sender: myAddress.String(),
CodeID: 1,
Label: "testing",
InitMsg: HackatomExampleInitMsg{
Verifier: verifierAddress,
Beneficiary: beneficiaryAddress,
}.GetBytes(t),
InitFunds: sdk.NewCoins(sdk.NewCoin(denom, sdk.NewInt(10))),
},
},
},
{
Sum: &types.GenesisState_GenMsgs_ExecuteContract{
ExecuteContract: &types.MsgExecuteContract{
Sender: verifierAddress.String(),
Contract: contractAddress(1, 1).String(),
Msg: []byte(`{"release":{}}`),
},
},
},
},
}
require.NoError(t, importState.ValidateBasic())
ctx, keepers := CreateDefaultTestInput(t)
keeper := keepers.WasmKeeper
ctx = ctx.WithBlockHeight(0).WithGasMeter(sdk.NewInfiniteGasMeter())
fundAccounts(t, ctx, keepers.AccountKeeper, keepers.BankKeeper, myAddress, sdk.NewCoins(sdk.NewCoin(denom, sdk.NewInt(100))))
// when
_, err = InitGenesis(ctx, keeper, importState, &StakingKeeperMock{}, TestHandler(keeper))
require.NoError(t, err)
// verify code stored
gotWasmCode, err := keeper.GetByteCode(ctx, 1)
require.NoError(t, err)
assert.Equal(t, wasmCode, gotWasmCode)
codeInfo := keeper.GetCodeInfo(ctx, 1)
require.NotNil(t, codeInfo)
// verify contract instantiated
cInfo := keeper.GetContractInfo(ctx, contractAddress(1, 1))
require.NotNil(t, cInfo)
// verify contract executed
gotBalance := keepers.BankKeeper.GetBalance(ctx, beneficiaryAddress, denom)
assert.Equal(t, sdk.NewCoin(denom, sdk.NewInt(10)), gotBalance)
}
func setupKeeper(t *testing.T) (*Keeper, sdk.Context, []sdk.StoreKey) {
t.Helper()
tempDir, err := ioutil.TempDir("", "wasm")
@@ -505,10 +612,46 @@ func setupKeeper(t *testing.T) (*Keeper, sdk.Context, []sdk.StoreKey) {
Time: time.Date(2020, time.April, 22, 12, 0, 0, 0, time.UTC),
}, false, log.NewNopLogger())
encodingConfig := MakeEncodingConfig()
encodingConfig := MakeEncodingConfig(t)
wasmConfig := wasmTypes.DefaultWasmConfig()
pk := paramskeeper.NewKeeper(encodingConfig.Marshaler, encodingConfig.Amino, keyParams, tkeyParams)
srcKeeper := NewKeeper(encodingConfig.Marshaler, keyWasm, pk.Subspace(wasmTypes.DefaultParamspace), authkeeper.AccountKeeper{}, nil, stakingkeeper.Keeper{}, distributionkeeper.Keeper{}, nil, tempDir, wasmConfig, "", nil, nil)
return &srcKeeper, ctx, []sdk.StoreKey{keyWasm, keyParams}
}
type StakingKeeperMock struct {
err error
validatorUpdate []abci.ValidatorUpdate
expCalls int
gotCalls int
}
func (s *StakingKeeperMock) ApplyAndReturnValidatorSetUpdates(_ sdk.Context) ([]abci.ValidatorUpdate, error) {
s.gotCalls++
return s.validatorUpdate, s.err
}
func (s *StakingKeeperMock) verifyCalls(t *testing.T) {
assert.Equal(t, s.expCalls, s.gotCalls, "number calls")
}
type MockMsgHandler struct {
result *sdk.Result
err error
expCalls int
gotCalls int
expMsg sdk.Msg
gotMsg sdk.Msg
}
func (m *MockMsgHandler) Handle(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
m.gotCalls++
m.gotMsg = msg
return m.result, m.err
}
func (m *MockMsgHandler) verifyCalls(t *testing.T) {
assert.Equal(t, m.expMsg, m.gotMsg, "message param")
assert.Equal(t, m.expCalls, m.gotCalls, "number calls")
}

View File

@@ -628,14 +628,17 @@ func (k Keeper) generateContractAddress(ctx sdk.Context, codeID uint64) sdk.AccA
return contractAddress(codeID, instanceID)
}
// contractAddress builds an sdk account address for a contract.
// Intentionally kept private as this is module internal logic.
func contractAddress(codeID, instanceID uint64) sdk.AccAddress {
// NOTE: It is possible to get a duplicate address if either codeID or instanceID
// overflow 32 bits. This is highly improbable, but something that could be refactored.
contractID := codeID<<32 + instanceID
return addrFromUint64(contractID)
}
// GetNextCodeID reads the next sequence id used for storing wasm code.
// Read only operation.
func (k Keeper) GetNextCodeID(ctx sdk.Context) uint64 {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.KeyLastCodeID)

View File

@@ -72,7 +72,7 @@ func mustParse(t *testing.T, data []byte, res interface{}) {
const MaskFeatures = "staking,mask"
func TestMaskReflectContractSend(t *testing.T) {
cdc := MakeTestCodec()
cdc := MakeTestCodec(t)
ctx, keepers := CreateTestInput(t, false, MaskFeatures, maskEncoders(cdc), nil)
accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.WasmKeeper, keepers.BankKeeper
@@ -154,7 +154,7 @@ func TestMaskReflectContractSend(t *testing.T) {
}
func TestMaskReflectCustomMsg(t *testing.T) {
cdc := MakeTestCodec()
cdc := MakeTestCodec(t)
ctx, keepers := CreateTestInput(t, false, MaskFeatures, maskEncoders(cdc), maskPlugins())
accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.WasmKeeper, keepers.BankKeeper
@@ -248,7 +248,7 @@ func TestMaskReflectCustomMsg(t *testing.T) {
}
func TestMaskReflectCustomQuery(t *testing.T) {
cdc := MakeTestCodec()
cdc := MakeTestCodec(t)
ctx, keepers := CreateTestInput(t, false, MaskFeatures, maskEncoders(cdc), maskPlugins())
accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.WasmKeeper, keepers.BankKeeper
@@ -302,7 +302,7 @@ type maskState struct {
}
func TestMaskReflectWasmQueries(t *testing.T) {
ctx, keepers := CreateTestInput(t, false, MaskFeatures, maskEncoders(MakeTestCodec()), nil)
ctx, keepers := CreateTestInput(t, false, MaskFeatures, maskEncoders(MakeTestCodec(t)), nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
@@ -373,7 +373,7 @@ func TestMaskReflectWasmQueries(t *testing.T) {
}
func TestWasmRawQueryWithNil(t *testing.T) {
ctx, keepers := CreateTestInput(t, false, MaskFeatures, maskEncoders(MakeTestCodec()), nil)
ctx, keepers := CreateTestInput(t, false, MaskFeatures, maskEncoders(MakeTestCodec(t)), nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))

View File

@@ -6,7 +6,6 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"testing"
"time"
@@ -84,10 +83,11 @@ var ModuleBasics = module.NewBasicManager(
transfer.AppModuleBasic{},
)
func MakeTestCodec() codec.Marshaler {
return MakeEncodingConfig().Marshaler
func MakeTestCodec(t *testing.T) codec.Marshaler {
return MakeEncodingConfig(t).Marshaler
}
func MakeEncodingConfig() params2.EncodingConfig {
func MakeEncodingConfig(_ *testing.T) params2.EncodingConfig {
amino := codec.NewLegacyAmino()
interfaceRegistry := codectypes.NewInterfaceRegistry()
marshaler := codec.NewProtoCodec(interfaceRegistry)
@@ -123,11 +123,14 @@ type TestKeepers struct {
WasmKeeper *Keeper
}
// CreateDefaultTestInput common settings for CreateTestInput
func CreateDefaultTestInput(t *testing.T) (sdk.Context, TestKeepers) {
return CreateTestInput(t, false, "staking", nil, nil)
}
// encoders can be nil to accept the defaults, or set it to override some of the message handlers (like default)
func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, encoders *MessageEncoders, queriers *QueryPlugins) (sdk.Context, TestKeepers) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
t.Cleanup(func() { os.RemoveAll(tempDir) })
tempDir := t.TempDir()
keyWasm := sdk.NewKVStoreKey(types.StoreKey)
keyAcc := sdk.NewKVStoreKey(authtypes.StoreKey)
@@ -154,7 +157,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc
Height: 1234567,
Time: time.Date(2020, time.April, 22, 12, 0, 0, 0, time.UTC),
}, isCheckTx, log.NewNopLogger())
encodingConfig := MakeEncodingConfig()
encodingConfig := MakeEncodingConfig(t)
appCodec, legacyAmino := encodingConfig.Marshaler, encodingConfig.Amino
paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, keyParams, tkeyParams)
@@ -216,7 +219,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc
// set some funds ot pay out validatores, based on code from:
// https://github.com/cosmos/cosmos-sdk/blob/fea231556aee4d549d7551a6190389c4328194eb/x/distribution/keeper/keeper_test.go#L50-L57
distrAcc := distKeeper.GetDistributionAccount(ctx)
err = bankKeeper.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins(
err := bankKeeper.SetBalances(ctx, distrAcc.GetAddress(), sdk.NewCoins(
sdk.NewCoin("stake", sdk.NewInt(2000000)),
))
require.NoError(t, err)
@@ -282,14 +285,13 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc
func TestHandler(k *Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
switch msg := msg.(type) {
case *types.MsgStoreCode:
return handleStoreCode(ctx, k, msg)
case *types.MsgInstantiateContract:
return handleInstantiate(ctx, k, msg)
case *types.MsgExecuteContract:
return handleExecute(ctx, k, msg)
default:
errMsg := fmt.Sprintf("unrecognized wasm message type: %T", msg)
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg)
@@ -297,15 +299,34 @@ func TestHandler(k *Keeper) sdk.Handler {
}
}
func handleStoreCode(ctx sdk.Context, k *Keeper, msg *types.MsgStoreCode) (*sdk.Result, error) {
senderAddr, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
return nil, sdkerrors.Wrap(err, "sender")
}
codeID, err := k.Create(ctx, senderAddr, msg.WASMByteCode, msg.Source, msg.Builder, msg.InstantiatePermission)
if err != nil {
return nil, err
}
return &sdk.Result{
Data: []byte(fmt.Sprintf("%d", codeID)),
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
func handleInstantiate(ctx sdk.Context, k *Keeper, msg *types.MsgInstantiateContract) (*sdk.Result, error) {
senderAddr, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
return nil, sdkerrors.Wrap(err, "sender")
}
adminAddr, err := sdk.AccAddressFromBech32(msg.Admin)
if err != nil {
return nil, sdkerrors.Wrap(err, "admin")
var adminAddr sdk.AccAddress
if msg.Admin != "" {
if adminAddr, err = sdk.AccAddressFromBech32(msg.Admin); err != nil {
return nil, sdkerrors.Wrap(err, "admin")
}
}
contractAddr, err := k.Instantiate(ctx, msg.CodeID, senderAddr, adminAddr, msg.InitMsg, msg.Label, msg.InitFunds)
if err != nil {
return nil, err

View File

@@ -32,6 +32,11 @@ func (s GenesisState) ValidateBasic() error {
return sdkerrors.Wrapf(err, "sequence: %d", i)
}
}
for i := range s.GenMsgs {
if err := s.GenMsgs[i].ValidateBasic(); err != nil {
return sdkerrors.Wrapf(err, "gen message: %d", i)
}
}
return nil
}
@@ -67,6 +72,28 @@ func (c Contract) ValidateBasic() error {
return nil
}
// AsMsg returns the underlying cosmos-sdk message instance. Null when can not be mapped to a known type.
func (m GenesisState_GenMsgs) AsMsg() sdk.Msg {
if msg := m.GetStoreCode(); msg != nil {
return msg
}
if msg := m.GetInstantiateContract(); msg != nil {
return msg
}
if msg := m.GetExecuteContract(); msg != nil {
return msg
}
return nil
}
func (m GenesisState_GenMsgs) ValidateBasic() error {
msg := m.AsMsg()
if msg == nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "unknown message")
}
return msg.ValidateBasic()
}
// ValidateGenesis performs basic validation of supply genesis data returning an
// error for any failed validation criteria.
func ValidateGenesis(data GenesisState) error {

View File

@@ -25,10 +25,11 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// GenesisState - genesis state of x/wasm
type GenesisState struct {
Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"`
Codes []Code `protobuf:"bytes,2,rep,name=codes,proto3" json:"codes,omitempty"`
Contracts []Contract `protobuf:"bytes,3,rep,name=contracts,proto3" json:"contracts,omitempty"`
Sequences []Sequence `protobuf:"bytes,4,rep,name=sequences,proto3" json:"sequences,omitempty"`
Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"`
Codes []Code `protobuf:"bytes,2,rep,name=codes,proto3" json:"codes,omitempty"`
Contracts []Contract `protobuf:"bytes,3,rep,name=contracts,proto3" json:"contracts,omitempty"`
Sequences []Sequence `protobuf:"bytes,4,rep,name=sequences,proto3" json:"sequences,omitempty"`
GenMsgs []GenesisState_GenMsgs `protobuf:"bytes,5,rep,name=gen_msgs,json=genMsgs,proto3" json:"gen_msgs,omitempty"`
}
func (m *GenesisState) Reset() { *m = GenesisState{} }
@@ -92,6 +93,115 @@ func (m *GenesisState) GetSequences() []Sequence {
return nil
}
func (m *GenesisState) GetGenMsgs() []GenesisState_GenMsgs {
if m != nil {
return m.GenMsgs
}
return nil
}
// GenMsgs define the messages that can be executed during genesis phase.
// The intention is to have more human readable data that is auditable.
type GenesisState_GenMsgs struct {
// sum is a single message
//
// Types that are valid to be assigned to Sum:
// *GenesisState_GenMsgs_StoreCode
// *GenesisState_GenMsgs_InstantiateContract
// *GenesisState_GenMsgs_ExecuteContract
Sum isGenesisState_GenMsgs_Sum `protobuf_oneof:"sum"`
}
func (m *GenesisState_GenMsgs) Reset() { *m = GenesisState_GenMsgs{} }
func (m *GenesisState_GenMsgs) String() string { return proto.CompactTextString(m) }
func (*GenesisState_GenMsgs) ProtoMessage() {}
func (*GenesisState_GenMsgs) Descriptor() ([]byte, []int) {
return fileDescriptor_52f9f2715025dba8, []int{0, 0}
}
func (m *GenesisState_GenMsgs) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *GenesisState_GenMsgs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_GenesisState_GenMsgs.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *GenesisState_GenMsgs) XXX_Merge(src proto.Message) {
xxx_messageInfo_GenesisState_GenMsgs.Merge(m, src)
}
func (m *GenesisState_GenMsgs) XXX_Size() int {
return m.Size()
}
func (m *GenesisState_GenMsgs) XXX_DiscardUnknown() {
xxx_messageInfo_GenesisState_GenMsgs.DiscardUnknown(m)
}
var xxx_messageInfo_GenesisState_GenMsgs proto.InternalMessageInfo
type isGenesisState_GenMsgs_Sum interface {
isGenesisState_GenMsgs_Sum()
MarshalTo([]byte) (int, error)
Size() int
}
type GenesisState_GenMsgs_StoreCode struct {
StoreCode *MsgStoreCode `protobuf:"bytes,1,opt,name=store_code,json=storeCode,proto3,oneof" json:"store_code,omitempty"`
}
type GenesisState_GenMsgs_InstantiateContract struct {
InstantiateContract *MsgInstantiateContract `protobuf:"bytes,2,opt,name=instantiate_contract,json=instantiateContract,proto3,oneof" json:"instantiate_contract,omitempty"`
}
type GenesisState_GenMsgs_ExecuteContract struct {
ExecuteContract *MsgExecuteContract `protobuf:"bytes,3,opt,name=execute_contract,json=executeContract,proto3,oneof" json:"execute_contract,omitempty"`
}
func (*GenesisState_GenMsgs_StoreCode) isGenesisState_GenMsgs_Sum() {}
func (*GenesisState_GenMsgs_InstantiateContract) isGenesisState_GenMsgs_Sum() {}
func (*GenesisState_GenMsgs_ExecuteContract) isGenesisState_GenMsgs_Sum() {}
func (m *GenesisState_GenMsgs) GetSum() isGenesisState_GenMsgs_Sum {
if m != nil {
return m.Sum
}
return nil
}
func (m *GenesisState_GenMsgs) GetStoreCode() *MsgStoreCode {
if x, ok := m.GetSum().(*GenesisState_GenMsgs_StoreCode); ok {
return x.StoreCode
}
return nil
}
func (m *GenesisState_GenMsgs) GetInstantiateContract() *MsgInstantiateContract {
if x, ok := m.GetSum().(*GenesisState_GenMsgs_InstantiateContract); ok {
return x.InstantiateContract
}
return nil
}
func (m *GenesisState_GenMsgs) GetExecuteContract() *MsgExecuteContract {
if x, ok := m.GetSum().(*GenesisState_GenMsgs_ExecuteContract); ok {
return x.ExecuteContract
}
return nil
}
// XXX_OneofWrappers is for the internal use of the proto package.
func (*GenesisState_GenMsgs) XXX_OneofWrappers() []interface{} {
return []interface{}{
(*GenesisState_GenMsgs_StoreCode)(nil),
(*GenesisState_GenMsgs_InstantiateContract)(nil),
(*GenesisState_GenMsgs_ExecuteContract)(nil),
}
}
// Code struct encompasses CodeInfo and CodeBytes
type Code struct {
CodeID uint64 `protobuf:"varint,1,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"`
@@ -269,6 +379,7 @@ func (m *Sequence) GetValue() uint64 {
func init() {
proto.RegisterType((*GenesisState)(nil), "cosmwasm.wasm.v1beta1.GenesisState")
proto.RegisterType((*GenesisState_GenMsgs)(nil), "cosmwasm.wasm.v1beta1.GenesisState.GenMsgs")
proto.RegisterType((*Code)(nil), "cosmwasm.wasm.v1beta1.Code")
proto.RegisterType((*Contract)(nil), "cosmwasm.wasm.v1beta1.Contract")
proto.RegisterType((*Sequence)(nil), "cosmwasm.wasm.v1beta1.Sequence")
@@ -279,39 +390,47 @@ func init() {
}
var fileDescriptor_52f9f2715025dba8 = []byte{
// 510 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0xc1, 0x6f, 0xd3, 0x3e,
0x14, 0xc7, 0x9b, 0x2e, 0xcd, 0xaf, 0xf5, 0xfa, 0x63, 0xc8, 0x0c, 0x11, 0x6d, 0x2c, 0x29, 0xed,
0xa5, 0x48, 0x28, 0x61, 0xe3, 0xc8, 0x89, 0x6c, 0x12, 0xca, 0x26, 0x10, 0xca, 0x0e, 0x48, 0xbb,
0x54, 0x6e, 0xfc, 0x56, 0x22, 0x9a, 0xb8, 0xc4, 0xee, 0x58, 0xfe, 0x09, 0xc4, 0x9f, 0xb5, 0x1b,
0x3d, 0x72, 0xaa, 0x50, 0x7a, 0xe3, 0xaf, 0x40, 0x76, 0xd2, 0x2c, 0x48, 0xeb, 0xb8, 0xa4, 0xf5,
0xf3, 0xf7, 0x7d, 0xfc, 0xde, 0xf7, 0xd9, 0x68, 0x70, 0xed, 0x7e, 0x25, 0x3c, 0x76, 0xa3, 0x44,
0x40, 0x9a, 0x90, 0xa9, 0x2b, 0xb2, 0x19, 0x70, 0x77, 0x02, 0x09, 0xf0, 0x88, 0x3b, 0xb3, 0x94,
0x09, 0x86, 0x1f, 0x87, 0x8c, 0xc7, 0x52, 0xe6, 0xa8, 0xcf, 0xd5, 0xe1, 0x18, 0x04, 0x39, 0xdc,
0xdb, 0x9d, 0xb0, 0x09, 0x53, 0x0a, 0x57, 0xfe, 0x2b, 0xc4, 0x7b, 0xcf, 0xee, 0x26, 0xaa, 0x6f,
0x21, 0xe9, 0xff, 0x68, 0xa2, 0xee, 0xdb, 0xe2, 0x84, 0x73, 0x41, 0x04, 0xe0, 0xd7, 0xc8, 0x98,
0x91, 0x94, 0xc4, 0xdc, 0xd4, 0x7a, 0xda, 0x70, 0xfb, 0xe8, 0xc0, 0xb9, 0xf3, 0x44, 0xe7, 0x83,
0x12, 0x79, 0xfa, 0xcd, 0xd2, 0x6e, 0x04, 0x65, 0x0a, 0x3e, 0x45, 0xad, 0x90, 0x51, 0xe0, 0x66,
0xb3, 0xb7, 0x35, 0xdc, 0x3e, 0xda, 0xdf, 0x90, 0x7b, 0xcc, 0x28, 0x78, 0x4f, 0x64, 0xe6, 0xef,
0xa5, 0xbd, 0xa3, 0x32, 0x5e, 0xb0, 0x38, 0x12, 0x10, 0xcf, 0x44, 0x16, 0x14, 0x08, 0x7c, 0x81,
0x3a, 0x21, 0x4b, 0x44, 0x4a, 0x42, 0xc1, 0xcd, 0x2d, 0xc5, 0xb3, 0x37, 0xf2, 0x0a, 0x9d, 0xb7,
0x5f, 0x32, 0x1f, 0x55, 0x99, 0x35, 0xee, 0x2d, 0x4e, 0xb2, 0x39, 0x7c, 0x99, 0x43, 0x12, 0x02,
0x37, 0xf5, 0x7b, 0xd9, 0xe7, 0xa5, 0xee, 0x96, 0x5d, 0x65, 0xd6, 0xd9, 0x55, 0xb0, 0xff, 0x4d,
0x43, 0xba, 0x6c, 0x10, 0x0f, 0xd0, 0x7f, 0xb2, 0x93, 0x51, 0x44, 0x95, 0x95, 0xba, 0x87, 0xf2,
0xa5, 0x6d, 0xc8, 0x2d, 0xff, 0x24, 0x30, 0xe4, 0x96, 0x4f, 0xb1, 0x27, 0xbb, 0x94, 0xa2, 0xe4,
0x92, 0x99, 0x4d, 0xe5, 0xb8, 0x7d, 0x8f, 0x6b, 0x7e, 0x72, 0xc9, 0x4a, 0xcf, 0xdb, 0x61, 0xb9,
0xc6, 0x07, 0x08, 0x29, 0xc6, 0x38, 0x13, 0x20, 0xad, 0xd2, 0x86, 0xdd, 0x40, 0x51, 0x3d, 0x19,
0xe8, 0x2f, 0x34, 0xd4, 0x5e, 0x3b, 0x84, 0x9f, 0xa3, 0x87, 0x6b, 0x1b, 0x46, 0x84, 0xd2, 0x14,
0x78, 0x31, 0xe8, 0x4e, 0xb0, 0xb3, 0x8e, 0xbf, 0x29, 0xc2, 0xf8, 0x3d, 0xfa, 0xbf, 0x92, 0xd6,
0xca, 0x1b, 0xfc, 0x63, 0x08, 0xb5, 0x12, 0xbb, 0x61, 0x2d, 0x86, 0x7d, 0xf4, 0xa0, 0xe2, 0x71,
0x79, 0xd7, 0xca, 0xa9, 0x3e, 0xdd, 0x00, 0x7c, 0xc7, 0x28, 0x4c, 0x4b, 0x52, 0x55, 0x89, 0xba,
0xa4, 0x7d, 0x0f, 0xb5, 0xd7, 0x73, 0xc1, 0x3d, 0x64, 0x44, 0x74, 0xf4, 0x19, 0x32, 0xd5, 0x47,
0xd7, 0xeb, 0xe4, 0x4b, 0xbb, 0xe5, 0x9f, 0x9c, 0x41, 0x16, 0xb4, 0x22, 0x7a, 0x06, 0x19, 0xde,
0x45, 0xad, 0x2b, 0x32, 0x9d, 0x83, 0x6a, 0x40, 0x0f, 0x8a, 0x85, 0x77, 0x7a, 0x93, 0x5b, 0xda,
0x22, 0xb7, 0xb4, 0x5f, 0xb9, 0xa5, 0x7d, 0x5f, 0x59, 0x8d, 0xc5, 0xca, 0x6a, 0xfc, 0x5c, 0x59,
0x8d, 0x8b, 0x97, 0x93, 0x48, 0x7c, 0x9a, 0x8f, 0x9d, 0x90, 0xc5, 0xee, 0x31, 0xe3, 0xf1, 0x47,
0xf9, 0x86, 0x64, 0x69, 0xd4, 0xbd, 0x2e, 0x7f, 0xff, 0x7e, 0x51, 0x63, 0x43, 0x3d, 0xa6, 0x57,
0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x56, 0x37, 0xff, 0x93, 0xc3, 0x03, 0x00, 0x00,
// 639 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x94, 0xc1, 0x6e, 0xd3, 0x40,
0x10, 0x86, 0xe3, 0x26, 0x4e, 0x93, 0x6d, 0xa0, 0xd5, 0xb6, 0x88, 0x28, 0xa5, 0x71, 0x49, 0x2e,
0xad, 0x80, 0x98, 0x96, 0x23, 0x27, 0xdc, 0x22, 0x9a, 0x56, 0x45, 0xc8, 0x95, 0x40, 0xea, 0x25,
0x72, 0xec, 0xa9, 0xb1, 0xa8, 0xbd, 0x21, 0xb3, 0x29, 0xf5, 0x4b, 0x20, 0xc4, 0x53, 0xf5, 0xd8,
0x23, 0xa7, 0x08, 0xa5, 0x37, 0x9e, 0x02, 0xed, 0x7a, 0xed, 0xba, 0x22, 0x2e, 0x17, 0x27, 0x3b,
0xfe, 0xff, 0xcf, 0x33, 0xb3, 0xb3, 0x4b, 0xba, 0x97, 0xe6, 0x37, 0x07, 0x43, 0x33, 0x88, 0x38,
0x8c, 0x23, 0xe7, 0xdc, 0xe4, 0xf1, 0x08, 0xd0, 0xf4, 0x21, 0x02, 0x0c, 0xb0, 0x37, 0x1a, 0x33,
0xce, 0xe8, 0x23, 0x97, 0x61, 0x28, 0x64, 0x3d, 0xf9, 0xb8, 0xd8, 0x19, 0x02, 0x77, 0x76, 0x5a,
0x6b, 0x3e, 0xf3, 0x99, 0x54, 0x98, 0xe2, 0x5f, 0x22, 0x6e, 0x3d, 0x9d, 0x4f, 0x94, 0x4f, 0x25,
0x31, 0xe6, 0x4b, 0x42, 0xf4, 0x13, 0x41, 0xe7, 0x4a, 0x27, 0x8d, 0x77, 0x49, 0x0a, 0x27, 0xdc,
0xe1, 0x40, 0x5f, 0x93, 0xea, 0xc8, 0x19, 0x3b, 0x21, 0x36, 0xb5, 0x4d, 0x6d, 0x6b, 0x69, 0x77,
0xa3, 0x37, 0x37, 0xa5, 0xde, 0x07, 0x29, 0xb2, 0x2a, 0x57, 0x53, 0xa3, 0x64, 0x2b, 0x0b, 0x3d,
0x24, 0xba, 0xcb, 0x3c, 0xc0, 0xe6, 0xc2, 0x66, 0x79, 0x6b, 0x69, 0x77, 0xbd, 0xc0, 0xbb, 0xc7,
0x3c, 0xb0, 0x1e, 0x0b, 0xe7, 0x9f, 0xa9, 0xb1, 0x2c, 0x1d, 0xcf, 0x59, 0x18, 0x70, 0x08, 0x47,
0x3c, 0xb6, 0x13, 0x04, 0x3d, 0x25, 0x75, 0x97, 0x45, 0x7c, 0xec, 0xb8, 0x1c, 0x9b, 0x65, 0xc9,
0x33, 0x0a, 0x79, 0x89, 0xce, 0x5a, 0x57, 0xcc, 0xd5, 0xcc, 0x99, 0xe3, 0xde, 0xe2, 0x04, 0x1b,
0xe1, 0xeb, 0x04, 0x22, 0x17, 0xb0, 0x59, 0xb9, 0x97, 0x7d, 0xa2, 0x74, 0xb7, 0xec, 0xcc, 0x99,
0x67, 0x67, 0x41, 0x3a, 0x24, 0x35, 0x1f, 0xa2, 0x41, 0x88, 0x3e, 0x36, 0x75, 0x89, 0x7e, 0x56,
0x80, 0xce, 0xf7, 0x5d, 0x2c, 0x8e, 0xd1, 0x47, 0xab, 0xa5, 0x3e, 0x43, 0x53, 0x48, 0xee, 0x2b,
0x8b, 0x7e, 0x22, 0x6a, 0xfd, 0x5c, 0x20, 0x8b, 0xca, 0x40, 0xf7, 0x09, 0x41, 0xce, 0xc6, 0x30,
0x10, 0x6d, 0x53, 0x9b, 0xd6, 0x2d, 0xf8, 0xe2, 0x31, 0xfa, 0x27, 0x42, 0x2b, 0x36, 0xe0, 0xa0,
0x64, 0xd7, 0x31, 0x5d, 0xd0, 0x21, 0x59, 0x0b, 0x22, 0xe4, 0x4e, 0xc4, 0x03, 0x87, 0x0b, 0x56,
0xd2, 0xaa, 0xe6, 0x82, 0xe4, 0xbd, 0x28, 0xe6, 0xf5, 0x6f, 0x5d, 0xe9, 0x36, 0x1c, 0x94, 0xec,
0xd5, 0xe0, 0xdf, 0x30, 0xfd, 0x48, 0x56, 0xe0, 0x12, 0xdc, 0x49, 0x9e, 0x5f, 0x96, 0xfc, 0xed,
0x62, 0xfe, 0xdb, 0xc4, 0x91, 0x63, 0x2f, 0xc3, 0xdd, 0x90, 0xa5, 0x93, 0x32, 0x4e, 0xc2, 0xce,
0x77, 0x8d, 0x54, 0x64, 0x2d, 0x5d, 0xb2, 0x28, 0x7a, 0x31, 0x08, 0x3c, 0xd9, 0x8e, 0x8a, 0x45,
0x66, 0x53, 0xa3, 0x2a, 0x5e, 0xf5, 0xf7, 0xed, 0xaa, 0x78, 0xd5, 0xf7, 0xa8, 0x25, 0xc6, 0x4b,
0x88, 0xa2, 0x33, 0xa6, 0xaa, 0x34, 0xee, 0x19, 0xd7, 0x7e, 0x74, 0xc6, 0xd4, 0xb0, 0xd7, 0x5c,
0xb5, 0xa6, 0x1b, 0x84, 0x48, 0xc6, 0x30, 0xe6, 0x80, 0xb2, 0x94, 0x86, 0x2d, 0xa9, 0x96, 0x08,
0x74, 0xae, 0x35, 0x52, 0xcb, 0x8a, 0xdf, 0x26, 0x2b, 0x69, 0xd1, 0x03, 0xc7, 0xf3, 0xc6, 0x80,
0xc9, 0x09, 0xab, 0xdb, 0xcb, 0x69, 0xfc, 0x4d, 0x12, 0xa6, 0xef, 0xc9, 0x83, 0x4c, 0x9a, 0x4b,
0xaf, 0xfb, 0x9f, 0xe9, 0xcf, 0xa5, 0xd8, 0x70, 0x73, 0x31, 0xda, 0x27, 0x0f, 0x33, 0x1e, 0x8a,
0x61, 0x53, 0xc7, 0xe9, 0x49, 0x51, 0xd7, 0x99, 0x07, 0xe7, 0x8a, 0x94, 0x65, 0x22, 0xa7, 0xb4,
0x63, 0x91, 0x5a, 0x7a, 0x20, 0xe8, 0x26, 0xa9, 0x06, 0xde, 0xe0, 0x0b, 0xc4, 0xb2, 0x8e, 0x86,
0x55, 0x9f, 0x4d, 0x0d, 0xbd, 0xbf, 0x7f, 0x04, 0xb1, 0xad, 0x07, 0xde, 0x11, 0xc4, 0x74, 0x8d,
0xe8, 0x17, 0xce, 0xf9, 0x04, 0x64, 0x01, 0x15, 0x3b, 0x59, 0x58, 0x87, 0x57, 0xb3, 0xb6, 0x76,
0x3d, 0x6b, 0x6b, 0xbf, 0x67, 0x6d, 0xed, 0xc7, 0x4d, 0xbb, 0x74, 0x7d, 0xd3, 0x2e, 0xfd, 0xba,
0x69, 0x97, 0x4e, 0x5f, 0xfa, 0x01, 0xff, 0x3c, 0x19, 0xf6, 0x5c, 0x16, 0x9a, 0x7b, 0x0c, 0xc3,
0x4f, 0xe2, 0xea, 0x12, 0xa9, 0x79, 0xe6, 0xa5, 0xfa, 0xbd, 0x7b, 0x91, 0x0d, 0xab, 0xf2, 0x16,
0x7b, 0xf5, 0x37, 0x00, 0x00, 0xff, 0xff, 0xc2, 0xba, 0x9d, 0x7b, 0x5d, 0x05, 0x00, 0x00,
}
func (m *GenesisState) Marshal() (dAtA []byte, err error) {
@@ -334,6 +453,20 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if len(m.GenMsgs) > 0 {
for iNdEx := len(m.GenMsgs) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.GenMsgs[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x2a
}
}
if len(m.Sequences) > 0 {
for iNdEx := len(m.Sequences) - 1; iNdEx >= 0; iNdEx-- {
{
@@ -389,6 +522,101 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
func (m *GenesisState_GenMsgs) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *GenesisState_GenMsgs) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *GenesisState_GenMsgs) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.Sum != nil {
{
size := m.Sum.Size()
i -= size
if _, err := m.Sum.MarshalTo(dAtA[i:]); err != nil {
return 0, err
}
}
}
return len(dAtA) - i, nil
}
func (m *GenesisState_GenMsgs_StoreCode) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *GenesisState_GenMsgs_StoreCode) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
if m.StoreCode != nil {
{
size, err := m.StoreCode.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *GenesisState_GenMsgs_InstantiateContract) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *GenesisState_GenMsgs_InstantiateContract) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
if m.InstantiateContract != nil {
{
size, err := m.InstantiateContract.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x12
}
return len(dAtA) - i, nil
}
func (m *GenesisState_GenMsgs_ExecuteContract) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *GenesisState_GenMsgs_ExecuteContract) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
if m.ExecuteContract != nil {
{
size, err := m.ExecuteContract.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x1a
}
return len(dAtA) - i, nil
}
func (m *Code) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -560,9 +788,63 @@ func (m *GenesisState) Size() (n int) {
n += 1 + l + sovGenesis(uint64(l))
}
}
if len(m.GenMsgs) > 0 {
for _, e := range m.GenMsgs {
l = e.Size()
n += 1 + l + sovGenesis(uint64(l))
}
}
return n
}
func (m *GenesisState_GenMsgs) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Sum != nil {
n += m.Sum.Size()
}
return n
}
func (m *GenesisState_GenMsgs_StoreCode) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.StoreCode != nil {
l = m.StoreCode.Size()
n += 1 + l + sovGenesis(uint64(l))
}
return n
}
func (m *GenesisState_GenMsgs_InstantiateContract) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.InstantiateContract != nil {
l = m.InstantiateContract.Size()
n += 1 + l + sovGenesis(uint64(l))
}
return n
}
func (m *GenesisState_GenMsgs_ExecuteContract) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.ExecuteContract != nil {
l = m.ExecuteContract.Size()
n += 1 + l + sovGenesis(uint64(l))
}
return n
}
func (m *Code) Size() (n int) {
if m == nil {
return 0
@@ -788,6 +1070,198 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 5:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field GenMsgs", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.GenMsgs = append(m.GenMsgs, GenesisState_GenMsgs{})
if err := m.GenMsgs[len(m.GenMsgs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenesis(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *GenesisState_GenMsgs) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: GenMsgs: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GenMsgs: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field StoreCode", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
v := &MsgStoreCode{}
if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
m.Sum = &GenesisState_GenMsgs_StoreCode{v}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field InstantiateContract", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
v := &MsgInstantiateContract{}
if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
m.Sum = &GenesisState_GenMsgs_InstantiateContract{v}
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ExecuteContract", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
v := &MsgExecuteContract{}
if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
m.Sum = &GenesisState_GenMsgs_ExecuteContract{v}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenesis(dAtA[iNdEx:])

View File

@@ -3,6 +3,7 @@ package cosmwasm.wasm.v1beta1;
import "gogoproto/gogo.proto";
import "x/wasm/internal/types/types.proto";
import "x/wasm/internal/types/msg.proto";
option go_package = "github.com/CosmWasm/wasmd/x/wasmd/internal/types";
@@ -12,6 +13,18 @@ message GenesisState {
repeated Code codes = 2 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "codes,omitempty"];
repeated Contract contracts = 3 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "contracts,omitempty"];
repeated Sequence sequences = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "sequences,omitempty"];
repeated GenMsgs gen_msgs = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "gen_msgs,omitempty"];
// GenMsgs define the messages that can be executed during genesis phase in order.
// The intention is to have more human readable data that is auditable.
message GenMsgs {
// sum is a single message
oneof sum {
MsgStoreCode store_code = 1;
MsgInstantiateContract instantiate_contract = 2;
MsgExecuteContract execute_contract = 3;
}
}
}
// Code struct encompasses CodeInfo and CodeBytes

View File

@@ -39,6 +39,30 @@ func TestValidateGenesisState(t *testing.T) {
},
expError: true,
},
"genesis store code message invalid": {
srcMutator: func(s *GenesisState) {
s.GenMsgs[0].GetStoreCode().WASMByteCode = nil
},
expError: true,
},
"genesis instantiate contract message invalid": {
srcMutator: func(s *GenesisState) {
s.GenMsgs[1].GetInstantiateContract().CodeID = 0
},
expError: true,
},
"genesis execute contract message invalid": {
srcMutator: func(s *GenesisState) {
s.GenMsgs[2].GetExecuteContract().Sender = "invalid"
},
expError: true,
},
"genesis invalid message type": {
srcMutator: func(s *GenesisState) {
s.GenMsgs[0].Sum = nil
},
expError: true,
},
}
for msg, spec := range specs {
t.Run(msg, func(t *testing.T) {

View File

@@ -14,6 +14,7 @@ func GenesisFixture(mutators ...func(*GenesisState)) GenesisState {
numCodes = 2
numContracts = 2
numSequences = 2
numMsg = 3
)
fixture := GenesisState{
@@ -34,6 +35,11 @@ func GenesisFixture(mutators ...func(*GenesisState)) GenesisState {
Value: uint64(i),
}
}
fixture.GenMsgs = []GenesisState_GenMsgs{
{Sum: &GenesisState_GenMsgs_StoreCode{StoreCode: MsgStoreCodeFixture()}},
{Sum: &GenesisState_GenMsgs_InstantiateContract{InstantiateContract: MsgInstantiateContractFixture()}},
{Sum: &GenesisState_GenMsgs_ExecuteContract{ExecuteContract: MsgExecuteContractFixture()}},
}
for _, m := range mutators {
m(&fixture)
}
@@ -120,6 +126,61 @@ func WithSHA256CodeHash(wasmCode []byte) func(info *CodeInfo) {
}
}
func MsgStoreCodeFixture(mutators ...func(*MsgStoreCode)) *MsgStoreCode {
var wasmIdent = []byte("\x00\x61\x73\x6D")
const anyAddress = "cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du"
r := &MsgStoreCode{
Sender: anyAddress,
WASMByteCode: wasmIdent,
Source: "https://example.com/code",
Builder: "foo/bar:latest",
InstantiatePermission: &AllowEverybody,
}
for _, m := range mutators {
m(r)
}
return r
}
func MsgInstantiateContractFixture(mutators ...func(*MsgInstantiateContract)) *MsgInstantiateContract {
const anyAddress = "cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du"
r := &MsgInstantiateContract{
Sender: anyAddress,
Admin: anyAddress,
CodeID: 1,
Label: "testing",
InitMsg: []byte(`{"foo":"bar"}`),
InitFunds: sdk.Coins{{
Denom: "stake",
Amount: sdk.NewInt(1),
}},
}
for _, m := range mutators {
m(r)
}
return r
}
func MsgExecuteContractFixture(mutators ...func(*MsgExecuteContract)) *MsgExecuteContract {
const (
anyAddress = "cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du"
firstContractAddress = "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5"
)
r := &MsgExecuteContract{
Sender: anyAddress,
Contract: firstContractAddress,
Msg: []byte(`{"do":"something"}`),
SentFunds: sdk.Coins{{
Denom: "stake",
Amount: sdk.NewInt(1),
}},
}
for _, m := range mutators {
m(r)
}
return r
}
func StoreCodeProposalFixture(mutators ...func(*StoreCodeProposal)) *StoreCodeProposal {
const anyAddress = "cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du"
p := &StoreCodeProposal{

View File

@@ -94,14 +94,16 @@ func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry)
// AppModule implements an application module for the wasm module.
type AppModule struct {
AppModuleBasic
keeper *Keeper
keeper *Keeper
validatorSetSource keeper.ValidatorSetSource
}
// NewAppModule creates a new AppModule object
func NewAppModule(keeper *Keeper) AppModule {
func NewAppModule(keeper *Keeper, validatorSetSource keeper.ValidatorSetSource) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{},
keeper: keeper,
AppModuleBasic: AppModuleBasic{},
keeper: keeper,
validatorSetSource: validatorSetSource,
}
}
@@ -131,10 +133,11 @@ func (AppModule) QuerierRoute() string {
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState GenesisState
cdc.MustUnmarshalJSON(data, &genesisState)
if err := InitGenesis(ctx, am.keeper, genesisState); err != nil {
validators, err := InitGenesis(ctx, am.keeper, genesisState, am.validatorSetSource, am.Route().Handler())
if err != nil {
panic(err)
}
return []abci.ValidatorUpdate{}
return validators
}
// ExportGenesis returns the exported genesis state as raw bytes for the wasm

View File

@@ -13,6 +13,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/module"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
"github.com/dvsekhvalnov/jose2go/base64url"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -22,23 +23,24 @@ import (
)
type testData struct {
module module.AppModule
ctx sdk.Context
acctKeeper authkeeper.AccountKeeper
keeper Keeper
bankKeeper bankkeeper.Keeper
module module.AppModule
ctx sdk.Context
acctKeeper authkeeper.AccountKeeper
keeper Keeper
bankKeeper bankkeeper.Keeper
stakingKeeper stakingkeeper.Keeper
}
// returns a cleanup function, which must be defered on
func setupTest(t *testing.T) testData {
ctx, keepers := CreateTestInput(t, false, "staking", nil, nil)
acctKeeper, wasmKeeper, bankKeeper := keepers.AccountKeeper, keepers.WasmKeeper, keepers.BankKeeper
data := testData{
module: NewAppModule(wasmKeeper),
ctx: ctx,
acctKeeper: acctKeeper,
keeper: *wasmKeeper,
bankKeeper: bankKeeper,
module: NewAppModule(keepers.WasmKeeper, keepers.StakingKeeper),
ctx: ctx,
acctKeeper: keepers.AccountKeeper,
keeper: *keepers.WasmKeeper,
bankKeeper: keepers.BankKeeper,
stakingKeeper: keepers.StakingKeeper,
}
return data
}