mirror of https://github.com/certusone/wasmd.git
474 lines
12 KiB
Go
474 lines
12 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"strconv"
|
|
|
|
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/gogo/protobuf/proto"
|
|
"github.com/spf13/cobra"
|
|
flag "github.com/spf13/pflag"
|
|
)
|
|
|
|
func GetQueryCmd() *cobra.Command {
|
|
queryCmd := &cobra.Command{
|
|
Use: types.ModuleName,
|
|
Short: "Querying commands for the wasm module",
|
|
DisableFlagParsing: true,
|
|
SuggestionsMinimumDistance: 2,
|
|
RunE: client.ValidateCmd,
|
|
}
|
|
queryCmd.AddCommand(
|
|
GetCmdListCode(),
|
|
GetCmdListContractByCode(),
|
|
GetCmdQueryCode(),
|
|
GetCmdGetContractInfo(),
|
|
GetCmdGetContractHistory(),
|
|
GetCmdGetContractState(),
|
|
)
|
|
return queryCmd
|
|
}
|
|
|
|
// GetCmdListCode lists all wasm code uploaded
|
|
func GetCmdListCode() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "list-code",
|
|
Short: "List all wasm bytecode on the chain",
|
|
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
|
|
}
|
|
|
|
pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
queryClient := types.NewQueryClient(clientCtx)
|
|
res, err := queryClient.Codes(
|
|
context.Background(),
|
|
&types.QueryCodesRequest{
|
|
Pagination: pageReq,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return clientCtx.WithJSONMarshaler(&VanillaStdJsonMarshaller{}).PrintProto(res)
|
|
},
|
|
}
|
|
flags.AddQueryFlagsToCmd(cmd)
|
|
flags.AddPaginationFlagsToCmd(cmd, "list codes")
|
|
return cmd
|
|
}
|
|
|
|
// GetCmdListContractByCode lists all wasm code uploaded for given code id
|
|
func GetCmdListContractByCode() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "list-contract-by-code [code_id]",
|
|
Short: "List wasm all bytecode on the chain for given code id",
|
|
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
|
|
}
|
|
|
|
codeID, err := strconv.ParseUint(args[0], 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
queryClient := types.NewQueryClient(clientCtx)
|
|
res, err := queryClient.ContractsByCode(
|
|
context.Background(),
|
|
&types.QueryContractsByCodeRequest{
|
|
CodeId: codeID,
|
|
Pagination: pageReq,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return clientCtx.WithJSONMarshaler(&VanillaStdJsonMarshaller{}).PrintProto(res)
|
|
},
|
|
}
|
|
flags.AddQueryFlagsToCmd(cmd)
|
|
flags.AddPaginationFlagsToCmd(cmd, "list contracts by code")
|
|
return cmd
|
|
}
|
|
|
|
// GetCmdQueryCode returns the bytecode for a given contract
|
|
func GetCmdQueryCode() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "code [code_id] [output filename]",
|
|
Short: "Downloads wasm bytecode for given code id",
|
|
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
|
|
}
|
|
|
|
codeID, err := strconv.ParseUint(args[0], 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
queryClient := types.NewQueryClient(clientCtx)
|
|
res, err := queryClient.Code(
|
|
context.Background(),
|
|
&types.QueryCodeRequest{
|
|
CodeId: codeID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(res.Data) == 0 {
|
|
return fmt.Errorf("contract not found")
|
|
}
|
|
|
|
fmt.Printf("Downloading wasm code to %s\n", args[1])
|
|
return ioutil.WriteFile(args[1], res.Data, 0644)
|
|
},
|
|
}
|
|
flags.AddQueryFlagsToCmd(cmd)
|
|
return cmd
|
|
}
|
|
|
|
// GetCmdGetContractInfo gets details about a given contract
|
|
func GetCmdGetContractInfo() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "contract [bech32_address]",
|
|
Short: "Prints out metadata of a contract given its address",
|
|
Long: "Prints out metadata 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
|
|
}
|
|
|
|
_, err = sdk.AccAddressFromBech32(args[0])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
queryClient := types.NewQueryClient(clientCtx)
|
|
res, err := queryClient.ContractInfo(
|
|
context.Background(),
|
|
&types.QueryContractInfoRequest{
|
|
Address: args[0],
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return clientCtx.WithJSONMarshaler(&VanillaStdJsonMarshaller{}).PrintProto(res)
|
|
},
|
|
}
|
|
flags.AddQueryFlagsToCmd(cmd)
|
|
return cmd
|
|
}
|
|
|
|
// GetCmdGetContractState dumps full internal state of a given contract
|
|
func GetCmdGetContractState() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "contract-state",
|
|
Short: "Querying commands for the wasm module",
|
|
DisableFlagParsing: true,
|
|
SuggestionsMinimumDistance: 2,
|
|
RunE: client.ValidateCmd,
|
|
}
|
|
cmd.AddCommand(
|
|
GetCmdGetContractStateAll(),
|
|
GetCmdGetContractStateRaw(),
|
|
GetCmdGetContractStateSmart(),
|
|
)
|
|
return cmd
|
|
|
|
}
|
|
|
|
func GetCmdGetContractStateAll() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "all [bech32_address]",
|
|
Short: "Prints out all internal state of a contract given its address",
|
|
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
|
|
}
|
|
|
|
_, err = sdk.AccAddressFromBech32(args[0])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
queryClient := types.NewQueryClient(clientCtx)
|
|
res, err := queryClient.AllContractState(
|
|
context.Background(),
|
|
&types.QueryAllContractStateRequest{
|
|
Address: args[0],
|
|
Pagination: pageReq,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return clientCtx.WithJSONMarshaler(&VanillaStdJsonMarshaller{}).PrintProto(res)
|
|
},
|
|
}
|
|
flags.AddQueryFlagsToCmd(cmd)
|
|
flags.AddPaginationFlagsToCmd(cmd, "contract state")
|
|
return cmd
|
|
}
|
|
|
|
func GetCmdGetContractStateRaw() *cobra.Command {
|
|
decoder := newArgDecoder(hex.DecodeString)
|
|
cmd := &cobra.Command{
|
|
Use: "raw [bech32_address] [key]",
|
|
Short: "Prints out internal state for key of a contract given its address",
|
|
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
|
|
}
|
|
|
|
_, err = sdk.AccAddressFromBech32(args[0])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
queryData, err := decoder.DecodeString(args[1])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
queryClient := types.NewQueryClient(clientCtx)
|
|
res, err := queryClient.RawContractState(
|
|
context.Background(),
|
|
&types.QueryRawContractStateRequest{
|
|
Address: args[0],
|
|
QueryData: queryData,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return clientCtx.WithJSONMarshaler(&VanillaStdJsonMarshaller{}).PrintProto(res)
|
|
},
|
|
}
|
|
decoder.RegisterFlags(cmd.PersistentFlags(), "key argument")
|
|
flags.AddQueryFlagsToCmd(cmd)
|
|
return cmd
|
|
}
|
|
|
|
func GetCmdGetContractStateSmart() *cobra.Command {
|
|
decoder := newArgDecoder(asciiDecodeString)
|
|
cmd := &cobra.Command{
|
|
Use: "smart [bech32_address] [query]",
|
|
Short: "Calls contract with given address with query data and prints the returned result",
|
|
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
|
|
}
|
|
|
|
_, err = sdk.AccAddressFromBech32(args[0])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if args[1] == "" {
|
|
return errors.New("query data must not be empty")
|
|
}
|
|
|
|
queryData, err := decoder.DecodeString(args[1])
|
|
if err != nil {
|
|
return fmt.Errorf("decode query: %s", err)
|
|
}
|
|
if !json.Valid(queryData) {
|
|
return errors.New("query data must be json")
|
|
}
|
|
|
|
queryClient := types.NewQueryClient(clientCtx)
|
|
res, err := queryClient.SmartContractState(
|
|
context.Background(),
|
|
&types.QuerySmartContractStateRequest{
|
|
Address: args[0],
|
|
QueryData: queryData,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return clientCtx.WithJSONMarshaler(&VanillaStdJsonMarshaller{}).PrintProto(res)
|
|
},
|
|
}
|
|
decoder.RegisterFlags(cmd.PersistentFlags(), "query argument")
|
|
flags.AddQueryFlagsToCmd(cmd)
|
|
return cmd
|
|
}
|
|
|
|
// GetCmdGetContractHistory prints the code history for a given contract
|
|
func GetCmdGetContractHistory() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "contract-history [bech32_address]",
|
|
Short: "Prints out the code history for a contract given its address",
|
|
Long: "Prints out the code history for 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
|
|
}
|
|
|
|
_, err = sdk.AccAddressFromBech32(args[0])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
queryClient := types.NewQueryClient(clientCtx)
|
|
res, err := queryClient.ContractHistory(
|
|
context.Background(),
|
|
&types.QueryContractHistoryRequest{
|
|
Address: args[0],
|
|
Pagination: pageReq,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return clientCtx.WithJSONMarshaler(&VanillaStdJsonMarshaller{}).PrintProto(res)
|
|
},
|
|
}
|
|
|
|
flags.AddQueryFlagsToCmd(cmd)
|
|
flags.AddPaginationFlagsToCmd(cmd, "contract history")
|
|
return cmd
|
|
}
|
|
|
|
type argumentDecoder struct {
|
|
// dec is the default decoder
|
|
dec func(string) ([]byte, error)
|
|
asciiF, hexF, b64F bool
|
|
}
|
|
|
|
func newArgDecoder(def func(string) ([]byte, error)) *argumentDecoder {
|
|
return &argumentDecoder{dec: def}
|
|
}
|
|
|
|
func (a *argumentDecoder) RegisterFlags(f *flag.FlagSet, argName string) {
|
|
f.BoolVar(&a.asciiF, "ascii", false, "ascii encoded "+argName)
|
|
f.BoolVar(&a.hexF, "hex", false, "hex encoded "+argName)
|
|
f.BoolVar(&a.b64F, "b64", false, "base64 encoded "+argName)
|
|
}
|
|
|
|
func (a *argumentDecoder) DecodeString(s string) ([]byte, error) {
|
|
found := -1
|
|
for i, v := range []*bool{&a.asciiF, &a.hexF, &a.b64F} {
|
|
if !*v {
|
|
continue
|
|
}
|
|
if found != -1 {
|
|
return nil, errors.New("multiple decoding flags used")
|
|
}
|
|
found = i
|
|
}
|
|
switch found {
|
|
case 0:
|
|
return asciiDecodeString(s)
|
|
case 1:
|
|
return hex.DecodeString(s)
|
|
case 2:
|
|
return base64.StdEncoding.DecodeString(s)
|
|
default:
|
|
return a.dec(s)
|
|
}
|
|
}
|
|
|
|
func asciiDecodeString(s string) ([]byte, error) {
|
|
return []byte(s), nil
|
|
}
|
|
|
|
type VanillaStdJsonMarshaller struct {
|
|
}
|
|
|
|
func (x VanillaStdJsonMarshaller) MarshalInterfaceJSON(i proto.Message) ([]byte, error) {
|
|
any, err := codectypes.NewAnyWithValue(i)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return x.MarshalJSON(any)
|
|
}
|
|
|
|
func (x VanillaStdJsonMarshaller) MarshalJSON(o proto.Message) ([]byte, error) {
|
|
return json.MarshalIndent(o, "", " ")
|
|
}
|
|
|
|
func (x VanillaStdJsonMarshaller) MustMarshalJSON(o proto.Message) []byte {
|
|
b, err := x.MarshalJSON(o)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return b
|
|
}
|
|
|
|
func (x VanillaStdJsonMarshaller) UnmarshalInterfaceJSON(bz []byte, ptr interface{}) error {
|
|
panic("not supported")
|
|
}
|
|
|
|
func (x VanillaStdJsonMarshaller) UnmarshalJSON(bz []byte, ptr proto.Message) error {
|
|
panic("not supported")
|
|
}
|
|
|
|
func (x VanillaStdJsonMarshaller) MustUnmarshalJSON(bz []byte, ptr proto.Message) {
|
|
panic("not supported")
|
|
}
|
|
|
|
// sdk ReadPageRequest expects binary but we encoded to base64 in our marshaller
|
|
func withPageKeyDecoded(flagSet *flag.FlagSet) *flag.FlagSet {
|
|
encoded, err := flagSet.GetString(flags.FlagPageKey)
|
|
if err != nil {
|
|
panic(err.Error())
|
|
}
|
|
raw, err := base64.StdEncoding.DecodeString(encoded)
|
|
if err != nil {
|
|
panic(err.Error())
|
|
}
|
|
flagSet.Set(flags.FlagPageKey, string(raw))
|
|
return flagSet
|
|
}
|