From ffcab2176a25d699717ad3459648ded50d48c84a Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 6 May 2020 17:21:59 +0200 Subject: [PATCH] Allow contracts to dispatch contract messages --- x/wasm/internal/keeper/handler_plugin.go | 50 ++++++++++++++++------- x/wasm/internal/keeper/keeper_test.go | 2 - x/wasm/internal/keeper/mask_test.go | 2 - x/wasm/internal/keeper/test_common.go | 51 +++++++++++++++++++++++- 4 files changed, 85 insertions(+), 20 deletions(-) diff --git a/x/wasm/internal/keeper/handler_plugin.go b/x/wasm/internal/keeper/handler_plugin.go index e38311a4..4482527f 100644 --- a/x/wasm/internal/keeper/handler_plugin.go +++ b/x/wasm/internal/keeper/handler_plugin.go @@ -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 diff --git a/x/wasm/internal/keeper/keeper_test.go b/x/wasm/internal/keeper/keeper_test.go index 11592543..e58c8f97 100644 --- a/x/wasm/internal/keeper/keeper_test.go +++ b/x/wasm/internal/keeper/keeper_test.go @@ -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) diff --git a/x/wasm/internal/keeper/mask_test.go b/x/wasm/internal/keeper/mask_test.go index dc2d647b..0b0e45d0 100644 --- a/x/wasm/internal/keeper/mask_test.go +++ b/x/wasm/internal/keeper/mask_test.go @@ -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) diff --git a/x/wasm/internal/keeper/test_common.go b/x/wasm/internal/keeper/test_common.go index ac1ccf03..6fc44e21 100644 --- a/x/wasm/internal/keeper/test_common.go +++ b/x/wasm/internal/keeper/test_common.go @@ -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 +}