github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/wasm/client/rest/query.go (about) 1 package rest 2 3 import ( 4 "context" 5 "encoding/base64" 6 "encoding/hex" 7 "encoding/json" 8 "fmt" 9 "net/http" 10 "strconv" 11 "strings" 12 13 clientCtx "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/context" 14 15 "github.com/gorilla/mux" 16 17 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 18 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/rest" 19 20 "github.com/fibonacci-chain/fbc/x/wasm/keeper" 21 "github.com/fibonacci-chain/fbc/x/wasm/types" 22 ) 23 24 func registerQueryRoutes(cliCtx clientCtx.CLIContext, r *mux.Router) { 25 r.HandleFunc("/wasm/code", listCodesHandlerFn(cliCtx)).Methods("GET") 26 r.HandleFunc("/wasm/code/{codeID}", queryCodeHandlerFn(cliCtx)).Methods("GET") 27 r.HandleFunc("/wasm/code/{codeID}/contracts", listContractsByCodeHandlerFn(cliCtx)).Methods("GET") 28 r.HandleFunc("/wasm/contract/{contractAddr}", queryContractHandlerFn(cliCtx)).Methods("GET") 29 r.HandleFunc("/wasm/contract/{contractAddr}/state", queryContractStateAllHandlerFn(cliCtx)).Methods("GET") 30 r.HandleFunc("/wasm/contract/{contractAddr}/history", queryContractHistoryFn(cliCtx)).Methods("GET") 31 r.HandleFunc("/wasm/contract/{contractAddr}/smart/{query}", queryContractStateSmartHandlerFn(cliCtx)).Queries("encoding", "{encoding}").Methods("GET") 32 r.HandleFunc("/wasm/contract/{contractAddr}/raw/{key}", queryContractStateRawHandlerFn(cliCtx)).Queries("encoding", "{encoding}").Methods("GET") 33 r.HandleFunc("/wasm/contract/{contractAddr}/blocked_methods", queryContractBlockedMethodsHandlerFn(cliCtx)).Methods("GET") 34 r.HandleFunc("/wasm/params", queryParamsHandlerFn(cliCtx)).Methods("GET") 35 r.HandleFunc("/wasm/whitelist", queryContractWhitelistHandlerFn(cliCtx)).Methods("GET") 36 } 37 38 func queryParamsHandlerFn(cliCtx clientCtx.CLIContext) http.HandlerFunc { 39 return func(w http.ResponseWriter, r *http.Request) { 40 cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) 41 if !ok { 42 return 43 } 44 route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, keeper.QueryParams) 45 46 res, height, err := cliCtx.Query(route) 47 if err != nil { 48 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 49 return 50 } 51 52 cliCtx = cliCtx.WithHeight(height) 53 rest.PostProcessResponse(w, cliCtx, res) 54 } 55 } 56 57 func queryContractWhitelistHandlerFn(cliCtx clientCtx.CLIContext) http.HandlerFunc { 58 return func(w http.ResponseWriter, r *http.Request) { 59 cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) 60 if !ok { 61 return 62 } 63 route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, keeper.QueryParams) 64 65 res, height, err := cliCtx.Query(route) 66 if err != nil { 67 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 68 return 69 } 70 var params types.Params 71 cliCtx.Codec.MustUnmarshalJSON(res, ¶ms) 72 var whitelist []string 73 whitelist = strings.Split(params.CodeUploadAccess.Address, ",") 74 // When params.CodeUploadAccess.Address == "", whitelist == []string{""} and len(whitelist) == 1. 75 // Above case should be avoided. 76 if len(whitelist) == 1 && whitelist[0] == "" { 77 whitelist = []string{} 78 } 79 response := types.NewQueryAddressWhitelistResponse(whitelist) 80 cliCtx = cliCtx.WithHeight(height) 81 rest.PostProcessResponse(w, cliCtx, response) 82 } 83 } 84 85 func listCodesHandlerFn(cliCtx clientCtx.CLIContext) http.HandlerFunc { 86 return func(w http.ResponseWriter, r *http.Request) { 87 cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) 88 if !ok { 89 return 90 } 91 queryClient := types.NewQueryClient(cliCtx) 92 pageReq, err := rest.ParseGRPCWasmPageRequest(r) 93 if err != nil { 94 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 95 return 96 } 97 var reverse bool 98 reverseStr := r.FormValue("reverse") 99 if reverseStr == "" { 100 reverse = false 101 } else { 102 reverse, err = strconv.ParseBool(reverseStr) 103 if err != nil { 104 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 105 return 106 } 107 } 108 109 res, err := queryClient.Codes( 110 context.Background(), 111 &types.QueryCodesRequest{ 112 Pagination: pageReq, 113 }, 114 ) 115 116 if reverse { 117 for i, j := 0, len(res.CodeInfos)-1; i < j; i, j = i+1, j-1 { 118 res.CodeInfos[i], res.CodeInfos[j] = res.CodeInfos[j], res.CodeInfos[i] 119 } 120 } 121 122 if err != nil { 123 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 124 return 125 } 126 127 rest.PostProcessResponse(w, cliCtx, res) 128 129 } 130 } 131 132 func queryCodeHandlerFn(cliCtx clientCtx.CLIContext) http.HandlerFunc { 133 return func(w http.ResponseWriter, r *http.Request) { 134 codeID, err := strconv.ParseUint(mux.Vars(r)["codeID"], 10, 64) 135 if err != nil { 136 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 137 return 138 } 139 140 cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) 141 if !ok { 142 return 143 } 144 145 route := fmt.Sprintf("custom/%s/%s/%d", types.QuerierRoute, keeper.QueryGetCode, codeID) 146 res, height, err := cliCtx.Query(route) 147 if err != nil { 148 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 149 return 150 } 151 if len(res) == 0 { 152 rest.WriteErrorResponse(w, http.StatusNotFound, "contract not found") 153 return 154 } 155 156 cliCtx = cliCtx.WithHeight(height) 157 rest.PostProcessResponse(w, cliCtx, json.RawMessage(res)) 158 } 159 } 160 161 func listContractsByCodeHandlerFn(cliCtx clientCtx.CLIContext) http.HandlerFunc { 162 return func(w http.ResponseWriter, r *http.Request) { 163 codeID, err := strconv.ParseUint(mux.Vars(r)["codeID"], 10, 64) 164 if err != nil { 165 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 166 return 167 } 168 cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) 169 if !ok { 170 return 171 } 172 173 queryClient := types.NewQueryClient(cliCtx) 174 pageReq, err := rest.ParseGRPCWasmPageRequest(r) 175 if err != nil { 176 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 177 return 178 } 179 var reverse bool 180 reverseStr := r.FormValue("reverse") 181 if reverseStr == "" { 182 reverse = false 183 } else { 184 reverse, err = strconv.ParseBool(reverseStr) 185 if err != nil { 186 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 187 return 188 } 189 } 190 191 res, err := queryClient.ContractsByCode( 192 context.Background(), 193 &types.QueryContractsByCodeRequest{ 194 CodeId: codeID, 195 Pagination: pageReq, 196 }, 197 ) 198 199 if reverse { 200 for i, j := 0, len(res.Contracts)-1; i < j; i, j = i+1, j-1 { 201 res.Contracts[i], res.Contracts[j] = res.Contracts[j], res.Contracts[i] 202 } 203 } 204 205 if err != nil { 206 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 207 return 208 } 209 210 rest.PostProcessResponse(w, cliCtx, res) 211 } 212 } 213 214 func queryContractHandlerFn(cliCtx clientCtx.CLIContext) http.HandlerFunc { 215 return func(w http.ResponseWriter, r *http.Request) { 216 addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"]) 217 if err != nil { 218 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 219 return 220 } 221 cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) 222 if !ok { 223 return 224 } 225 226 route := fmt.Sprintf("custom/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContract, addr.String()) 227 res, height, err := cliCtx.Query(route) 228 if err != nil { 229 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 230 return 231 } 232 233 cliCtx = cliCtx.WithHeight(height) 234 rest.PostProcessResponse(w, cliCtx, json.RawMessage(res)) 235 } 236 } 237 238 func queryContractBlockedMethodsHandlerFn(cliCtx clientCtx.CLIContext) http.HandlerFunc { 239 return func(w http.ResponseWriter, r *http.Request) { 240 addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"]) 241 if err != nil { 242 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 243 return 244 } 245 cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) 246 if !ok { 247 return 248 } 249 250 route := fmt.Sprintf("custom/%s/%s/%s", types.QuerierRoute, keeper.QueryListContractBlockedMethod, addr.String()) 251 res, height, err := cliCtx.Query(route) 252 if err != nil { 253 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 254 return 255 } 256 257 cliCtx = cliCtx.WithHeight(height) 258 rest.PostProcessResponse(w, cliCtx, json.RawMessage(res)) 259 } 260 } 261 262 func queryContractStateAllHandlerFn(cliCtx clientCtx.CLIContext) http.HandlerFunc { 263 return func(w http.ResponseWriter, r *http.Request) { 264 addr := mux.Vars(r)["contractAddr"] 265 266 cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) 267 if !ok { 268 return 269 } 270 271 queryClient := types.NewQueryClient(cliCtx) 272 pageReq, err := rest.ParseGRPCWasmPageRequest(r) 273 if err != nil { 274 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 275 return 276 } 277 var reverse bool 278 reverseStr := r.FormValue("reverse") 279 if reverseStr == "" { 280 reverse = false 281 } else { 282 reverse, err = strconv.ParseBool(reverseStr) 283 if err != nil { 284 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 285 return 286 } 287 } 288 289 res, err := queryClient.AllContractState( 290 context.Background(), 291 &types.QueryAllContractStateRequest{ 292 Address: addr, 293 Pagination: pageReq, 294 }, 295 ) 296 297 if reverse { 298 for i, j := 0, len(res.Models)-1; i < j; i, j = i+1, j-1 { 299 res.Models[i], res.Models[j] = res.Models[j], res.Models[i] 300 } 301 } 302 303 if err != nil { 304 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 305 return 306 } 307 308 rest.PostProcessResponse(w, cliCtx, res) 309 } 310 } 311 312 func queryContractStateRawHandlerFn(cliCtx clientCtx.CLIContext) http.HandlerFunc { 313 return func(w http.ResponseWriter, r *http.Request) { 314 decoder := newArgDecoder(hex.DecodeString) 315 addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"]) 316 if err != nil { 317 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 318 return 319 } 320 decoder.encoding = mux.Vars(r)["encoding"] 321 queryData, err := decoder.DecodeString(mux.Vars(r)["key"]) 322 if err != nil { 323 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 324 return 325 } 326 cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) 327 if !ok { 328 return 329 } 330 331 route := fmt.Sprintf("custom/%s/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContractState, addr.String(), keeper.QueryMethodContractStateRaw) 332 res, height, err := cliCtx.QueryWithData(route, queryData) 333 if err != nil { 334 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 335 return 336 } 337 cliCtx = cliCtx.WithHeight(height) 338 // ensure this is base64 encoded 339 encoded := base64.StdEncoding.EncodeToString(res) 340 rest.PostProcessResponse(w, cliCtx, encoded) 341 } 342 } 343 344 type smartResponse struct { 345 Smart []byte `json:"smart"` 346 } 347 348 func queryContractStateSmartHandlerFn(cliCtx clientCtx.CLIContext) http.HandlerFunc { 349 return func(w http.ResponseWriter, r *http.Request) { 350 decoder := newArgDecoder(hex.DecodeString) 351 addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"]) 352 if err != nil { 353 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 354 return 355 } 356 decoder.encoding = mux.Vars(r)["encoding"] 357 cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) 358 if !ok { 359 return 360 } 361 362 route := fmt.Sprintf("custom/%s/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContractState, addr.String(), keeper.QueryMethodContractStateSmart) 363 364 queryData, err := decoder.DecodeString(mux.Vars(r)["query"]) 365 if err != nil { 366 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 367 return 368 } 369 res, height, err := cliCtx.QueryWithData(route, queryData) 370 if err != nil { 371 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 372 return 373 } 374 // return as raw bytes (to be base64-encoded) 375 responseData := smartResponse{Smart: res} 376 377 cliCtx = cliCtx.WithHeight(height) 378 rest.PostProcessResponse(w, cliCtx, responseData) 379 } 380 } 381 382 func queryContractHistoryFn(cliCtx clientCtx.CLIContext) http.HandlerFunc { 383 return func(w http.ResponseWriter, r *http.Request) { 384 addr := mux.Vars(r)["contractAddr"] 385 386 cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) 387 if !ok { 388 return 389 } 390 391 queryClient := types.NewQueryClient(cliCtx) 392 pageReq, err := rest.ParseGRPCWasmPageRequest(r) 393 if err != nil { 394 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 395 return 396 } 397 var reverse bool 398 reverseStr := r.FormValue("reverse") 399 if reverseStr == "" { 400 reverse = false 401 } else { 402 reverse, err = strconv.ParseBool(reverseStr) 403 if err != nil { 404 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 405 return 406 } 407 } 408 409 res, err := queryClient.ContractHistory( 410 context.Background(), 411 &types.QueryContractHistoryRequest{ 412 Address: addr, 413 Pagination: pageReq, 414 }, 415 ) 416 417 if reverse { 418 for i, j := 0, len(res.Entries)-1; i < j; i, j = i+1, j-1 { 419 res.Entries[i], res.Entries[j] = res.Entries[j], res.Entries[i] 420 } 421 } 422 423 if err != nil { 424 rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) 425 return 426 } 427 428 rest.PostProcessResponse(w, cliCtx, res) 429 } 430 } 431 432 type argumentDecoder struct { 433 // dec is the default decoder 434 dec func(string) ([]byte, error) 435 encoding string 436 } 437 438 func newArgDecoder(def func(string) ([]byte, error)) *argumentDecoder { 439 return &argumentDecoder{dec: def} 440 } 441 442 func (a *argumentDecoder) DecodeString(s string) ([]byte, error) { 443 switch a.encoding { 444 case "hex": 445 return hex.DecodeString(s) 446 case "base64": 447 return base64.StdEncoding.DecodeString(s) 448 default: 449 return a.dec(s) 450 } 451 }