Allow contracts to dispatch contract messages

This commit is contained in:
Ethan Frey
2020-05-06 17:21:59 +02:00
parent 77d1ea4c22
commit ffcab2176a
4 changed files with 85 additions and 20 deletions

View File

@@ -16,10 +16,10 @@ type MessageHandler struct {
}
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)
Bank func(sender sdk.AccAddress, msg *wasmTypes.BankMsg) (sdk.Msg, error)
Custom func(sender sdk.AccAddress, msg json.RawMessage) (sdk.Msg, error)
Staking func(sender sdk.AccAddress, msg *wasmTypes.StakingMsg) (sdk.Msg, error)
Wasm func(sender sdk.AccAddress, msg *wasmTypes.WasmMsg) (sdk.Msg, error)
}
func DefaultEncoders() MessageEncoders {
@@ -31,7 +31,7 @@ func DefaultEncoders() MessageEncoders {
}
}
func EncodeBankMsg(msg *wasmTypes.BankMsg) (sdk.Msg, error) {
func EncodeBankMsg(sender sdk.AccAddress, msg *wasmTypes.BankMsg) (sdk.Msg, error) {
if msg.Send == nil {
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Unknown variant of Bank")
}
@@ -58,19 +58,39 @@ func EncodeBankMsg(msg *wasmTypes.BankMsg) (sdk.Msg, error) {
return sendMsg, nil
}
func NoCustomMsg(msg json.RawMessage) (sdk.Msg, error) {
func NoCustomMsg(sender sdk.AccAddress, msg json.RawMessage) (sdk.Msg, error) {
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Custom variant not supported")
}
func EncodeStakingMsg(msg *wasmTypes.StakingMsg) (sdk.Msg, error) {
func EncodeStakingMsg(sender sdk.AccAddress, msg *wasmTypes.StakingMsg) (sdk.Msg, error) {
// TODO
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Staking variant not supported")
}
func EncodeWasmMsg(msg *wasmTypes.WasmMsg) (sdk.Msg, error) {
// TODO
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Wasm variant not supported")
// } else if msg.Contract != nil {
func EncodeWasmMsg(sender sdk.AccAddress, msg *wasmTypes.WasmMsg) (sdk.Msg, error) {
if msg.Execute != nil {
contractAddr, err := sdk.AccAddressFromBech32(msg.Execute.ContractAddr)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Execute.ContractAddr)
}
coins, err := convertWasmCoinToSdkCoin(msg.Execute.Send)
if err != nil {
return nil, err
}
sdkMsg := types.MsgExecuteContract{
Sender: sender,
Contract: contractAddr,
Msg: msg.Execute.Msg,
SentFunds: coins,
}
return sdkMsg, nil
}
if msg.Instantiate != nil {
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Wasm.Instantiate variant not supported")
}
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Unknown variant of Wasm")
//lse if msg.Contract != nil {
// targetAddr, stderr := sdk.AccAddressFromBech32(msg.Contract.ContractAddr)
// if stderr != nil {
// return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Contract.ContractAddr)
@@ -91,13 +111,13 @@ func (h MessageHandler) Dispatch(ctx sdk.Context, contract exported.Account, msg
var err error
switch {
case msg.Bank != nil:
sdkMsg, err = h.encoders.Bank(msg.Bank)
sdkMsg, err = h.encoders.Bank(contractAddr, msg.Bank)
case msg.Custom != nil:
sdkMsg, err = h.encoders.Custom(msg.Custom)
sdkMsg, err = h.encoders.Custom(contractAddr, msg.Custom)
case msg.Staking != nil:
sdkMsg, err = h.encoders.Staking(msg.Staking)
sdkMsg, err = h.encoders.Staking(contractAddr, msg.Staking)
case msg.Wasm != nil:
sdkMsg, err = h.encoders.Wasm(msg.Wasm)
sdkMsg, err = h.encoders.Wasm(contractAddr, msg.Wasm)
}
if err != nil {
return err

View File

@@ -349,8 +349,6 @@ func TestExecuteWithPanic(t *testing.T) {
}
func TestExecuteWithCpuLoop(t *testing.T) {
// TODO
t.Skip("out of gas error not thrown")
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)

View File

@@ -167,8 +167,6 @@ func fromMaskRawMsg(cdc *codec.Codec, msg json.RawMessage) (sdk.Msg, error) {
}
func TestMaskReflectContractSend(t *testing.T) {
// TODO
t.Skip("this causes a panic in the rust code!")
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)

View File

@@ -1,6 +1,7 @@
package keeper
import (
"fmt"
"testing"
"time"
@@ -8,6 +9,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/params"
@@ -74,7 +76,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, tempDir string) (sdk.Context,
)
bk.SetSendEnabled(ctx, true)
// TODO: register more than bank.send
// TODO: register slashing (and more?)
router := baseapp.NewRouter()
h := bank.NewHandler(bk)
router.AddRoute(bank.RouterKey, h)
@@ -83,6 +85,53 @@ func CreateTestInput(t *testing.T, isCheckTx bool, tempDir string) (sdk.Context,
wasmConfig := wasmTypes.DefaultWasmConfig()
keeper := NewKeeper(cdc, keyContract, accountKeeper, bk, router, tempDir, wasmConfig)
// add wasm handler so we can loop-back (contracts calling contracts)
router.AddRoute(wasmTypes.RouterKey, TestHandler(keeper))
return ctx, accountKeeper, keeper
}
// TestHandler returns a wasm handler for tests (to avoid circular imports)
func TestHandler(k Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
switch msg := msg.(type) {
case wasmTypes.MsgInstantiateContract:
return handleInstantiate(ctx, k, &msg)
case *wasmTypes.MsgInstantiateContract:
return handleInstantiate(ctx, k, msg)
case wasmTypes.MsgExecuteContract:
return handleExecute(ctx, k, &msg)
case *wasmTypes.MsgExecuteContract:
return handleExecute(ctx, k, msg)
default:
errMsg := fmt.Sprintf("unrecognized wasm message type: %T", msg)
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg)
}
}
}
func handleInstantiate(ctx sdk.Context, k Keeper, msg *wasmTypes.MsgInstantiateContract) (*sdk.Result, error) {
contractAddr, err := k.Instantiate(ctx, msg.Code, msg.Sender, msg.InitMsg, msg.Label, msg.InitFunds)
if err != nil {
return nil, err
}
return &sdk.Result{
Data: contractAddr,
Events: ctx.EventManager().Events(),
}, nil
}
func handleExecute(ctx sdk.Context, k Keeper, msg *wasmTypes.MsgExecuteContract) (*sdk.Result, error) {
res, err := k.Execute(ctx, msg.Contract, msg.Sender, msg.Msg, msg.SentFunds)
if err != nil {
return nil, err
}
res.Events = ctx.EventManager().Events()
return &res, nil
}