laconicd-deprecated/x/wasm/keeper/legacy_querier.go
2023-02-28 15:05:49 +05:30

155 lines
5.0 KiB
Go

package keeper
import (
"encoding/json"
"reflect"
"strconv"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cerc-io/laconicd/x/wasm/types"
)
const (
QueryListContractByCode = "list-contracts-by-code"
QueryGetContract = "contract-info"
QueryGetContractState = "contract-state"
QueryGetCode = "code"
QueryListCode = "list-code"
QueryContractHistory = "contract-history"
)
const (
QueryMethodContractStateSmart = "smart"
QueryMethodContractStateAll = "all"
QueryMethodContractStateRaw = "raw"
)
// NewLegacyQuerier creates a new querier
// Deprecated: the rest support will be removed. You can use the GRPC gateway instead
func NewLegacyQuerier(keeper types.ViewKeeper, gasLimit sdk.Gas) sdk.Querier {
return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) {
var (
rsp interface{}
err error
)
switch path[0] {
case QueryGetContract:
addr, addrErr := sdk.AccAddressFromBech32(path[1])
if addrErr != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, addrErr.Error())
}
rsp, err = queryContractInfo(ctx, addr, keeper)
case QueryListContractByCode:
codeID, parseErr := strconv.ParseUint(path[1], 10, 64)
if parseErr != nil {
return nil, sdkerrors.Wrapf(types.ErrInvalid, "code id: %s", parseErr.Error())
}
rsp = queryContractListByCode(ctx, codeID, keeper)
case QueryGetContractState:
if len(path) < 3 {
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown data query endpoint")
}
return queryContractState(ctx, path[1], path[2], req.Data, gasLimit, keeper)
case QueryGetCode:
codeID, parseErr := strconv.ParseUint(path[1], 10, 64)
if parseErr != nil {
return nil, sdkerrors.Wrapf(types.ErrInvalid, "code id: %s", parseErr.Error())
}
rsp, err = queryCode(ctx, codeID, keeper)
case QueryListCode:
rsp, err = queryCodeList(ctx, keeper)
case QueryContractHistory:
contractAddr, addrErr := sdk.AccAddressFromBech32(path[1])
if addrErr != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, addrErr.Error())
}
rsp, err = queryContractHistory(ctx, contractAddr, keeper)
default:
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown data query endpoint")
}
if err != nil {
return nil, err
}
if rsp == nil || reflect.ValueOf(rsp).IsNil() {
return nil, nil
}
bz, err := json.MarshalIndent(rsp, "", " ")
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
}
func queryContractState(ctx sdk.Context, bech, queryMethod string, data []byte, gasLimit sdk.Gas, keeper types.ViewKeeper) (json.RawMessage, error) {
contractAddr, err := sdk.AccAddressFromBech32(bech)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, bech)
}
switch queryMethod {
case QueryMethodContractStateAll:
resultData := make([]types.Model, 0)
// this returns a serialized json object (which internally encoded binary fields properly)
keeper.IterateContractState(ctx, contractAddr, func(key, value []byte) bool {
resultData = append(resultData, types.Model{Key: key, Value: value})
return false
})
bz, err := json.Marshal(resultData)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
case QueryMethodContractStateRaw:
// this returns the raw data from the state, base64-encoded
return keeper.QueryRaw(ctx, contractAddr, data), nil
case QueryMethodContractStateSmart:
// we enforce a subjective gas limit on all queries to avoid infinite loops
ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimit))
msg := types.RawContractMessage(data)
if err := msg.ValidateBasic(); err != nil {
return nil, sdkerrors.Wrap(err, "json msg")
}
// this returns raw bytes (must be base64-encoded)
bz, err := keeper.QuerySmart(ctx, contractAddr, msg)
return bz, err
default:
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, queryMethod)
}
}
func queryCodeList(ctx sdk.Context, keeper types.ViewKeeper) ([]types.CodeInfoResponse, error) {
var info []types.CodeInfoResponse
keeper.IterateCodeInfos(ctx, func(i uint64, res types.CodeInfo) bool {
info = append(info, types.CodeInfoResponse{
CodeID: i,
Creator: res.Creator,
DataHash: res.CodeHash,
InstantiatePermission: res.InstantiateConfig,
})
return false
})
return info, nil
}
func queryContractHistory(ctx sdk.Context, contractAddr sdk.AccAddress, keeper types.ViewKeeper) ([]types.ContractCodeHistoryEntry, error) {
history := keeper.GetContractHistory(ctx, contractAddr)
// redact response
for i := range history {
history[i].Updated = nil
}
return history, nil
}
func queryContractListByCode(ctx sdk.Context, codeID uint64, keeper types.ViewKeeper) []string {
var contracts []string
keeper.IterateContractsByCode(ctx, codeID, func(addr sdk.AccAddress) bool {
contracts = append(contracts, addr.String())
return false
})
return contracts
}