mirror of https://github.com/certusone/wasmd.git
270 lines
8.6 KiB
Go
270 lines
8.6 KiB
Go
package rest
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/CosmWasm/wasmd/x/wasm/internal/keeper"
|
|
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/cosmos/cosmos-sdk/types/rest"
|
|
"github.com/gorilla/mux"
|
|
)
|
|
|
|
func registerQueryRoutes(cliCtx client.Context, r *mux.Router) {
|
|
r.HandleFunc("/wasm/code", listCodesHandlerFn(cliCtx)).Methods("GET")
|
|
r.HandleFunc("/wasm/code/{codeID}", queryCodeHandlerFn(cliCtx)).Methods("GET")
|
|
r.HandleFunc("/wasm/code/{codeID}/contracts", listContractsByCodeHandlerFn(cliCtx)).Methods("GET")
|
|
r.HandleFunc("/wasm/contract/{contractAddr}", queryContractHandlerFn(cliCtx)).Methods("GET")
|
|
r.HandleFunc("/wasm/contract/{contractAddr}/state", queryContractStateAllHandlerFn(cliCtx)).Methods("GET")
|
|
r.HandleFunc("/wasm/contract/{contractAddr}/history", queryContractHistoryFn(cliCtx)).Methods("GET")
|
|
r.HandleFunc("/wasm/contract/{contractAddr}/smart/{query}", queryContractStateSmartHandlerFn(cliCtx)).Queries("encoding", "{encoding}").Methods("GET")
|
|
r.HandleFunc("/wasm/contract/{contractAddr}/raw/{key}", queryContractStateRawHandlerFn(cliCtx)).Queries("encoding", "{encoding}").Methods("GET")
|
|
}
|
|
|
|
func listCodesHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, keeper.QueryListCode)
|
|
res, height, err := cliCtx.Query(route)
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
cliCtx = cliCtx.WithHeight(height)
|
|
rest.PostProcessResponse(w, cliCtx, json.RawMessage(res))
|
|
}
|
|
}
|
|
|
|
func queryCodeHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
codeID, err := strconv.ParseUint(mux.Vars(r)["codeID"], 10, 64)
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
|
|
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
route := fmt.Sprintf("custom/%s/%s/%d", types.QuerierRoute, keeper.QueryGetCode, codeID)
|
|
res, height, err := cliCtx.Query(route)
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
if len(res) == 0 {
|
|
rest.WriteErrorResponse(w, http.StatusNotFound, "contract not found")
|
|
return
|
|
}
|
|
|
|
cliCtx = cliCtx.WithHeight(height)
|
|
rest.PostProcessResponse(w, cliCtx, json.RawMessage(res))
|
|
}
|
|
}
|
|
|
|
func listContractsByCodeHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
codeID, err := strconv.ParseUint(mux.Vars(r)["codeID"], 10, 64)
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
route := fmt.Sprintf("custom/%s/%s/%d", types.QuerierRoute, keeper.QueryListContractByCode, codeID)
|
|
res, height, err := cliCtx.Query(route)
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
|
|
cliCtx = cliCtx.WithHeight(height)
|
|
rest.PostProcessResponse(w, cliCtx, json.RawMessage(res))
|
|
}
|
|
}
|
|
|
|
func queryContractHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"])
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
route := fmt.Sprintf("custom/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContract, addr.String())
|
|
res, height, err := cliCtx.Query(route)
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
|
|
cliCtx = cliCtx.WithHeight(height)
|
|
rest.PostProcessResponse(w, cliCtx, json.RawMessage(res))
|
|
}
|
|
}
|
|
|
|
func queryContractStateAllHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"])
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
route := fmt.Sprintf("custom/%s/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContractState, addr.String(), keeper.QueryMethodContractStateAll)
|
|
res, height, err := cliCtx.Query(route)
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
|
|
// parse res
|
|
var resultData []types.Model
|
|
err = json.Unmarshal(res, &resultData)
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
|
|
cliCtx = cliCtx.WithHeight(height)
|
|
rest.PostProcessResponse(w, cliCtx, resultData)
|
|
}
|
|
}
|
|
|
|
func queryContractStateRawHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
decoder := newArgDecoder(hex.DecodeString)
|
|
addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"])
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
decoder.encoding = mux.Vars(r)["encoding"]
|
|
queryData, err := decoder.DecodeString(mux.Vars(r)["key"])
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
route := fmt.Sprintf("custom/%s/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContractState, addr.String(), keeper.QueryMethodContractStateRaw)
|
|
res, height, err := cliCtx.QueryWithData(route, queryData)
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
cliCtx = cliCtx.WithHeight(height)
|
|
// ensure this is base64 encoded
|
|
encoded := base64.StdEncoding.EncodeToString(res)
|
|
rest.PostProcessResponse(w, cliCtx, encoded)
|
|
}
|
|
}
|
|
|
|
type smartResponse struct {
|
|
Smart []byte `json:"smart"`
|
|
}
|
|
|
|
func queryContractStateSmartHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
decoder := newArgDecoder(hex.DecodeString)
|
|
addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"])
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
decoder.encoding = mux.Vars(r)["encoding"]
|
|
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
route := fmt.Sprintf("custom/%s/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContractState, addr.String(), keeper.QueryMethodContractStateSmart)
|
|
|
|
queryData, err := decoder.DecodeString(mux.Vars(r)["query"])
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
res, height, err := cliCtx.QueryWithData(route, queryData)
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
// return as raw bytes (to be base64-encoded)
|
|
responseData := smartResponse{Smart: res}
|
|
|
|
cliCtx = cliCtx.WithHeight(height)
|
|
rest.PostProcessResponse(w, cliCtx, responseData)
|
|
}
|
|
}
|
|
|
|
func queryContractHistoryFn(cliCtx client.Context) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"])
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
route := fmt.Sprintf("custom/%s/%s/%s", types.QuerierRoute, keeper.QueryContractHistory, addr.String())
|
|
res, height, err := cliCtx.Query(route)
|
|
if err != nil {
|
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
cliCtx = cliCtx.WithHeight(height)
|
|
rest.PostProcessResponse(w, cliCtx, json.RawMessage(res))
|
|
}
|
|
}
|
|
|
|
type argumentDecoder struct {
|
|
// dec is the default decoder
|
|
dec func(string) ([]byte, error)
|
|
encoding string
|
|
}
|
|
|
|
func newArgDecoder(def func(string) ([]byte, error)) *argumentDecoder {
|
|
return &argumentDecoder{dec: def}
|
|
}
|
|
|
|
func (a *argumentDecoder) DecodeString(s string) ([]byte, error) {
|
|
switch a.encoding {
|
|
case "hex":
|
|
return hex.DecodeString(s)
|
|
case "base64":
|
|
return base64.StdEncoding.DecodeString(s)
|
|
default:
|
|
return a.dec(s)
|
|
}
|
|
}
|