Added stubs for handler, querier to compile code
This commit is contained in:
147
x/wasm/internal/keeper/handler_plugin.go
Normal file
147
x/wasm/internal/keeper/handler_plugin.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
wasmTypes "github.com/CosmWasm/go-cosmwasm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmwasm/wasmd/x/wasm/internal/types"
|
||||
)
|
||||
|
||||
type MessageHandler struct {
|
||||
router sdk.Router
|
||||
encoders MessageEncoders
|
||||
}
|
||||
|
||||
type MessageEncoders struct {
|
||||
Bank func(msg *wasmTypes.BankMsg) (sdk.Msg, error)
|
||||
Custom func(msg json.RawMessage) (sdk.Msg, error)
|
||||
Staking func(msg *wasmTypes.StakingMsg) (sdk.Msg, error)
|
||||
Wasm func(msg *wasmTypes.WasmMsg) (sdk.Msg, error)
|
||||
}
|
||||
|
||||
func DefaultEncoders() MessageEncoders {
|
||||
return MessageEncoders{
|
||||
Bank: EncodeBankMsg,
|
||||
Custom: NoCustomMsg,
|
||||
Staking: EncodeStakingMsg,
|
||||
Wasm: EncodeWasmMsg,
|
||||
}
|
||||
}
|
||||
|
||||
func EncodeBankMsg(msg *wasmTypes.BankMsg) (sdk.Msg, error) {
|
||||
if msg.Send == nil {
|
||||
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Unknown variant of Bank")
|
||||
}
|
||||
if len(msg.Send.Amount) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
fromAddr, stderr := sdk.AccAddressFromBech32(msg.Send.FromAddress)
|
||||
if stderr != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Send.FromAddress)
|
||||
}
|
||||
toAddr, stderr := sdk.AccAddressFromBech32(msg.Send.ToAddress)
|
||||
if stderr != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Send.ToAddress)
|
||||
}
|
||||
toSend, err := convertWasmCoinToSdkCoin(msg.Send.Amount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sendMsg := bank.MsgSend{
|
||||
FromAddress: fromAddr,
|
||||
ToAddress: toAddr,
|
||||
Amount: toSend,
|
||||
}
|
||||
return sendMsg, nil
|
||||
}
|
||||
|
||||
func NoCustomMsg(msg json.RawMessage) (sdk.Msg, error) {
|
||||
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Custom variant not supported")
|
||||
}
|
||||
|
||||
func EncodeStakingMsg(msg *wasmTypes.StakingMsg) (sdk.Msg, error) {
|
||||
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Staking variant not supported")
|
||||
}
|
||||
|
||||
func EncodeWasmMsg(msg *wasmTypes.WasmMsg) (sdk.Msg, error) {
|
||||
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Wasm variant not supported")
|
||||
// } else if msg.Contract != nil {
|
||||
// targetAddr, stderr := sdk.AccAddressFromBech32(msg.Contract.ContractAddr)
|
||||
// if stderr != nil {
|
||||
// return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Contract.ContractAddr)
|
||||
// }
|
||||
// sentFunds, err := convertWasmCoinToSdkCoin(msg.Contract.Send)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// // TODO: special case?
|
||||
// _, err = k.Execute(ctx, targetAddr, contractAddr, msg.Contract.Msg, sentFunds)
|
||||
// return err // may be nil
|
||||
}
|
||||
|
||||
func (h MessageHandler) Dispatch(ctx sdk.Context, contract exported.Account, msg wasmTypes.CosmosMsg) error {
|
||||
// maybe use this instead for the arg?
|
||||
contractAddr := contract.GetAddress()
|
||||
var sdkMsg sdk.Msg
|
||||
var err error
|
||||
switch {
|
||||
case msg.Bank != nil:
|
||||
sdkMsg, err = h.encoders.Bank(msg.Bank)
|
||||
case msg.Custom != nil:
|
||||
sdkMsg, err = h.encoders.Custom(msg.Custom)
|
||||
case msg.Staking != nil:
|
||||
sdkMsg, err = h.encoders.Staking(msg.Staking)
|
||||
case msg.Wasm != nil:
|
||||
sdkMsg, err = h.encoders.Wasm(msg.Wasm)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// (msg=nil, err=nil) is a no-op, ignore the message (eg. send with no tokens)
|
||||
if sdkMsg == nil {
|
||||
return nil
|
||||
}
|
||||
return h.handleSdkMessage(ctx, contractAddr, sdkMsg)
|
||||
}
|
||||
|
||||
func (h MessageHandler) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Address, msg sdk.Msg) error {
|
||||
// make sure this account can send it
|
||||
for _, acct := range msg.GetSigners() {
|
||||
if !acct.Equals(contractAddr) {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "contract doesn't have permission")
|
||||
}
|
||||
}
|
||||
|
||||
// find the handler and execute it
|
||||
handler := h.router.Route(ctx, msg.Route())
|
||||
if handler == nil {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, msg.Route())
|
||||
}
|
||||
res, err := handler(ctx, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// redispatch all events, (type sdk.EventTypeMessage will be filtered out in the handler)
|
||||
ctx.EventManager().EmitEvents(res.Events)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertWasmCoinToSdkCoin(coins []wasmTypes.Coin) (sdk.Coins, error) {
|
||||
var toSend sdk.Coins
|
||||
for _, coin := range coins {
|
||||
amount, ok := sdk.NewIntFromString(coin.Amount)
|
||||
if !ok {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, coin.Amount+coin.Denom)
|
||||
}
|
||||
c := sdk.Coin{
|
||||
Denom: coin.Denom,
|
||||
Amount: amount,
|
||||
}
|
||||
toSend = append(toSend, c)
|
||||
}
|
||||
return toSend, nil
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package keeper
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
wasm "github.com/CosmWasm/go-cosmwasm"
|
||||
@@ -37,7 +36,9 @@ type Keeper struct {
|
||||
|
||||
router sdk.Router
|
||||
|
||||
wasmer wasm.Wasmer
|
||||
wasmer wasm.Wasmer
|
||||
querier QueryHandler
|
||||
messenger MessageHandler
|
||||
// queryGasLimit is the max wasm gas that can be spent on executing a query with a contract
|
||||
queryGasLimit uint64
|
||||
}
|
||||
@@ -50,13 +51,18 @@ func NewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, accountKeeper auth.Accou
|
||||
panic(err)
|
||||
}
|
||||
|
||||
messenger := MessageHandler{
|
||||
router: router,
|
||||
}
|
||||
|
||||
return Keeper{
|
||||
storeKey: storeKey,
|
||||
cdc: cdc,
|
||||
wasmer: *wasmer,
|
||||
accountKeeper: accountKeeper,
|
||||
bankKeeper: bankKeeper,
|
||||
router: router,
|
||||
messenger: messenger,
|
||||
querier: QueryHandler{}, // TODO: not empty
|
||||
queryGasLimit: wasmConfig.SmartQueryGasLimit,
|
||||
}
|
||||
}
|
||||
@@ -127,7 +133,7 @@ func (k Keeper) Instantiate(ctx sdk.Context, codeID uint64, creator sdk.AccAddre
|
||||
|
||||
// instantiate wasm contract
|
||||
gas := gasForContract(ctx)
|
||||
res, err := k.wasmer.Instantiate(codeInfo.CodeHash, params, initMsg, prefixStore, cosmwasmAPI, gas)
|
||||
res, err := k.wasmer.Instantiate(codeInfo.CodeHash, params, initMsg, prefixStore, cosmwasmAPI, k.querier, gas)
|
||||
if err != nil {
|
||||
return contractAddress, sdkerrors.Wrap(types.ErrInstantiateFailed, err.Error())
|
||||
// return contractAddress, sdkerrors.Wrap(err, "cosmwasm instantiate")
|
||||
@@ -170,7 +176,7 @@ func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller
|
||||
params := types.NewParams(ctx, caller, coins, contractAccount)
|
||||
|
||||
gas := gasForContract(ctx)
|
||||
res, execErr := k.wasmer.Execute(codeInfo.CodeHash, params, msg, prefixStore, cosmwasmAPI, gas)
|
||||
res, execErr := k.wasmer.Execute(codeInfo.CodeHash, params, msg, prefixStore, cosmwasmAPI, k.querier, gas)
|
||||
if execErr != nil {
|
||||
// TODO: wasmer doesn't return gas used on error. we should consume it (for error on metering failure)
|
||||
return sdk.Result{}, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error())
|
||||
@@ -199,7 +205,7 @@ func (k Keeper) QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []b
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queryResult, gasUsed, qErr := k.wasmer.Query(codeInfo.CodeHash, req, prefixStore, cosmwasmAPI, gasForContract(ctx))
|
||||
queryResult, gasUsed, qErr := k.wasmer.Query(codeInfo.CodeHash, req, prefixStore, cosmwasmAPI, k.querier, gasForContract(ctx))
|
||||
if qErr != nil {
|
||||
return nil, sdkerrors.Wrap(types.ErrQueryFailed, qErr.Error())
|
||||
}
|
||||
@@ -313,112 +319,13 @@ func (k Keeper) GetByteCode(ctx sdk.Context, codeID uint64) ([]byte, error) {
|
||||
|
||||
func (k Keeper) dispatchMessages(ctx sdk.Context, contract exported.Account, msgs []wasmTypes.CosmosMsg) error {
|
||||
for _, msg := range msgs {
|
||||
if err := k.dispatchMessage(ctx, contract, msg); err != nil {
|
||||
if err := k.messenger.Dispatch(ctx, contract, msg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k Keeper) dispatchMessage(ctx sdk.Context, contract exported.Account, msg wasmTypes.CosmosMsg) error {
|
||||
// maybe use this instead for the arg?
|
||||
contractAddr := contract.GetAddress()
|
||||
if msg.Send != nil {
|
||||
return k.sendTokens(ctx, contractAddr, msg.Send.FromAddress, msg.Send.ToAddress, msg.Send.Amount)
|
||||
} else if msg.Contract != nil {
|
||||
targetAddr, stderr := sdk.AccAddressFromBech32(msg.Contract.ContractAddr)
|
||||
if stderr != nil {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Contract.ContractAddr)
|
||||
}
|
||||
sentFunds, err := convertWasmCoinToSdkCoin(msg.Contract.Send)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = k.Execute(ctx, targetAddr, contractAddr, msg.Contract.Msg, sentFunds)
|
||||
return err // may be nil
|
||||
} else if msg.Opaque != nil {
|
||||
msg, err := ParseOpaqueMsg(k.cdc, msg.Opaque)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return k.handleSdkMessage(ctx, contractAddr, msg)
|
||||
}
|
||||
// what is it?
|
||||
panic(fmt.Sprintf("Unknown CosmosMsg: %#v", msg))
|
||||
}
|
||||
|
||||
func (k Keeper) sendTokens(ctx sdk.Context, signer sdk.AccAddress, origin string, target string, tokens []wasmTypes.Coin) error {
|
||||
if len(tokens) == 0 {
|
||||
return nil
|
||||
}
|
||||
msg, err := convertCosmosSendMsg(origin, target, tokens)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return k.handleSdkMessage(ctx, signer, msg)
|
||||
}
|
||||
|
||||
func convertCosmosSendMsg(from string, to string, coins []wasmTypes.Coin) (bank.MsgSend, error) {
|
||||
fromAddr, stderr := sdk.AccAddressFromBech32(from)
|
||||
if stderr != nil {
|
||||
return bank.MsgSend{}, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, from)
|
||||
}
|
||||
toAddr, stderr := sdk.AccAddressFromBech32(to)
|
||||
if stderr != nil {
|
||||
return bank.MsgSend{}, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, to)
|
||||
}
|
||||
|
||||
toSend, err := convertWasmCoinToSdkCoin(coins)
|
||||
if err != nil {
|
||||
return bank.MsgSend{}, err
|
||||
}
|
||||
sendMsg := bank.MsgSend{
|
||||
FromAddress: fromAddr,
|
||||
ToAddress: toAddr,
|
||||
Amount: toSend,
|
||||
}
|
||||
return sendMsg, nil
|
||||
}
|
||||
|
||||
func convertWasmCoinToSdkCoin(coins []wasmTypes.Coin) (sdk.Coins, error) {
|
||||
var toSend sdk.Coins
|
||||
for _, coin := range coins {
|
||||
amount, ok := sdk.NewIntFromString(coin.Amount)
|
||||
if !ok {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, coin.Amount+coin.Denom)
|
||||
}
|
||||
c := sdk.Coin{
|
||||
Denom: coin.Denom,
|
||||
Amount: amount,
|
||||
}
|
||||
toSend = append(toSend, c)
|
||||
}
|
||||
return toSend, nil
|
||||
}
|
||||
|
||||
func (k Keeper) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Address, msg sdk.Msg) error {
|
||||
// make sure this account can send it
|
||||
for _, acct := range msg.GetSigners() {
|
||||
if !acct.Equals(contractAddr) {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "contract doesn't have permission")
|
||||
}
|
||||
}
|
||||
|
||||
// find the handler and execute it
|
||||
h := k.router.Route(ctx, msg.Route())
|
||||
if h == nil {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, msg.Route())
|
||||
}
|
||||
res, err := h(ctx, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// redispatch all events, (type sdk.EventTypeMessage will be filtered out in the handler)
|
||||
ctx.EventManager().EmitEvents(res.Events)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func gasForContract(ctx sdk.Context) uint64 {
|
||||
meter := ctx.GasMeter()
|
||||
remaining := (meter.Limit() - meter.GasConsumed()) * GasMultiplier
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
wasmTypes "github.com/CosmWasm/go-cosmwasm/types"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// ToCosmosMsg encodes an sdk msg using amino json encoding.
|
||||
// Then wraps it as an opaque message
|
||||
func ToCosmosMsg(cdc *codec.Codec, msg sdk.Msg) (wasmTypes.CosmosMsg, error) {
|
||||
opaqueBz, err := cdc.MarshalJSON(msg)
|
||||
if err != nil {
|
||||
return wasmTypes.CosmosMsg{}, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
|
||||
}
|
||||
res := wasmTypes.CosmosMsg{
|
||||
Opaque: &wasmTypes.OpaqueMsg{
|
||||
Data: opaqueBz,
|
||||
},
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// ParseOpaqueMsg decodes msg.Data to an sdk.Msg using amino json encoding.
|
||||
func ParseOpaqueMsg(cdc *codec.Codec, msg *wasmTypes.OpaqueMsg) (sdk.Msg, error) {
|
||||
// until more is changes, format is amino json encoding, wrapped base64
|
||||
var sdkmsg sdk.Msg
|
||||
err := cdc.UnmarshalJSON(msg.Data, &sdkmsg)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
|
||||
}
|
||||
return sdkmsg, nil
|
||||
}
|
||||
27
x/wasm/internal/keeper/query_plugins.go
Normal file
27
x/wasm/internal/keeper/query_plugins.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
wasmTypes "github.com/CosmWasm/go-cosmwasm/types"
|
||||
)
|
||||
|
||||
// TODO: make this something besides failure
|
||||
// Give it sub-queriers
|
||||
type QueryHandler struct{}
|
||||
|
||||
var _ wasmTypes.Querier = QueryHandler{}
|
||||
|
||||
func (q QueryHandler) Query(request wasmTypes.QueryRequest) ([]byte, error) {
|
||||
//if request.Bank != nil {
|
||||
// return q.Bank.Query(request.Bank)
|
||||
//}
|
||||
//if request.Custom != nil {
|
||||
// return q.Custom.Query(request.Custom)
|
||||
//}
|
||||
//if request.Staking != nil {
|
||||
// return nil, wasmTypes.UnsupportedRequest{"staking"}
|
||||
//}
|
||||
//if request.Wasm != nil {
|
||||
// return nil, wasmTypes.UnsupportedRequest{"wasm"}
|
||||
//}
|
||||
return nil, wasmTypes.Unknown{}
|
||||
}
|
||||
@@ -31,4 +31,7 @@ var (
|
||||
|
||||
// ErrQueryFailed error for rust smart query contract failure
|
||||
ErrQueryFailed = sdkErrors.Register(DefaultCodespace, 8, "query wasm contract failed")
|
||||
|
||||
// ErrInvalidMsg error when we cannot process the error returned from the contract
|
||||
ErrInvalidMsg = sdkErrors.Register(DefaultCodespace, 9, "invalid CosmosMsg from the contract")
|
||||
)
|
||||
|
||||
@@ -103,12 +103,11 @@ func NewParams(ctx sdk.Context, creator sdk.AccAddress, deposit sdk.Coins, contr
|
||||
ChainID: ctx.ChainID(),
|
||||
},
|
||||
Message: wasmTypes.MessageInfo{
|
||||
Signer: wasmTypes.CanonicalAddress(creator),
|
||||
Sender: wasmTypes.CanonicalAddress(creator),
|
||||
SentFunds: NewWasmCoins(deposit),
|
||||
},
|
||||
Contract: wasmTypes.ContractInfo{
|
||||
Address: wasmTypes.CanonicalAddress(contractAcct.GetAddress()),
|
||||
Balance: NewWasmCoins(contractAcct.GetCoins()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user