github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/wasm/client/cli/query.go (about) 1 package cli 2 3 import ( 4 "context" 5 "encoding/base64" 6 "encoding/hex" 7 "encoding/json" 8 "errors" 9 "fmt" 10 "io/ioutil" 11 "strconv" 12 "strings" 13 14 wasmvm "github.com/CosmWasm/wasmvm" 15 16 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 17 18 "github.com/fibonacci-chain/fbc/x/wasm/keeper" 19 20 "github.com/spf13/cobra" 21 flag "github.com/spf13/pflag" 22 23 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client" 24 clientCtx "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/context" 25 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/flags" 26 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec" 27 codectypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec/types" 28 "github.com/fibonacci-chain/fbc/x/wasm/types" 29 ) 30 31 // NewQueryCmd returns the query commands for wasm 32 func NewQueryCmd(cdc *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 33 queryCmd := &cobra.Command{ 34 Use: types.ModuleName, 35 Short: "Querying commands for the wasm module", 36 DisableFlagParsing: true, 37 SuggestionsMinimumDistance: 2, 38 RunE: client.ValidateCmd, 39 } 40 41 queryCmd.AddCommand( 42 NewCmdListCode(cdc, reg), 43 NewCmdListContractByCode(cdc, reg), 44 NewCmdQueryCode(cdc, reg), 45 NewCmdQueryCodeInfo(cdc, reg), 46 NewCmdGetContractInfo(cdc, reg), 47 NewCmdGetContractHistory(cdc, reg), 48 NewCmdGetContractState(cdc, reg), 49 NewCmdListPinnedCode(cdc, reg), 50 NewCmdLibVersion(cdc, reg), 51 NewCmdListContractBlockedMethod(cdc), 52 NewCmdGetParams(cdc, reg), 53 NewCmdGetAddressWhitelist(cdc, reg), 54 ) 55 56 return queryCmd 57 } 58 59 // NewCmdLibVersion gets current libwasmvm version. 60 func NewCmdLibVersion(m *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 61 cmd := &cobra.Command{ 62 Use: "libwasmvm-version", 63 Short: "Get libwasmvm version", 64 Long: "Get libwasmvm version", 65 Aliases: []string{"lib-version"}, 66 Args: cobra.ExactArgs(0), 67 RunE: func(cmd *cobra.Command, args []string) error { 68 version, err := wasmvm.LibwasmvmVersion() 69 if err != nil { 70 return fmt.Errorf("error retrieving libwasmvm version: %w", err) 71 } 72 fmt.Println(version) 73 return nil 74 }, 75 } 76 return cmd 77 } 78 79 // NewCmdListCode lists all wasm code uploaded 80 func NewCmdListCode(m *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 81 cmd := &cobra.Command{ 82 Use: "list-code", 83 Short: "List all wasm bytecode on the chain", 84 Long: "List all wasm bytecode on the chain", 85 Aliases: []string{"list-codes", "codes", "lco"}, 86 Args: cobra.ExactArgs(0), 87 RunE: func(cmd *cobra.Command, args []string) error { 88 clientCtx := clientCtx.NewCLIContext().WithProxy(m).WithInterfaceRegistry(reg) 89 queryClient := types.NewQueryClient(clientCtx) 90 91 pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags())) 92 if err != nil { 93 return err 94 } 95 res, err := queryClient.Codes( 96 context.Background(), 97 &types.QueryCodesRequest{ 98 Pagination: pageReq, 99 }, 100 ) 101 if err != nil { 102 return err 103 } 104 return clientCtx.PrintProto(res) 105 }, 106 } 107 flags.AddQueryFlagsToCmd(cmd) 108 flags.AddPaginationFlagsToCmd(cmd, "list codes") 109 return cmd 110 } 111 112 func NewCmdGetParams(m *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 113 cmd := &cobra.Command{ 114 Use: "get-params", 115 Short: "Get wasm parameters on the chain", 116 Long: "Get wasm parameters on the chain", 117 Aliases: []string{"get-params", "params"}, 118 Args: cobra.ExactArgs(0), 119 RunE: func(cmd *cobra.Command, args []string) error { 120 clientCtx := clientCtx.NewCLIContext().WithProxy(m).WithInterfaceRegistry(reg) 121 route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, keeper.QueryParams) 122 123 res, _, err := clientCtx.Query(route) 124 if err != nil { 125 return err 126 } 127 128 var params types.Params 129 m.GetCdc().MustUnmarshalJSON(res, ¶ms) 130 return clientCtx.PrintOutput(params) 131 }, 132 } 133 return cmd 134 } 135 136 func NewCmdGetAddressWhitelist(m *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 137 cmd := &cobra.Command{ 138 Use: "get-address-whitelist", 139 Short: "Get wasm address whitelist on the chain", 140 Long: "Get wasm address whitelist on the chain", 141 Aliases: []string{"whitelist", "gawl"}, 142 Args: cobra.ExactArgs(0), 143 RunE: func(cmd *cobra.Command, args []string) error { 144 clientCtx := clientCtx.NewCLIContext().WithProxy(m).WithInterfaceRegistry(reg) 145 route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, keeper.QueryParams) 146 147 res, _, err := clientCtx.Query(route) 148 if err != nil { 149 return err 150 } 151 152 var params types.Params 153 m.GetCdc().MustUnmarshalJSON(res, ¶ms) 154 var whitelist []string 155 whitelist = strings.Split(params.CodeUploadAccess.Address, ",") 156 if len(whitelist) == 1 && whitelist[0] == "" { 157 whitelist = []string{} 158 } 159 response := types.NewQueryAddressWhitelistResponse(whitelist) 160 return clientCtx.PrintOutput(response) 161 }, 162 } 163 return cmd 164 } 165 166 // NewCmdListContractByCode lists all wasm code uploaded for given code id 167 func NewCmdListContractByCode(m *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 168 cmd := &cobra.Command{ 169 Use: "list-contract-by-code [code_id]", 170 Short: "List wasm all bytecode on the chain for given code id", 171 Long: "List wasm all bytecode on the chain for given code id", 172 Aliases: []string{"list-contracts-by-code", "list-contracts", "contracts", "lca"}, 173 Args: cobra.ExactArgs(1), 174 RunE: func(cmd *cobra.Command, args []string) error { 175 clientCtx := clientCtx.NewCLIContext().WithProxy(m).WithInterfaceRegistry(reg) 176 queryClient := types.NewQueryClient(clientCtx) 177 178 codeID, err := strconv.ParseUint(args[0], 10, 64) 179 if err != nil { 180 return err 181 } 182 pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags())) 183 if err != nil { 184 return err 185 } 186 res, err := queryClient.ContractsByCode( 187 context.Background(), 188 &types.QueryContractsByCodeRequest{ 189 CodeId: codeID, 190 Pagination: pageReq, 191 }, 192 ) 193 if err != nil { 194 return err 195 } 196 return clientCtx.PrintProto(res) 197 }, 198 } 199 flags.AddQueryFlagsToCmd(cmd) 200 flags.AddPaginationFlagsToCmd(cmd, "list contracts by code") 201 return cmd 202 } 203 204 // NewCmdQueryCode returns the bytecode for a given contract 205 func NewCmdQueryCode(m *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 206 cmd := &cobra.Command{ 207 Use: "code [code_id] [output filename]", 208 Short: "Downloads wasm bytecode for given code id", 209 Long: "Downloads wasm bytecode for given code id", 210 Aliases: []string{"source-code", "source"}, 211 Args: cobra.ExactArgs(2), 212 RunE: func(cmd *cobra.Command, args []string) error { 213 clientCtx := clientCtx.NewCLIContext().WithProxy(m).WithInterfaceRegistry(reg) 214 queryClient := types.NewQueryClient(clientCtx) 215 216 codeID, err := strconv.ParseUint(args[0], 10, 64) 217 if err != nil { 218 return err 219 } 220 res, err := queryClient.Code( 221 context.Background(), 222 &types.QueryCodeRequest{ 223 CodeId: codeID, 224 }, 225 ) 226 if err != nil { 227 return err 228 } 229 if len(res.Data) == 0 { 230 return fmt.Errorf("contract not found") 231 } 232 233 fmt.Printf("Downloading wasm code to %s\n", args[1]) 234 return ioutil.WriteFile(args[1], res.Data, 0o600) 235 }, 236 } 237 flags.AddQueryFlagsToCmd(cmd) 238 return cmd 239 } 240 241 // NewCmdQueryCodeInfo returns the code info for a given code id 242 func NewCmdQueryCodeInfo(m *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 243 cmd := &cobra.Command{ 244 Use: "code-info [code_id]", 245 Short: "Prints out metadata of a code id", 246 Long: "Prints out metadata of a code id", 247 Args: cobra.ExactArgs(1), 248 RunE: func(cmd *cobra.Command, args []string) error { 249 clientCtx := clientCtx.NewCLIContext().WithProxy(m).WithInterfaceRegistry(reg) 250 251 codeID, err := strconv.ParseUint(args[0], 10, 64) 252 if err != nil { 253 return err 254 } 255 256 queryClient := types.NewQueryClient(clientCtx) 257 res, err := queryClient.Code( 258 context.Background(), 259 &types.QueryCodeRequest{ 260 CodeId: codeID, 261 }, 262 ) 263 if err != nil { 264 return err 265 } 266 if res.CodeInfoResponse == nil { 267 return fmt.Errorf("contract not found") 268 } 269 270 return clientCtx.PrintProto(res.CodeInfoResponse) 271 }, 272 } 273 flags.AddQueryFlagsToCmd(cmd) 274 return cmd 275 } 276 277 // NewCmdGetContractInfo gets details about a given contract 278 func NewCmdGetContractInfo(m *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 279 cmd := &cobra.Command{ 280 Use: "contract [bech32_address]", 281 Short: "Prints out metadata of a contract given its address", 282 Long: "Prints out metadata of a contract given its address", 283 Aliases: []string{"meta", "c"}, 284 Args: cobra.ExactArgs(1), 285 RunE: func(cmd *cobra.Command, args []string) error { 286 clientCtx := clientCtx.NewCLIContext().WithProxy(m).WithInterfaceRegistry(reg) 287 queryClient := types.NewQueryClient(clientCtx) 288 289 _, err := sdk.AccAddressFromBech32(args[0]) 290 if err != nil { 291 return err 292 } 293 res, err := queryClient.ContractInfo( 294 context.Background(), 295 &types.QueryContractInfoRequest{ 296 Address: args[0], 297 }, 298 ) 299 if err != nil { 300 return err 301 } 302 return clientCtx.PrintProto(res) 303 }, 304 } 305 flags.AddQueryFlagsToCmd(cmd) 306 return cmd 307 } 308 309 func NewCmdListContractBlockedMethod(m *codec.CodecProxy) *cobra.Command { 310 cmd := &cobra.Command{ 311 Use: "list-contract-blocked-method [bech32_address]", 312 Short: "List blocked methods of a contract given its address", 313 Long: "List blocked methods of a contract given its address", 314 Aliases: []string{"lcbm"}, 315 Args: cobra.ExactArgs(1), 316 RunE: func(cmd *cobra.Command, args []string) error { 317 clientCtx := clientCtx.NewCLIContext().WithCodec(m.GetCdc()) 318 319 _, err := sdk.AccAddressFromBech32(args[0]) 320 if err != nil { 321 return err 322 } 323 res, _, err := clientCtx.Query(fmt.Sprintf("custom/wasm/list-contract-blocked-method/%s", args[0])) 324 if err != nil { 325 return err 326 } 327 return clientCtx.PrintOutput(res) 328 }, 329 } 330 flags.AddQueryFlagsToCmd(cmd) 331 return cmd 332 } 333 334 // NewCmdGetContractHistory prints the code history for a given contract 335 func NewCmdGetContractHistory(m *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 336 cmd := &cobra.Command{ 337 Use: "contract-history [bech32_address]", 338 Short: "Prints out the code history for a contract given its address", 339 Long: "Prints out the code history for a contract given its address", 340 Aliases: []string{"history", "hist", "ch"}, 341 Args: cobra.ExactArgs(1), 342 RunE: func(cmd *cobra.Command, args []string) error { 343 clientCtx := clientCtx.NewCLIContext().WithProxy(m).WithInterfaceRegistry(reg) 344 queryClient := types.NewQueryClient(clientCtx) 345 346 _, err := sdk.AccAddressFromBech32(args[0]) 347 if err != nil { 348 return err 349 } 350 pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags())) 351 if err != nil { 352 return err 353 } 354 res, err := queryClient.ContractHistory( 355 context.Background(), 356 &types.QueryContractHistoryRequest{ 357 Address: args[0], 358 Pagination: pageReq, 359 }, 360 ) 361 if err != nil { 362 return err 363 } 364 365 return clientCtx.PrintProto(res) 366 }, 367 } 368 369 flags.AddQueryFlagsToCmd(cmd) 370 flags.AddPaginationFlagsToCmd(cmd, "contract history") 371 return cmd 372 } 373 374 // NewCmdGetContractState dumps full internal state of a given contract 375 func NewCmdGetContractState(m *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 376 cmd := &cobra.Command{ 377 Use: "contract-state", 378 Short: "Querying commands for the wasm module", 379 Aliases: []string{"state", "cs", "s"}, 380 DisableFlagParsing: true, 381 SuggestionsMinimumDistance: 2, 382 RunE: client.ValidateCmd, 383 } 384 cmd.AddCommand( 385 newCmdGetContractStateAll(m, reg), 386 newCmdGetContractStateRaw(m, reg), 387 newCmdGetContractStateSmart(m, reg), 388 ) 389 return cmd 390 } 391 392 func newCmdGetContractStateAll(m *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 393 cmd := &cobra.Command{ 394 Use: "all [bech32_address]", 395 Short: "Prints out all internal state of a contract given its address", 396 Long: "Prints out all internal state of a contract given its address", 397 Args: cobra.ExactArgs(1), 398 RunE: func(cmd *cobra.Command, args []string) error { 399 clientCtx := clientCtx.NewCLIContext().WithProxy(m).WithInterfaceRegistry(reg) 400 queryClient := types.NewQueryClient(clientCtx) 401 402 _, err := sdk.AccAddressFromBech32(args[0]) 403 if err != nil { 404 return err 405 } 406 pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags())) 407 if err != nil { 408 return err 409 } 410 res, err := queryClient.AllContractState( 411 context.Background(), 412 &types.QueryAllContractStateRequest{ 413 Address: args[0], 414 Pagination: pageReq, 415 }, 416 ) 417 if err != nil { 418 return err 419 } 420 return clientCtx.PrintProto(res) 421 }, 422 } 423 flags.AddQueryFlagsToCmd(cmd) 424 flags.AddPaginationFlagsToCmd(cmd, "contract state") 425 return cmd 426 } 427 428 func newCmdGetContractStateRaw(m *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 429 decoder := newArgDecoder(hex.DecodeString) 430 cmd := &cobra.Command{ 431 Use: "raw [bech32_address] [key]", 432 Short: "Prints out internal state for key of a contract given its address", 433 Long: "Prints out internal state for of a contract given its address", 434 Args: cobra.ExactArgs(2), 435 RunE: func(cmd *cobra.Command, args []string) error { 436 clientCtx := clientCtx.NewCLIContext().WithProxy(m).WithInterfaceRegistry(reg) 437 queryClient := types.NewQueryClient(clientCtx) 438 439 _, err := sdk.AccAddressFromBech32(args[0]) 440 if err != nil { 441 return err 442 } 443 queryData, err := decoder.DecodeString(args[1]) 444 if err != nil { 445 return err 446 } 447 448 res, err := queryClient.RawContractState( 449 context.Background(), 450 &types.QueryRawContractStateRequest{ 451 Address: args[0], 452 QueryData: queryData, 453 }, 454 ) 455 if err != nil { 456 return err 457 } 458 return clientCtx.PrintProto(res) 459 }, 460 } 461 decoder.RegisterFlags(cmd.PersistentFlags(), "key argument") 462 flags.AddQueryFlagsToCmd(cmd) 463 return cmd 464 } 465 466 func newCmdGetContractStateSmart(m *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 467 decoder := newArgDecoder(asciiDecodeString) 468 cmd := &cobra.Command{ 469 Use: "smart [bech32_address] [query]", 470 Short: "Calls contract with given address with query data and prints the returned result", 471 Long: "Calls contract with given address with query data and prints the returned result", 472 Args: cobra.ExactArgs(2), 473 RunE: func(cmd *cobra.Command, args []string) error { 474 clientCtx := clientCtx.NewCLIContext().WithProxy(m).WithInterfaceRegistry(reg) 475 queryClient := types.NewQueryClient(clientCtx) 476 477 _, err := sdk.AccAddressFromBech32(args[0]) 478 if err != nil { 479 return err 480 } 481 if args[1] == "" { 482 return errors.New("query data must not be empty") 483 } 484 queryData, err := decoder.DecodeString(args[1]) 485 if err != nil { 486 return fmt.Errorf("decode query: %s", err) 487 } 488 if !json.Valid(queryData) { 489 return errors.New("query data must be json") 490 } 491 492 res, err := queryClient.SmartContractState( 493 context.Background(), 494 &types.QuerySmartContractStateRequest{ 495 Address: args[0], 496 QueryData: queryData, 497 }, 498 ) 499 if err != nil { 500 return err 501 } 502 return clientCtx.PrintProto(res) 503 }, 504 } 505 decoder.RegisterFlags(cmd.PersistentFlags(), "query argument") 506 flags.AddQueryFlagsToCmd(cmd) 507 return cmd 508 } 509 510 // NewCmdListPinnedCode lists all wasm code ids that are pinned 511 func NewCmdListPinnedCode(m *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command { 512 cmd := &cobra.Command{ 513 Use: "pinned", 514 Short: "List all pinned code ids", 515 Long: "\t\tLong: List all pinned code ids,\n", 516 Args: cobra.ExactArgs(0), 517 RunE: func(cmd *cobra.Command, args []string) error { 518 clientCtx := clientCtx.NewCLIContext().WithProxy(m).WithInterfaceRegistry(reg) 519 queryClient := types.NewQueryClient(clientCtx) 520 521 pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags())) 522 if err != nil { 523 return err 524 } 525 res, err := queryClient.PinnedCodes( 526 context.Background(), 527 &types.QueryPinnedCodesRequest{ 528 Pagination: pageReq, 529 }, 530 ) 531 if err != nil { 532 return err 533 } 534 return clientCtx.PrintProto(res) 535 }, 536 } 537 flags.AddQueryFlagsToCmd(cmd) 538 flags.AddPaginationFlagsToCmd(cmd, "list codes") 539 return cmd 540 } 541 542 type argumentDecoder struct { 543 // dec is the default decoder 544 dec func(string) ([]byte, error) 545 asciiF, hexF, b64F bool 546 } 547 548 func newArgDecoder(def func(string) ([]byte, error)) *argumentDecoder { 549 return &argumentDecoder{dec: def} 550 } 551 552 func (a *argumentDecoder) RegisterFlags(f *flag.FlagSet, argName string) { 553 f.BoolVar(&a.asciiF, "ascii", false, "ascii encoded "+argName) 554 f.BoolVar(&a.hexF, "hex", false, "hex encoded "+argName) 555 f.BoolVar(&a.b64F, "b64", false, "base64 encoded "+argName) 556 } 557 558 func (a *argumentDecoder) DecodeString(s string) ([]byte, error) { 559 found := -1 560 for i, v := range []*bool{&a.asciiF, &a.hexF, &a.b64F} { 561 if !*v { 562 continue 563 } 564 if found != -1 { 565 return nil, errors.New("multiple decoding flags used") 566 } 567 found = i 568 } 569 switch found { 570 case 0: 571 return asciiDecodeString(s) 572 case 1: 573 return hex.DecodeString(s) 574 case 2: 575 return base64.StdEncoding.DecodeString(s) 576 default: 577 return a.dec(s) 578 } 579 } 580 581 func asciiDecodeString(s string) ([]byte, error) { 582 return []byte(s), nil 583 } 584 585 // sdk ReadPageRequest expects binary but we encoded to base64 in our marshaller 586 func withPageKeyDecoded(flagSet *flag.FlagSet) *flag.FlagSet { 587 encoded, err := flagSet.GetString(flags.FlagPageKey) 588 if err != nil { 589 panic(err.Error()) 590 } 591 raw, err := base64.StdEncoding.DecodeString(encoded) 592 if err != nil { 593 panic(err.Error()) 594 } 595 err = flagSet.Set(flags.FlagPageKey, string(raw)) 596 if err != nil { 597 panic(err.Error()) 598 } 599 return flagSet 600 }