Add wasm command to support v1 gov proposals (#1326)
* Add wasm command to support v1 gov proposals * fix lint issues * fix comments * Minor tweak and test files --------- Co-authored-by: Alex Peters <alpe@users.noreply.github.com>
This commit is contained in:
19
contrib/local/04-gov.sh
Executable file
19
contrib/local/04-gov.sh
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
set -o errexit -o nounset -o pipefail
|
||||
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
|
||||
|
||||
echo "Compile with buildflag ''-X github.com/CosmWasm/wasmd/app.ProposalsEnabled=true' to enable gov"
|
||||
sleep 1
|
||||
echo "## Submit a CosmWasm gov proposal"
|
||||
RESP=$(wasmd tx wasm submit-proposal store-instantiate "$DIR/../../x/wasm/keeper/testdata/reflect.wasm" \
|
||||
'{}' --label="testing" \
|
||||
--title "testing" --summary "Testing" --deposit "1000000000ustake" \
|
||||
--admin $(wasmd keys show -a validator --keyring-backend=test) \
|
||||
--amount 123ustake \
|
||||
--keyring-backend=test \
|
||||
--from validator --gas auto --gas-adjustment=1.5 -y --chain-id=testing --node=http://localhost:26657 -b sync -o json)
|
||||
echo $RESP
|
||||
sleep 6
|
||||
wasmd q tx $(echo "$RESP"| jq -r '.txhash') -o json | jq
|
||||
|
||||
@@ -18,7 +18,7 @@ if ! wasmd keys show validator --keyring-backend=test; then
|
||||
) | wasmd keys add validator --keyring-backend=test
|
||||
fi
|
||||
# hardcode the validator account for this instance
|
||||
echo "$PASSWORD" | wasmd genesis add-genesis-account validator "1000000000$STAKE,1000000000$FEE" --keyring-backend=test
|
||||
echo "$PASSWORD" | wasmd genesis add-genesis-account validator "1000000000000$STAKE,1000000000000$FEE" --keyring-backend=test
|
||||
# (optionally) add a few more genesis accounts
|
||||
for addr in "$@"; do
|
||||
echo "$addr"
|
||||
|
||||
840
x/wasm/client/cli/gov_tx.go
Normal file
840
x/wasm/client/cli/gov_tx.go
Normal file
@@ -0,0 +1,840 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/address"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov/client/cli"
|
||||
v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
flag "github.com/spf13/pflag"
|
||||
|
||||
"github.com/CosmWasm/wasmd/x/wasm/ioutils"
|
||||
"github.com/CosmWasm/wasmd/x/wasm/types"
|
||||
)
|
||||
|
||||
// DefaultGovAuthority is set to the gov module address.
|
||||
// Extension point for chains to overwrite the default
|
||||
var DefaultGovAuthority = sdk.AccAddress(address.Module("gov"))
|
||||
|
||||
func SubmitProposalCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "submit-proposal",
|
||||
Short: "Submit a wasm proposal.",
|
||||
SilenceUsage: true,
|
||||
}
|
||||
cmd.AddCommand(
|
||||
ProposalStoreCodeCmd(),
|
||||
ProposalInstantiateContractCmd(),
|
||||
ProposalInstantiateContract2Cmd(),
|
||||
ProposalStoreAndInstantiateContractCmd(),
|
||||
ProposalMigrateContractCmd(),
|
||||
ProposalExecuteContractCmd(),
|
||||
ProposalSudoContractCmd(),
|
||||
ProposalUpdateContractAdminCmd(),
|
||||
ProposalClearContractAdminCmd(),
|
||||
ProposalPinCodesCmd(),
|
||||
ProposalUnpinCodesCmd(),
|
||||
ProposalUpdateInstantiateConfigCmd(),
|
||||
)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalStoreCodeCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "wasm-store [wasm file] --title [text] --summary [text] --authority [address]",
|
||||
Short: "Submit a wasm binary proposal",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, summary, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authority, err := cmd.Flags().GetString(flagAuthority)
|
||||
if err != nil {
|
||||
return fmt.Errorf("authority: %s", err)
|
||||
}
|
||||
|
||||
if len(authority) == 0 {
|
||||
return errors.New("authority address is required")
|
||||
}
|
||||
|
||||
src, err := parseStoreCodeArgs(args[0], authority, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{&src}, deposit, clientCtx.GetFromAddress().String(), "", proposalTitle, summary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = proposalMsg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposalMsg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
addInstantiatePermissionFlags(cmd)
|
||||
|
||||
// proposal flags
|
||||
addCommonProposalFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseVerificationFlags(gzippedWasm []byte, flags *flag.FlagSet) (string, string, []byte, error) {
|
||||
source, err := flags.GetString(flagSource)
|
||||
if err != nil {
|
||||
return "", "", nil, fmt.Errorf("source: %s", err)
|
||||
}
|
||||
builder, err := flags.GetString(flagBuilder)
|
||||
if err != nil {
|
||||
return "", "", nil, fmt.Errorf("builder: %s", err)
|
||||
}
|
||||
codeHash, err := flags.GetBytesHex(flagCodeHash)
|
||||
if err != nil {
|
||||
return "", "", nil, fmt.Errorf("codeHash: %s", err)
|
||||
}
|
||||
|
||||
// if any set require others to be set
|
||||
if len(source) != 0 || len(builder) != 0 || len(codeHash) != 0 {
|
||||
if source == "" {
|
||||
return "", "", nil, fmt.Errorf("source is required")
|
||||
}
|
||||
if _, err = url.ParseRequestURI(source); err != nil {
|
||||
return "", "", nil, fmt.Errorf("source: %s", err)
|
||||
}
|
||||
if builder == "" {
|
||||
return "", "", nil, fmt.Errorf("builder is required")
|
||||
}
|
||||
if _, err := reference.ParseDockerRef(builder); err != nil {
|
||||
return "", "", nil, fmt.Errorf("builder: %s", err)
|
||||
}
|
||||
if len(codeHash) == 0 {
|
||||
return "", "", nil, fmt.Errorf("code hash is required")
|
||||
}
|
||||
// wasm is gzipped in parseStoreCodeArgs
|
||||
// checksum generation will be decoupled here
|
||||
// reference https://github.com/CosmWasm/wasmvm/issues/359
|
||||
raw, err := ioutils.Uncompress(gzippedWasm, uint64(types.MaxWasmSize))
|
||||
if err != nil {
|
||||
return "", "", nil, fmt.Errorf("invalid zip: %w", err)
|
||||
}
|
||||
checksum := sha256.Sum256(raw)
|
||||
if !bytes.Equal(checksum[:], codeHash) {
|
||||
return "", "", nil, fmt.Errorf("code-hash mismatch: %X, checksum: %X", codeHash, checksum)
|
||||
}
|
||||
}
|
||||
return source, builder, codeHash, nil
|
||||
}
|
||||
|
||||
func ProposalInstantiateContractCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "instantiate-contract [code_id_int64] [json_encoded_init_args] --authority [address] --label [text] --title [text] --summary [text] --admin [address,optional] --amount [coins,optional]",
|
||||
Short: "Submit an instantiate wasm contract proposal",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, summary, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authority, err := cmd.Flags().GetString(flagAuthority)
|
||||
if err != nil {
|
||||
return fmt.Errorf("authority: %s", err)
|
||||
}
|
||||
|
||||
if len(authority) == 0 {
|
||||
return errors.New("authority address is required")
|
||||
}
|
||||
|
||||
src, err := parseInstantiateArgs(args[0], args[1], clientCtx.Keyring, authority, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{src}, deposit, clientCtx.GetFromAddress().String(), "", proposalTitle, summary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = proposalMsg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposalMsg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
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 or key name of an admin")
|
||||
cmd.Flags().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin")
|
||||
|
||||
// proposal flags
|
||||
addCommonProposalFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalInstantiateContract2Cmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "instantiate-contract-2 [code_id_int64] [json_encoded_init_args] --authority [address] --label [text] --title [text] --summary [text] --admin [address,optional] --amount [coins,optional]",
|
||||
Short: "Submit an instantiate wasm contract proposal with predictable address",
|
||||
Args: cobra.ExactArgs(3),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, summary, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authority, err := cmd.Flags().GetString(flagAuthority)
|
||||
if err != nil {
|
||||
return fmt.Errorf("authority: %s", err)
|
||||
}
|
||||
|
||||
if len(authority) == 0 {
|
||||
return errors.New("authority address is required")
|
||||
}
|
||||
|
||||
src, err := parseInstantiateArgs(args[0], args[1], clientCtx.Keyring, authority, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{src}, deposit, clientCtx.GetFromAddress().String(), "", proposalTitle, summary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = proposalMsg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposalMsg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
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().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin")
|
||||
|
||||
// proposal flags
|
||||
addCommonProposalFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalStoreAndInstantiateContractCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "store-instantiate [wasm file] [json_encoded_init_args] --authority [address] --label [text] --title [text] --summary [text]" +
|
||||
"--unpin-code [unpin_code,optional] --source [source,optional] --builder [builder,optional] --code-hash [code_hash,optional] --admin [address,optional] --amount [coins,optional]",
|
||||
Short: "Submit and instantiate a wasm contract proposal",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, summary, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authority, err := cmd.Flags().GetString(flagAuthority)
|
||||
if err != nil {
|
||||
return fmt.Errorf("authority: %s", err)
|
||||
}
|
||||
|
||||
if len(authority) == 0 {
|
||||
return errors.New("authority address is required")
|
||||
}
|
||||
|
||||
src, err := parseStoreCodeArgs(args[0], authority, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
unpinCode, err := cmd.Flags().GetBool(flagUnpinCode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source, builder, codeHash, err := parseVerificationFlags(src.WASMByteCode, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
amountStr, err := cmd.Flags().GetString(flagAmount)
|
||||
if err != nil {
|
||||
return fmt.Errorf("amount: %s", err)
|
||||
}
|
||||
amount, err := sdk.ParseCoinsNormalized(amountStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("amount: %s", err)
|
||||
}
|
||||
label, err := cmd.Flags().GetString(flagLabel)
|
||||
if err != nil {
|
||||
return fmt.Errorf("label: %s", err)
|
||||
}
|
||||
if label == "" {
|
||||
return errors.New("label is required on all contracts")
|
||||
}
|
||||
adminStr, err := cmd.Flags().GetString(flagAdmin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("admin: %s", err)
|
||||
}
|
||||
noAdmin, err := cmd.Flags().GetBool(flagNoAdmin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("no-admin: %s", err)
|
||||
}
|
||||
|
||||
// ensure sensible admin is set (or explicitly immutable)
|
||||
if adminStr == "" && !noAdmin {
|
||||
return fmt.Errorf("you must set an admin or explicitly pass --no-admin to make it immutible (wasmd issue #719)")
|
||||
}
|
||||
if adminStr != "" && noAdmin {
|
||||
return fmt.Errorf("you set an admin and passed --no-admin, those cannot both be true")
|
||||
}
|
||||
|
||||
if adminStr != "" {
|
||||
addr, err := sdk.AccAddressFromBech32(adminStr)
|
||||
if err != nil {
|
||||
info, err := clientCtx.Keyring.Key(adminStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("admin %s", err)
|
||||
}
|
||||
admin, err := info.GetAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
adminStr = admin.String()
|
||||
} else {
|
||||
adminStr = addr.String()
|
||||
}
|
||||
}
|
||||
|
||||
msg := types.MsgStoreAndInstantiateContract{
|
||||
Authority: authority,
|
||||
WASMByteCode: src.WASMByteCode,
|
||||
InstantiatePermission: src.InstantiatePermission,
|
||||
UnpinCode: unpinCode,
|
||||
Source: source,
|
||||
Builder: builder,
|
||||
CodeHash: codeHash,
|
||||
Admin: adminStr,
|
||||
Label: label,
|
||||
Msg: []byte(args[1]),
|
||||
Funds: amount,
|
||||
}
|
||||
|
||||
proposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{&msg}, deposit, clientCtx.GetFromAddress().String(), "", proposalTitle, summary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = proposalMsg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposalMsg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
cmd.Flags().Bool(flagUnpinCode, false, "Unpin code on upload, optional")
|
||||
cmd.Flags().String(flagSource, "", "Code Source URL is a valid absolute HTTPS URI to the contract's source code,")
|
||||
cmd.Flags().String(flagBuilder, "", "Builder is a valid docker image name with tag, such as \"cosmwasm/workspace-optimizer:0.12.9\"")
|
||||
cmd.Flags().BytesHex(flagCodeHash, nil, "CodeHash is the sha256 hash of the wasm code")
|
||||
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 or key name of an admin")
|
||||
cmd.Flags().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin")
|
||||
addInstantiatePermissionFlags(cmd)
|
||||
// proposal flags
|
||||
addCommonProposalFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalMigrateContractCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "migrate-contract [contract_addr_bech32] [new_code_id_int64] [json_encoded_migration_args] --title [text] --summary [text] --authority [address]",
|
||||
Short: "Submit a migrate wasm contract to a new code version proposal",
|
||||
Args: cobra.ExactArgs(3),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, summary, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authority, err := cmd.Flags().GetString(flagAuthority)
|
||||
if err != nil {
|
||||
return fmt.Errorf("authority: %s", err)
|
||||
}
|
||||
|
||||
if len(authority) == 0 {
|
||||
return errors.New("authority address is required")
|
||||
}
|
||||
|
||||
src, err := parseMigrateContractArgs(args, authority)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{&src}, deposit, clientCtx.GetFromAddress().String(), "", proposalTitle, summary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = proposalMsg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposalMsg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
// proposal flags
|
||||
addCommonProposalFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalExecuteContractCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "execute-contract [contract_addr_bech32] [json_encoded_migration_args] --title [text] --summary [text] --authority [address]",
|
||||
Short: "Submit a execute wasm contract proposal (run by any address)",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, summary, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authority, err := cmd.Flags().GetString(flagAuthority)
|
||||
if err != nil {
|
||||
return fmt.Errorf("authority: %s", err)
|
||||
}
|
||||
|
||||
if len(authority) == 0 {
|
||||
return errors.New("authority address is required")
|
||||
}
|
||||
|
||||
contract := args[0]
|
||||
execMsg := []byte(args[1])
|
||||
amountStr, err := cmd.Flags().GetString(flagAmount)
|
||||
if err != nil {
|
||||
return fmt.Errorf("amount: %s", err)
|
||||
}
|
||||
funds, err := sdk.ParseCoinsNormalized(amountStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("amount: %s", err)
|
||||
}
|
||||
|
||||
msg := types.MsgExecuteContract{
|
||||
Sender: authority,
|
||||
Contract: contract,
|
||||
Msg: execMsg,
|
||||
Funds: funds,
|
||||
}
|
||||
|
||||
proposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{&msg}, deposit, clientCtx.GetFromAddress().String(), "", proposalTitle, summary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = proposalMsg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposalMsg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation")
|
||||
|
||||
// proposal flags
|
||||
addCommonProposalFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalSudoContractCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "sudo-contract [contract_addr_bech32] [json_encoded_migration_args] --title [text] --summary [text] --authority [address]",
|
||||
Short: "Submit a sudo wasm contract proposal (to call privileged commands)",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, summary, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authority, err := cmd.Flags().GetString(flagAuthority)
|
||||
if err != nil {
|
||||
return fmt.Errorf("authority: %s", err)
|
||||
}
|
||||
|
||||
if len(authority) == 0 {
|
||||
return errors.New("authority address is required")
|
||||
}
|
||||
|
||||
msg := types.MsgSudoContract{
|
||||
Authority: authority,
|
||||
Contract: args[0],
|
||||
Msg: []byte(args[1]),
|
||||
}
|
||||
|
||||
proposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{&msg}, deposit, clientCtx.GetFromAddress().String(), "", proposalTitle, summary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = proposalMsg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposalMsg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
// proposal flagsExecute
|
||||
addCommonProposalFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalUpdateContractAdminCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "set-contract-admin [contract_addr_bech32] [new_admin_addr_bech32] --title [text] --summary [text] --authority [address]",
|
||||
Short: "Submit a new admin for a contract proposal",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, summary, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authority, err := cmd.Flags().GetString(flagAuthority)
|
||||
if err != nil {
|
||||
return fmt.Errorf("authority: %s", err)
|
||||
}
|
||||
|
||||
if len(authority) == 0 {
|
||||
return errors.New("authority address is required")
|
||||
}
|
||||
|
||||
src := parseUpdateContractAdminArgs(args, authority)
|
||||
|
||||
proposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{&src}, deposit, clientCtx.GetFromAddress().String(), "", proposalTitle, summary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = proposalMsg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposalMsg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
// proposal flags
|
||||
addCommonProposalFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalClearContractAdminCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "clear-contract-admin [contract_addr_bech32] --title [text] --summary [text] --authority [address]",
|
||||
Short: "Submit a clear admin for a contract to prevent further migrations proposal",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, summary, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authority, err := cmd.Flags().GetString(flagAuthority)
|
||||
if err != nil {
|
||||
return fmt.Errorf("authority: %s", err)
|
||||
}
|
||||
|
||||
if len(authority) == 0 {
|
||||
return errors.New("authority address is required")
|
||||
}
|
||||
|
||||
msg := types.MsgClearAdmin{
|
||||
Sender: authority,
|
||||
Contract: args[0],
|
||||
}
|
||||
|
||||
proposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{&msg}, deposit, clientCtx.GetFromAddress().String(), "", proposalTitle, summary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = proposalMsg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposalMsg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
// proposal flags
|
||||
addCommonProposalFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalPinCodesCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "pin-codes [code-ids] --title [text] --summary [text] --authority [address]",
|
||||
Short: "Submit a pin code proposal for pinning a code to cache",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, summary, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authority, err := cmd.Flags().GetString(flagAuthority)
|
||||
if err != nil {
|
||||
return fmt.Errorf("authority: %s", err)
|
||||
}
|
||||
|
||||
if len(authority) == 0 {
|
||||
return errors.New("authority address is required")
|
||||
}
|
||||
|
||||
codeIds, err := parsePinCodesArgs(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := types.MsgPinCodes{
|
||||
Authority: authority,
|
||||
CodeIDs: codeIds,
|
||||
}
|
||||
|
||||
proposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{&msg}, deposit, clientCtx.GetFromAddress().String(), "", proposalTitle, summary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = proposalMsg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposalMsg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
// proposal flags
|
||||
addCommonProposalFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parsePinCodesArgs(args []string) ([]uint64, error) {
|
||||
codeIDs := make([]uint64, len(args))
|
||||
for i, c := range args {
|
||||
codeID, err := strconv.ParseUint(c, 10, 64)
|
||||
if err != nil {
|
||||
return codeIDs, fmt.Errorf("code IDs: %s", err)
|
||||
}
|
||||
codeIDs[i] = codeID
|
||||
}
|
||||
return codeIDs, nil
|
||||
}
|
||||
|
||||
func ProposalUnpinCodesCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "unpin-codes [code-ids] --title [text] --summary [text] --authority [address]",
|
||||
Short: "Submit a unpin code proposal for unpinning a code to cache",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, summary, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authority, err := cmd.Flags().GetString(flagAuthority)
|
||||
if err != nil {
|
||||
return fmt.Errorf("authority: %s", err)
|
||||
}
|
||||
|
||||
if len(authority) == 0 {
|
||||
return errors.New("authority address is required")
|
||||
}
|
||||
|
||||
codeIds, err := parsePinCodesArgs(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := types.MsgUnpinCodes{
|
||||
Authority: authority,
|
||||
CodeIDs: codeIds,
|
||||
}
|
||||
|
||||
proposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{&msg}, deposit, clientCtx.GetFromAddress().String(), "", proposalTitle, summary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = proposalMsg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposalMsg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
// proposal flags
|
||||
addCommonProposalFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseAccessConfig(raw string) (c types.AccessConfig, err error) {
|
||||
switch raw {
|
||||
case "nobody":
|
||||
return types.AllowNobody, nil
|
||||
case "everybody":
|
||||
return types.AllowEverybody, nil
|
||||
default:
|
||||
parts := strings.Split(raw, ",")
|
||||
addrs := make([]sdk.AccAddress, len(parts))
|
||||
for i, v := range parts {
|
||||
addr, err := sdk.AccAddressFromBech32(v)
|
||||
if err != nil {
|
||||
return types.AccessConfig{}, fmt.Errorf("unable to parse address %q: %s", v, err)
|
||||
}
|
||||
addrs[i] = addr
|
||||
}
|
||||
defer func() { // convert panic in ".With" to error for better output
|
||||
if r := recover(); r != nil {
|
||||
err = r.(error)
|
||||
}
|
||||
}()
|
||||
cfg := types.AccessTypeAnyOfAddresses.With(addrs...)
|
||||
return cfg, cfg.ValidateBasic()
|
||||
}
|
||||
}
|
||||
|
||||
func parseAccessConfigUpdates(args []string) ([]types.AccessConfigUpdate, error) {
|
||||
updates := make([]types.AccessConfigUpdate, len(args))
|
||||
for i, c := range args {
|
||||
// format: code_id:access_config
|
||||
// access_config: nobody|everybody|address(es)
|
||||
parts := strings.Split(c, ":")
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("invalid format")
|
||||
}
|
||||
|
||||
codeID, err := strconv.ParseUint(parts[0], 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid code ID: %s", err)
|
||||
}
|
||||
|
||||
accessConfig, err := parseAccessConfig(parts[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updates[i] = types.AccessConfigUpdate{
|
||||
CodeID: codeID,
|
||||
InstantiatePermission: accessConfig,
|
||||
}
|
||||
}
|
||||
return updates, nil
|
||||
}
|
||||
|
||||
func ProposalUpdateInstantiateConfigCmd() *cobra.Command {
|
||||
bech32Prefix := sdk.GetConfig().GetBech32AccountAddrPrefix()
|
||||
cmd := &cobra.Command{
|
||||
Use: "update-instantiate-config [code-id:permission] --title [text] --summary [text] --authority [address]",
|
||||
Short: "Submit an update instantiate config proposal.",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
Long: strings.TrimSpace(
|
||||
fmt.Sprintf(`Submit an update instantiate config proposal for multiple code ids.
|
||||
|
||||
Example:
|
||||
$ %s tx gov submit-proposal update-instantiate-config 1:nobody 2:everybody 3:%s1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm,%s1vx8knpllrj7n963p9ttd80w47kpacrhuts497x
|
||||
`, version.AppName, bech32Prefix, bech32Prefix)),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, summary, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authority, err := cmd.Flags().GetString(flagAuthority)
|
||||
if err != nil {
|
||||
return fmt.Errorf("authority: %s", err)
|
||||
}
|
||||
|
||||
if len(authority) == 0 {
|
||||
return errors.New("authority address is required")
|
||||
}
|
||||
|
||||
updates, err := parseAccessConfigUpdates(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgs := make([]sdk.Msg, len(updates))
|
||||
for i, update := range updates {
|
||||
permission := update.InstantiatePermission
|
||||
msgs[i] = &types.MsgUpdateInstantiateConfig{
|
||||
Sender: authority,
|
||||
CodeID: update.CodeID,
|
||||
NewInstantiatePermission: &permission,
|
||||
}
|
||||
}
|
||||
|
||||
proposalMsg, err := v1.NewMsgSubmitProposal(msgs, deposit, clientCtx.GetFromAddress().String(), "", proposalTitle, summary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = proposalMsg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposalMsg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
// proposal flags
|
||||
addCommonProposalFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func addCommonProposalFlags(cmd *cobra.Command) {
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
cmd.Flags().String(cli.FlagTitle, "", "Title of proposal")
|
||||
cmd.Flags().String(cli.FlagSummary, "", "Summary of proposal")
|
||||
cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal")
|
||||
cmd.Flags().String(flagAuthority, DefaultGovAuthority.String(), "The address of the governance account. Default is the sdk gov module account")
|
||||
}
|
||||
|
||||
func getProposalInfo(cmd *cobra.Command) (client.Context, string, string, sdk.Coins, error) {
|
||||
clientCtx, err := client.GetClientTxContext(cmd)
|
||||
if err != nil {
|
||||
return client.Context{}, "", "", nil, err
|
||||
}
|
||||
|
||||
proposalTitle, err := cmd.Flags().GetString(cli.FlagTitle)
|
||||
if err != nil {
|
||||
return clientCtx, proposalTitle, "", nil, err
|
||||
}
|
||||
|
||||
summary, err := cmd.Flags().GetString(cli.FlagSummary)
|
||||
if err != nil {
|
||||
return client.Context{}, proposalTitle, summary, nil, err
|
||||
}
|
||||
|
||||
depositArg, err := cmd.Flags().GetString(cli.FlagDeposit)
|
||||
if err != nil {
|
||||
return client.Context{}, proposalTitle, summary, nil, err
|
||||
}
|
||||
|
||||
deposit, err := sdk.ParseCoinsNormalized(depositArg)
|
||||
if err != nil {
|
||||
return client.Context{}, proposalTitle, summary, deposit, err
|
||||
}
|
||||
|
||||
return clientCtx, proposalTitle, summary, deposit, nil
|
||||
}
|
||||
158
x/wasm/client/cli/gov_tx_test.go
Normal file
158
x/wasm/client/cli/gov_tx_test.go
Normal file
@@ -0,0 +1,158 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/CosmWasm/wasmd/x/wasm/types"
|
||||
)
|
||||
|
||||
func TestParseAccessConfigUpdates(t *testing.T) {
|
||||
specs := map[string]struct {
|
||||
src []string
|
||||
exp []types.AccessConfigUpdate
|
||||
expErr bool
|
||||
}{
|
||||
"nobody": {
|
||||
src: []string{"1:nobody"},
|
||||
exp: []types.AccessConfigUpdate{{
|
||||
CodeID: 1,
|
||||
InstantiatePermission: types.AccessConfig{Permission: types.AccessTypeNobody},
|
||||
}},
|
||||
},
|
||||
"everybody": {
|
||||
src: []string{"1:everybody"},
|
||||
exp: []types.AccessConfigUpdate{{
|
||||
CodeID: 1,
|
||||
InstantiatePermission: types.AccessConfig{Permission: types.AccessTypeEverybody},
|
||||
}},
|
||||
},
|
||||
"any of addresses - single": {
|
||||
src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"},
|
||||
exp: []types.AccessConfigUpdate{
|
||||
{
|
||||
CodeID: 1,
|
||||
InstantiatePermission: types.AccessConfig{
|
||||
Permission: types.AccessTypeAnyOfAddresses,
|
||||
Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"any of addresses - multiple": {
|
||||
src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"},
|
||||
exp: []types.AccessConfigUpdate{
|
||||
{
|
||||
CodeID: 1,
|
||||
InstantiatePermission: types.AccessConfig{
|
||||
Permission: types.AccessTypeAnyOfAddresses,
|
||||
Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x", "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"multiple code ids with different permissions": {
|
||||
src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", "2:nobody"},
|
||||
exp: []types.AccessConfigUpdate{
|
||||
{
|
||||
CodeID: 1,
|
||||
InstantiatePermission: types.AccessConfig{
|
||||
Permission: types.AccessTypeAnyOfAddresses,
|
||||
Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x", "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"},
|
||||
},
|
||||
}, {
|
||||
CodeID: 2,
|
||||
InstantiatePermission: types.AccessConfig{
|
||||
Permission: types.AccessTypeNobody,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"any of addresses - empty list": {
|
||||
src: []string{"1:"},
|
||||
expErr: true,
|
||||
},
|
||||
"any of addresses - invalid address": {
|
||||
src: []string{"1:foo"},
|
||||
expErr: true,
|
||||
},
|
||||
"any of addresses - duplicate address": {
|
||||
src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"},
|
||||
expErr: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, gotErr := parseAccessConfigUpdates(spec.src)
|
||||
if spec.expErr {
|
||||
require.Error(t, gotErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, gotErr)
|
||||
assert.Equal(t, spec.exp, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCodeInfoFlags(t *testing.T) {
|
||||
correctSource := "https://github.com/CosmWasm/wasmd/blob/main/x/wasm/keeper/testdata/hackatom.wasm"
|
||||
correctBuilderRef := "cosmwasm/workspace-optimizer:0.12.9"
|
||||
|
||||
wasmBin, err := os.ReadFile("../../keeper/testdata/hackatom.wasm.gzip")
|
||||
require.NoError(t, err)
|
||||
|
||||
checksumStr := "beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b"
|
||||
|
||||
specs := map[string]struct {
|
||||
args []string
|
||||
expErr bool
|
||||
}{
|
||||
"source missing": {
|
||||
args: []string{"--builder=" + correctBuilderRef, "--code-hash=" + checksumStr},
|
||||
expErr: true,
|
||||
},
|
||||
"builder missing": {
|
||||
args: []string{"--code-source-url=" + correctSource, "--code-hash=" + checksumStr},
|
||||
expErr: true,
|
||||
},
|
||||
"code hash missing": {
|
||||
args: []string{"--code-source-url=" + correctSource, "--builder=" + correctBuilderRef},
|
||||
expErr: true,
|
||||
},
|
||||
"source format wrong": {
|
||||
args: []string{"--code-source-url=" + "format_wrong", "--builder=" + correctBuilderRef, "--code-hash=" + checksumStr},
|
||||
expErr: true,
|
||||
},
|
||||
"builder format wrong": {
|
||||
args: []string{"--code-source-url=" + correctSource, "--builder=" + "format//", "--code-hash=" + checksumStr},
|
||||
expErr: true,
|
||||
},
|
||||
"code hash wrong": {
|
||||
args: []string{"--code-source-url=" + correctSource, "--builder=" + correctBuilderRef, "--code-hash=" + "AA"},
|
||||
expErr: true,
|
||||
},
|
||||
"happy path, none set": {
|
||||
args: []string{},
|
||||
expErr: false,
|
||||
},
|
||||
"happy path all set": {
|
||||
args: []string{"--code-source-url=" + correctSource, "--builder=" + correctBuilderRef, "--code-hash=" + checksumStr},
|
||||
expErr: false,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
flags := ProposalStoreAndInstantiateContractCmd().Flags()
|
||||
require.NoError(t, flags.Parse(spec.args))
|
||||
_, _, _, gotErr := parseVerificationFlags(wasmBin, flags)
|
||||
if spec.expErr {
|
||||
require.Error(t, gotErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, gotErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,7 @@ const (
|
||||
flagMaxFunds = "max-funds"
|
||||
flagAllowAllMsgs = "allow-all-messages"
|
||||
flagNoTokenTransfer = "no-token-transfer" //nolint:gosec
|
||||
flagAuthority = "authority"
|
||||
)
|
||||
|
||||
// GetTxCmd returns the transaction commands for this module
|
||||
@@ -66,6 +67,7 @@ func GetTxCmd() *cobra.Command {
|
||||
ClearContractAdminCmd(),
|
||||
GrantAuthorizationCmd(),
|
||||
UpdateInstantiateConfigCmd(),
|
||||
SubmitProposalCmd(),
|
||||
)
|
||||
return txCmd
|
||||
}
|
||||
|
||||
@@ -1,14 +1,79 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/CosmWasm/wasmd/x/wasm/ioutils"
|
||||
"github.com/CosmWasm/wasmd/x/wasm/types"
|
||||
)
|
||||
|
||||
func TestParseVerificationFlags(t *testing.T) {
|
||||
mySender := sdk.MustAccAddressFromBech32("cosmos1wyqh3n50ecatjg4vww5crmtd0nmyzusnwckw4at4gluc0m5m477q4arfek")
|
||||
|
||||
specs := map[string]struct {
|
||||
srcPath string
|
||||
args []string
|
||||
expErr bool
|
||||
expSource string
|
||||
expBuilder string
|
||||
expCodeHash string
|
||||
}{
|
||||
"gov store zipped": {
|
||||
srcPath: "../../keeper/testdata/hackatom.wasm.gzip",
|
||||
args: []string{
|
||||
"--instantiate-everybody=true", "--code-hash=beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b",
|
||||
"--code-source-url=https://example.com", "--builder=cosmwasm/workspace-optimizer:0.12.11",
|
||||
},
|
||||
expBuilder: "cosmwasm/workspace-optimizer:0.12.11",
|
||||
expSource: "https://example.com",
|
||||
expCodeHash: "beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b",
|
||||
},
|
||||
"gov store raw": {
|
||||
srcPath: "../../keeper/testdata/hackatom.wasm",
|
||||
args: []string{
|
||||
"--instantiate-everybody=true", "--code-hash=beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b",
|
||||
"--code-source-url=https://example.com", "--builder=cosmwasm/workspace-optimizer:0.12.11",
|
||||
},
|
||||
expBuilder: "cosmwasm/workspace-optimizer:0.12.11",
|
||||
expSource: "https://example.com",
|
||||
expCodeHash: "beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b",
|
||||
},
|
||||
"gov store checksum mismatch": {
|
||||
srcPath: "../../keeper/testdata/hackatom.wasm",
|
||||
args: []string{
|
||||
"--instantiate-everybody=true", "--code-hash=0000de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b",
|
||||
"--code-source-url=https://example.com", "--builder=cosmwasm/workspace-optimizer:0.12.11",
|
||||
},
|
||||
expErr: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
flagSet := ProposalStoreAndInstantiateContractCmd().Flags()
|
||||
require.NoError(t, flagSet.Parse(spec.args))
|
||||
|
||||
gotMsg, err := parseStoreCodeArgs(spec.srcPath, mySender.String(), flagSet)
|
||||
require.NoError(t, err)
|
||||
require.True(t, ioutils.IsGzip(gotMsg.WASMByteCode))
|
||||
|
||||
gotSource, gotBuilder, gotCodeHash, gotErr := parseVerificationFlags(gotMsg.WASMByteCode, flagSet)
|
||||
if spec.expErr {
|
||||
require.Error(t, gotErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, gotErr)
|
||||
assert.Equal(t, spec.expSource, gotSource)
|
||||
assert.Equal(t, spec.expBuilder, gotBuilder)
|
||||
assert.Equal(t, spec.expCodeHash, hex.EncodeToString(gotCodeHash))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseAccessConfigFlags(t *testing.T) {
|
||||
specs := map[string]struct {
|
||||
args []string
|
||||
|
||||
@@ -57,7 +57,7 @@ func ValidateSalt(salt []byte) error {
|
||||
// ValidateVerificationInfo ensure source, builder and checksum constraints
|
||||
func ValidateVerificationInfo(source, builder string, codeHash []byte) error {
|
||||
// if any set require others to be set
|
||||
if len(source) != 0 || len(builder) != 0 || codeHash != nil {
|
||||
if len(source) != 0 || len(builder) != 0 || len(codeHash) != 0 {
|
||||
if source == "" {
|
||||
return fmt.Errorf("source is required")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user