diff --git a/packages/cosmic-swingset/x/swingset/alias.go b/packages/cosmic-swingset/x/swingset/alias.go index 9f268180d5e..a9380529ac1 100644 --- a/packages/cosmic-swingset/x/swingset/alias.go +++ b/packages/cosmic-swingset/x/swingset/alias.go @@ -15,6 +15,7 @@ var ( NewKeeper = keeper.NewKeeper NewQuerier = keeper.NewQuerier NewMsgDeliverInbound = types.NewMsgDeliverInbound + NewMsgProvision = types.NewMsgProvision NewMsgSendPacket = types.NewMsgSendPacket NewStorage = types.NewStorage NewMailbox = types.NewMailbox @@ -26,6 +27,7 @@ var ( type ( Keeper = keeper.Keeper MsgDeliverInbound = types.MsgDeliverInbound + MsgProvision = types.MsgProvision MsgSendPacket = types.MsgSendPacket QueryResStorage = types.QueryResStorage QueryResKeys = types.QueryResKeys diff --git a/packages/cosmic-swingset/x/swingset/client/cli/tx.go b/packages/cosmic-swingset/x/swingset/client/cli/tx.go index d31caa180e7..942e4ea148d 100644 --- a/packages/cosmic-swingset/x/swingset/client/cli/tx.go +++ b/packages/cosmic-swingset/x/swingset/client/cli/tx.go @@ -29,6 +29,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { swingsetTxCmd.AddCommand(flags.PostCommands( GetCmdDeliver(cdc), + GetCmdProvisionOne(cdc), )...) return swingsetTxCmd @@ -77,3 +78,30 @@ func GetCmdDeliver(cdc *codec.Codec) *cobra.Command { }, } } + +// GetCmdProvision is the CLI command for sending a Provision transaction +func GetCmdProvisionOne(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "provision-one [nickname] [address]", + Short: "provision a single address", + Args: cobra.ExactArgs(2), + + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) + + addr, err := sdk.AccAddressFromBech32(args[1]) + if err != nil { + return err + } + msg := types.NewMsgProvision(args[0], addr, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } +} diff --git a/packages/cosmic-swingset/x/swingset/handler.go b/packages/cosmic-swingset/x/swingset/handler.go index 7732418b88c..c35f51e78c8 100644 --- a/packages/cosmic-swingset/x/swingset/handler.go +++ b/packages/cosmic-swingset/x/swingset/handler.go @@ -34,6 +34,9 @@ func NewHandler(keeper Keeper) sdk.Handler { case MsgSendPacket: return handleMsgSendPacket(ctx, keeper, msg) + case MsgProvision: + return handleMsgProvision(ctx, keeper, msg) + default: errMsg := fmt.Sprintf("Unrecognized swingset Msg type: %v", msg.Type()) return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg) @@ -113,3 +116,33 @@ func handleMsgSendPacket(ctx sdk.Context, keeper Keeper, msg MsgSendPacket) (*sd Events: ctx.EventManager().Events().ToABCIEvents(), }, nil } + +type provisionAction struct { + MsgProvision + Type string `json:"type"` // IBC_EVENT + BlockHeight int64 `json:"blockHeight"` + BlockTime int64 `json:"blockTime"` +} + +func handleMsgProvision(ctx sdk.Context, keeper Keeper, msg MsgProvision) (*sdk.Result, error) { + action := &provisionAction{ + MsgProvision: msg, + Type: "PLEASE_PROVISION", + BlockHeight: ctx.BlockHeight(), + BlockTime: ctx.BlockTime().Unix(), + } + // fmt.Fprintf(os.Stderr, "Context is %+v\n", ctx) + b, err := json.Marshal(action) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + + _, err = keeper.CallToController(ctx, string(b)) + // fmt.Fprintln(os.Stderr, "Returned from SwingSet", out, err) + if err != nil { + return nil, err + } + return &sdk.Result{ + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} diff --git a/packages/cosmic-swingset/x/swingset/internal/types/codec.go b/packages/cosmic-swingset/x/swingset/internal/types/codec.go index b6927eeea34..1a2217fcb46 100644 --- a/packages/cosmic-swingset/x/swingset/internal/types/codec.go +++ b/packages/cosmic-swingset/x/swingset/internal/types/codec.go @@ -10,5 +10,6 @@ var ModuleCdc *codec.Codec func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgDeliverInbound{}, "swingset/DeliverInbound", nil) cdc.RegisterConcrete(MsgSendPacket{}, "swingset/SendPacket", nil) + cdc.RegisterConcrete(MsgProvision{}, "swingset/Provision", nil) ModuleCdc = cdc } diff --git a/packages/cosmic-swingset/x/swingset/internal/types/msgs.go b/packages/cosmic-swingset/x/swingset/internal/types/msgs.go index c8a1925e75d..189cf24d3d1 100644 --- a/packages/cosmic-swingset/x/swingset/internal/types/msgs.go +++ b/packages/cosmic-swingset/x/swingset/internal/types/msgs.go @@ -120,3 +120,53 @@ func (msg MsgSendPacket) GetSigners() []sdk.AccAddress { func (msg MsgSendPacket) Type() string { return "sendpacket" } + +// MsgProvision defines a Provision message +type MsgProvision struct { + Nickname string `json:"nickname" yaml:"nickname"` + Address sdk.AccAddress `json:"address" yaml:"address"` + Submitter sdk.AccAddress `json:"submitter" yaml:"submitter"` +} + +var _ sdk.Msg = &MsgProvision{} + +func NewMsgProvision(nickname string, addr sdk.AccAddress, submitter sdk.AccAddress) MsgProvision { + return MsgProvision{ + Nickname: nickname, + Address: addr, + Submitter: submitter, + } +} + +// Route should return the name of the module +func (msg MsgProvision) Route() string { return RouterKey } + +// Type should return the action +func (msg MsgProvision) Type() string { return "provision" } + +// ValidateBasic runs stateless checks on the message +func (msg MsgProvision) ValidateBasic() error { + if msg.Submitter.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Submitter.String()) + } + if msg.Address.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Address.String()) + } + if len(msg.Nickname) == 0 { + return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "Nickname cannot be empty") + } + if msg.Address.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Address.String()) + } + return nil +} + +// GetSignBytes encodes the message for signing +func (msg MsgProvision) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners defines whose signature is required +func (msg MsgProvision) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Submitter} +}