From c2680882609196cf7eeafb96331b6feda455bd62 Mon Sep 17 00:00:00 2001 From: rhuairahrighairigh Date: Mon, 27 Aug 2018 23:48:48 -0400 Subject: [PATCH] add error handling and fix compile errors --- internal/x/paychan/README.md | 5 +- internal/x/paychan/endblocker.go | 24 ++++- internal/x/paychan/handler.go | 14 ++- internal/x/paychan/keeper.go | 158 ++++++++++++++++++------------ internal/x/paychan/keeper_test.go | 2 + internal/x/paychan/types.go | 142 +++++++++++++-------------- internal/x/paychan/wire.go | 4 +- 7 files changed, 200 insertions(+), 149 deletions(-) diff --git a/internal/x/paychan/README.md b/internal/x/paychan/README.md index 45222831..d85b83b7 100644 --- a/internal/x/paychan/README.md +++ b/internal/x/paychan/README.md @@ -7,7 +7,10 @@ Simplifications: TODO - - error handling (getter setter return values? and what happens in failures) - chnge module name to "channel"? - Find a better name for Queue - clarify distinction between int slice and abstract queue concept - Do all the small functions need to be methods on the keeper or can they just be floating around? + - Tidy up - standardise var names, comments and method descriptions + - is having all the get functions return a bool if not found reasonable? + - any problem in signing your own address? + - Gas diff --git a/internal/x/paychan/endblocker.go b/internal/x/paychan/endblocker.go index 74947561..cb793d2a 100644 --- a/internal/x/paychan/endblocker.go +++ b/internal/x/paychan/endblocker.go @@ -1,22 +1,36 @@ package paychan -import () +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) func EndBlocker(ctx sdk.Context, k Keeper) sdk.Tags { + var err sdk.Error + var channelTags sdk.Tags + tags := sdk.EmptyTags() // Iterate through submittedUpdatesQueue // TODO optimise so it doesn't pull every update from DB every block var sUpdate SubmittedUpdate - q := k.getSubmittedUpdatesQueue(ctx) + q, found := k.getSubmittedUpdatesQueue(ctx) + if !found { + panic("SubmittedUpdatesQueue not found.") + } for _, id := range q { // close the channel if the update has reached its execution time. // Using >= in case some are somehow missed. - sUpdate = k.getSubmittedUpdate(ctx, id) + sUpdate, found = k.getSubmittedUpdate(ctx, id) + if !found { + panic("can't find element in queue that should exist") + } if ctx.BlockHeight() >= sUpdate.ExecutionTime { - k.closeChannel(ctx, sUpdate.Update) + channelTags, err = k.closeChannel(ctx, sUpdate.Update) + if err != nil { + panic(err) + } + tags.AppendTags(channelTags) } } - tags := sdk.NewTags() return tags } diff --git a/internal/x/paychan/handler.go b/internal/x/paychan/handler.go index d442f7c1..c4d949a8 100644 --- a/internal/x/paychan/handler.go +++ b/internal/x/paychan/handler.go @@ -37,15 +37,19 @@ func handleMsgCreate(ctx sdk.Context, k Keeper, msg MsgCreate) sdk.Result { // Handle MsgSubmitUpdate // Leaves validation to the keeper methods. func handleMsgSubmitUpdate(ctx sdk.Context, k Keeper, msg MsgSubmitUpdate) sdk.Result { + var err sdk.Error + tags := sdk.EmptyTags() - participants := k.getChannel(ctx, msg.Update.ChannelID).Participants + // TODO refactor signer detection - move to keeper or find nicer setup + channel, _ := k.getChannel(ctx, msg.Update.ChannelID) + participants := channel.Participants // if only sender signed - if msg.submitter == participants[0] { - tags, err := k.InitCloseChannelBySender() + if reflect.DeepEqual(msg.submitter, participants[0]) { + tags, err = k.InitCloseChannelBySender(ctx, msg.Update) // else if receiver signed - } else if msg.submitter == participants[len(participants)-1] { - tags, err := k.CloseChannelByReceiver() + } else if reflect.DeepEqual(msg.submitter, participants[len(participants)-1]) { + tags, err = k.CloseChannelByReceiver(ctx, msg.Update) } if err != nil { diff --git a/internal/x/paychan/keeper.go b/internal/x/paychan/keeper.go index dfcf99c6..7bab151e 100644 --- a/internal/x/paychan/keeper.go +++ b/internal/x/paychan/keeper.go @@ -1,8 +1,7 @@ package paychan import ( - "strconv" - + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/bank" @@ -33,9 +32,8 @@ func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, ck bank.Keeper) Keeper { // ============================================== Main Business Logic - // Create a new payment channel and lock up sender funds. -func (k Keeper) CreateChannel(ctx sdk.Context, sender sdk.Address, receiver sdk.Address, coins sdk.Coins) (sdk.Tags, sdk.Error) { +func (k Keeper) CreateChannel(ctx sdk.Context, sender sdk.AccAddress, receiver sdk.AccAddress, coins sdk.Coins) (sdk.Tags, sdk.Error) { // TODO do validation and maybe move somewhere nicer /* // args present @@ -67,18 +65,18 @@ func (k Keeper) CreateChannel(ctx sdk.Context, sender sdk.Address, receiver sdk. // TODO check if sender and receiver different? */ - // Calculate next id - id := k.getNewChannelID(ctx) // subtract coins from sender _, tags, err := k.coinKeeper.SubtractCoins(ctx, sender, coins) if err != nil { return nil, err } + // Calculate next id + id := k.getNewChannelID(ctx) // create new Paychan struct channel := Channel{ - ID: id - Participants: [2]sdk.AccAddress{sender, receiver}, - Coins: coins, + ID: id, + Participants: [2]sdk.AccAddress{sender, receiver}, + Coins: coins, } // save to db k.setChannel(ctx, channel) @@ -88,51 +86,64 @@ func (k Keeper) CreateChannel(ctx sdk.Context, sender sdk.Address, receiver sdk. return tags, err } - - -func (k Keeper) InitCloseChannelBySender(update Update) { +func (k Keeper) InitCloseChannelBySender(ctx sdk.Context, update Update) (sdk.Tags, sdk.Error) { // This is roughly the default path for non unidirectional channels // TODO Validate update - e.g. check signed by sender - q := k.getSubmittedUpdateQueue(ctx) + q, found := k.getSubmittedUpdatesQueue(ctx) + if !found { + panic("SubmittedUpdatesQueue not found.") // TODO nicer custom errors + } if q.Contains(update.ChannelID) { // Someone has previously tried to update channel - existingSUpdate := k.getSubmittedUpdate(ctx, update.ChannelID) - k.addToSubmittedUpdateQueue(ctx, k.applyNewUpdate(existingSUpdate, update)) - } else { - // No one has tried to update channel. - submittedUpdate := SubmittedUpdate{ - Update: update - executionTime: ctx.BlockHeight()+ChannelDisputeTime //TODO check what exactly BlockHeight refers to + existingSUpdate, found := k.getSubmittedUpdate(ctx, update.ChannelID) + if !found { + panic("can't find element in queue that should exist") } - k.addToSubmittedUpdateQueue(ctx, submittedUpdate) + k.addToSubmittedUpdatesQueue(ctx, k.applyNewUpdate(existingSUpdate, update)) + } else { + // No one has tried to update channel + submittedUpdate := SubmittedUpdate{ + Update: update, + ExecutionTime: ctx.BlockHeight() + ChannelDisputeTime, //TODO check what exactly BlockHeight refers to + } + k.addToSubmittedUpdatesQueue(ctx, submittedUpdate) } + + tags := sdk.EmptyTags() // TODO tags + + return tags, nil } -func (k Keeper) CloseChannelByReceiver(update Update) () { +func (k Keeper) CloseChannelByReceiver(ctx sdk.Context, update Update) (sdk.Tags, sdk.Error) { // TODO Validate update // Check if there is an update in the queue already - q := k.getSubmittedUpdateQueue(ctx) + q, found := k.getSubmittedUpdatesQueue(ctx) + if !found { + panic("SubmittedUpdatesQueue not found.") // TODO nicer custom errors + } if q.Contains(update.ChannelID) { // Someone has previously tried to update channel but receiver has final say - k.removeFromSubmittedUpdateQueue(ctx, update.ChannelID) + k.removeFromSubmittedUpdatesQueue(ctx, update.ChannelID) } - - k.closeChannel(ctx, update) + + tags, err := k.closeChannel(ctx, update) + + return tags, err } // Main function that compare updates against each other. // Pure function -func (k Keeper) applyNewUpdate(existingSUpdate, proposedUpdate) SubmittedUpdate { +func (k Keeper) applyNewUpdate(existingSUpdate SubmittedUpdate, proposedUpdate Update) SubmittedUpdate { var returnUpdate SubmittedUpdate - if existingSUpdate.sequence > proposedUpdate.sequence { + if existingSUpdate.Sequence > proposedUpdate.Sequence { // update accepted returnUpdate = SubmittedUpdate{ - Update: proposedUpdate - ExecutionTime: existingSUpdate.ExecutionTime + Update: proposedUpdate, + ExecutionTime: existingSUpdate.ExecutionTime, } } else { // update rejected @@ -141,62 +152,79 @@ func (k Keeper) applyNewUpdate(existingSUpdate, proposedUpdate) SubmittedUpdate return returnUpdate } -func (k Keeper) closeChannel(ctx sdk.Context, update Update) { - channel := k.getChannel(ctx, update.ChannelID) +// unsafe close channel - doesn't check if update matches existing channel TODO make safer? +func (k Keeper) closeChannel(ctx sdk.Context, update Update) (sdk.Tags, sdk.Error) { + var err error + var sdkErr sdk.Error + var tags sdk.Tags // Add coins to sender and receiver - for address, coins := range update.CoinsUpdate { + // TODO check for possible errors first to avoid coins being half paid out? + var address sdk.AccAddress + for bech32Address, coins := range update.CoinsUpdate { + address, err = sdk.AccAddressFromBech32(bech32Address) + if err != nil { + panic(err) + } // TODO check somewhere if coins are not negative? - k.ck.AddCoins(ctx, address, coins) + _, tags, sdkErr = k.coinKeeper.AddCoins(ctx, address, coins) + if sdkErr != nil { + panic(sdkErr) + } } - + k.deleteChannel(ctx, update.ChannelID) + + return tags, nil } - - // =========================================== QUEUE - func (k Keeper) addToSubmittedUpdatesQueue(ctx sdk.Context, sUpdate SubmittedUpdate) { // always overwrite prexisting values - leave paychan logic to higher levels // get current queue - q := k.getSubmittedUpdateQueue(ctx) + q, found := k.getSubmittedUpdatesQueue(ctx) + if !found { + panic("SubmittedUpdatesQueue not found.") + } // append ID to queue - if q.Contains(sUpdate.ChannelID)! { + if !q.Contains(sUpdate.ChannelID) { q = append(q, sUpdate.ChannelID) } // set queue - k.setSubmittedUpdateQueue(ctx, q) + k.setSubmittedUpdatesQueue(ctx, q) // store submittedUpdate k.setSubmittedUpdate(ctx, sUpdate) } -func (k Keeper) removeFromSubmittdUpdatesQueue(ctx sdk.Context, channelID) { +func (k Keeper) removeFromSubmittedUpdatesQueue(ctx sdk.Context, channelID ChannelID) { // get current queue - q := k.getSubmittedUpdateQueue(ctx) + q, found := k.getSubmittedUpdatesQueue(ctx) + if !found { + panic("SubmittedUpdatesQueue not found.") + } // remove id q.RemoveMatchingElements(channelID) // set queue - k.setSubmittedUpdateQueue(ctx, q) + k.setSubmittedUpdatesQueue(ctx, q) // delete submittedUpdate k.deleteSubmittedUpdate(ctx, channelID) } -func (k Keeper) getSubmittedUpdatesQueue(ctx sdk.Context) (Queue, bool) { +func (k Keeper) getSubmittedUpdatesQueue(ctx sdk.Context) (SubmittedUpdatesQueue, bool) { // load from DB store := ctx.KVStore(k.storeKey) bz := store.Get(k.getSubmittedUpdatesQueueKey()) - var q Queue + var suq SubmittedUpdatesQueue if bz == nil { - return q, false + return suq, false // TODO maybe create custom error to pass up here } // unmarshal - k.cdc.MustUnmarshalBinary(bz, &q) + k.cdc.MustUnmarshalBinary(bz, &suq) // return - return q, true + return suq, true } -func (k Keeper) setSubmittedUpdatesQueue(ctx sdk.Context, q Queue) { +func (k Keeper) setSubmittedUpdatesQueue(ctx sdk.Context, q SubmittedUpdatesQueue) { store := ctx.KVStore(k.storeKey) // marshal bz := k.cdc.MustMarshalBinary(q) @@ -213,7 +241,7 @@ func (k Keeper) getSubmittedUpdatesQueueKey() []byte { // This section deals with only setting and getting func (k Keeper) getSubmittedUpdate(ctx sdk.Context, channelID ChannelID) (SubmittedUpdate, bool) { - + // load from DB store := ctx.KVStore(k.storeKey) bz := store.Get(k.getSubmittedUpdateKey(channelID)) @@ -234,11 +262,11 @@ func (k Keeper) setSubmittedUpdate(ctx sdk.Context, sUpdate SubmittedUpdate) { // marshal bz := k.cdc.MustMarshalBinary(sUpdate) // panics if something goes wrong // write to db - key := k.getSubmittedUpdateKey(sUpdate.channelID) + key := k.getSubmittedUpdateKey(sUpdate.ChannelID) store.Set(key, bz) // panics if something goes wrong } -func (k Keeper) deleteSubmittedUpdate(ctx sdk.Context, channelID ) { +func (k Keeper) deleteSubmittedUpdate(ctx sdk.Context, channelID ChannelID) { store := ctx.KVStore(k.storeKey) store.Delete(k.getSubmittedUpdateKey(channelID)) // TODO does this have return values? What happens when key doesn't exist? @@ -247,12 +275,10 @@ func (k Keeper) getSubmittedUpdateKey(channelID ChannelID) []byte { return []byte(fmt.Sprintf("submittedUpdate:%d", channelID)) } - // ========================================== CHANNELS // Reteive a payment channel struct from the blockchain store. func (k Keeper) getChannel(ctx sdk.Context, channelID ChannelID) (Channel, bool) { - // load from DB store := ctx.KVStore(k.storeKey) bz := store.Get(k.getChannelKey(channelID)) @@ -273,27 +299,28 @@ func (k Keeper) setChannel(ctx sdk.Context, channel Channel) { // marshal bz := k.cdc.MustMarshalBinary(channel) // panics if something goes wrong // write to db - key := sdk.getChannelKey(channel.ID) + key := k.getChannelKey(channel.ID) store.Set(key, bz) // panics if something goes wrong } -func (k Keeper) deleteChannel(ctx sdk.Context, channelID ) { +func (k Keeper) deleteChannel(ctx sdk.Context, channelID ChannelID) { store := ctx.KVStore(k.storeKey) store.Delete(k.getChannelKey(channelID)) // TODO does this have return values? What happens when key doesn't exist? } -func (k Keeper) getNewChannelID(ctx sdk.Context) (int64, error) { +func (k Keeper) getNewChannelID(ctx sdk.Context) ChannelID { // get last channel ID - store := k.KVStore(k.storeKey) + var lastID ChannelID + store := ctx.KVStore(k.storeKey) bz := store.Get(k.getLastChannelIDKey()) if bz == nil { - return nil, // TODO throw some error (assumes this has been initialized elsewhere) or just set to zero here + lastID = -1 // TODO is just setting to zero if uninitialized ok? + } else { + k.cdc.MustUnmarshalBinary(bz, &lastID) } - var lastID ChannelID - k.cdc.MustUnmarshalBinary(bz, &lastID) // increment to create new one - newID := lastID+1 + newID := lastID + 1 bz = k.cdc.MustMarshalBinary(newID) // set last channel id again store.Set(k.getLastChannelIDKey(), bz) @@ -302,11 +329,12 @@ func (k Keeper) getNewChannelID(ctx sdk.Context) (int64, error) { } func (k Keeper) getChannelKey(channelID ChannelID) []byte { - return []bytes(fmt.Sprintf("channel:%d", channelID)) + return []byte(fmt.Sprintf("channel:%d", channelID)) } func (k Keeper) getLastChannelIDKey() []byte { - return []bytes("lastChannelID") + return []byte("lastChannelID") } + /* // Close a payment channel and distribute funds to participants. func (k Keeper) ClosePaychan(ctx sdk.Context, sender sdk.Address, receiver sdk.Address, id int64, receiverAmount sdk.Coins) (sdk.Tags, sdk.Error) { diff --git a/internal/x/paychan/keeper_test.go b/internal/x/paychan/keeper_test.go index 8ba25b79..41fa21b4 100644 --- a/internal/x/paychan/keeper_test.go +++ b/internal/x/paychan/keeper_test.go @@ -1,5 +1,6 @@ package paychan +/* import ( "testing" //"github.com/stretchr/testify/assert" @@ -139,3 +140,4 @@ func TestKeeper(t *testing.T) { } } +*/ diff --git a/internal/x/paychan/types.go b/internal/x/paychan/types.go index 2b532c74..68531b9c 100644 --- a/internal/x/paychan/types.go +++ b/internal/x/paychan/types.go @@ -2,7 +2,7 @@ package paychan import ( sdk "github.com/cosmos/cosmos-sdk/types" - "strconv" + "github.com/tendermint/tendermint/crypto" ) /* CHANNEL TYPES */ @@ -11,32 +11,35 @@ import ( // Participants is limited to two as currently these are unidirectional channels. // Last participant is designated as receiver. type Channel struct { - ID ChannelID - Participants [2]sdk.AccAddress - Coins sdk.Coins + ID ChannelID + Participants [2]sdk.AccAddress // [senderAddr, receiverAddr] + Coins sdk.Coins } type ChannelID int64 // TODO should this be positive only // The data that is passed between participants as payments, and submitted to the blockchain to close a channel. type Update struct { - ChannelID int64 - CoinsUpdate map[sdk.AccAddress]sdk.Coins - Sequence int64 - sig // TODO type, only sender needs to sign + ChannelID ChannelID + CoinsUpdate map[string]sdk.Coins // map of bech32 addresses to coins + Sequence int64 + Sigs [1]{crypto.Signature} // only sender needs to sign } +var ChannelDisputeTime = int64(2000) // measured in blocks TODO pick reasonable time + // An update that has been submitted to the blockchain, but not yet acted on. -type SubmittedUpdate { +type SubmittedUpdate struct { Update - executionTime int64 // BlockHeight + ExecutionTime int64 // BlockHeight } -type SubmittedUpdateQueue []ChannelID +type SubmittedUpdatesQueue []ChannelID + // Check if value is in queue -func (suq SubmittedChannelID) Contains(channelID ChannelID) bool { +func (suq SubmittedUpdatesQueue) Contains(channelID ChannelID) bool { found := false - for _, id := range(suq) { + for _, id := range suq { if id == channelID { found = true break @@ -44,11 +47,12 @@ func (suq SubmittedChannelID) Contains(channelID ChannelID) bool { } return found } -// Remove all values from queue that match argument -func (suq SubmittedUpdateQueue) RemoveMatchingElements(channelID ChannelID) { - newSUQ := SubmittedUpdateQueue{} - for _, id := range(suq) { +// Remove all values from queue that match argument +func (suq SubmittedUpdatesQueue) RemoveMatchingElements(channelID ChannelID) { + newSUQ := SubmittedUpdatesQueue{} + + for _, id := range suq { if id != channelID { newSUQ = append(newSUQ, id) } @@ -56,8 +60,6 @@ func (suq SubmittedUpdateQueue) RemoveMatchingElements(channelID ChannelID) { suq = newSUQ } -var ChannelDisputeTime = 2000 // measured in blocks - /* MESSAGE TYPES */ /* Message implement the sdk.Msg interface: @@ -77,14 +79,14 @@ type Msg interface { // Signers returns the addrs of signers that must sign. // CONTRACT: All signatures must be present to be valid. // CONTRACT: Returns addrs in some deterministic order. - GetSigners() []Address + GetSigners() []AccAddress } */ // A message to create a payment channel. type MsgCreate struct { - Participants [2]sdk.AccAddress - Coins sdk.Coins + Participants [2]sdk.AccAddress + Coins sdk.Coins } //Create a new message. @@ -103,12 +105,11 @@ func (msg CreatMsg) NewMsgCreate(sender sdk.Address, receiver sdk.Address, amoun func (msg MsgCreate) Type() string { return "paychan" } func (msg MsgCreate) GetSignBytes() []byte { - // TODO create msgCdc in wire.go - bz, err := msgCdc.Marshal(msg) + bz, err := msgCdc.MarshalJSON(msg) if err != nil { panic(err) } - return MustSortJSON(bz) + return sdk.MustSortJSON(bz) } func (msg MsgCreate) ValidateBasic() sdk.Error { @@ -118,29 +119,29 @@ func (msg MsgCreate) ValidateBasic() sdk.Error { //TODO implement /* - // check if all fields present / not 0 valued - if len(msg.Sender) == 0 { - return sdk.ErrInvalidAddress(msg.Sender.String()) - } - if len(msg.Receiver) == 0 { - return sdk.ErrInvalidAddress(msg.Receiver.String()) - } - if len(msg.Amount) == 0 { - return sdk.ErrInvalidCoins(msg.Amount.String()) - } - // Check if coins are sorted, non zero, non negative - if !msg.Amount.IsValid() { - return sdk.ErrInvalidCoins(msg.Amount.String()) - } - if !msg.Amount.IsPositive() { - return sdk.ErrInvalidCoins(msg.Amount.String()) - } - // TODO check if Address valid? + // check if all fields present / not 0 valued + if len(msg.Sender) == 0 { + return sdk.ErrInvalidAddress(msg.Sender.String()) + } + if len(msg.Receiver) == 0 { + return sdk.ErrInvalidAddress(msg.Receiver.String()) + } + if len(msg.Amount) == 0 { + return sdk.ErrInvalidCoins(msg.Amount.String()) + } + // Check if coins are sorted, non zero, non negative + if !msg.Amount.IsValid() { + return sdk.ErrInvalidCoins(msg.Amount.String()) + } + if !msg.Amount.IsPositive() { + return sdk.ErrInvalidCoins(msg.Amount.String()) + } + // TODO check if Address valid? */ return nil } -func (msg MsgCreate) GetSigners() []sdk.Address { +func (msg MsgCreate) GetSigners() []sdk.AccAddress { // Only sender must sign to create a paychan return []sdk.AccAddress{msg.Participants[0]} // select sender address } @@ -160,46 +161,45 @@ type MsgSubmitUpdate struct { func (msg MsgSubmitUpdate) Type() string { return "paychan" } func (msg MsgSubmitUpdate) GetSignBytes() []byte { - // TODO create msgCdc in wire.go - bz, err := msgCdc.Marshal(msg) + bz, err := msgCdc.MarshalJSON(msg) if err != nil { panic(err) } - return MustSortJSON(bz) + return sdk.MustSortJSON(bz) } func (msg MsgSubmitUpdate) ValidateBasic() sdk.Error { // TODO implement /* - // check if all fields present / not 0 valued - if len(msg.Sender) == 0 { - return sdk.ErrInvalidAddress(msg.Sender.String()) - } - if len(msg.Receiver) == 0 { - return sdk.ErrInvalidAddress(msg.Receiver.String()) - } - if len(msg.ReceiverAmount) == 0 { - return sdk.ErrInvalidCoins(msg.ReceiverAmount.String()) - } - // check id ≥ 0 - if msg.Id < 0 { - return sdk.ErrInvalidAddress(strconv.Itoa(int(msg.Id))) // TODO implement custom errors - } - // Check if coins are sorted, non zero, non negative - if !msg.ReceiverAmount.IsValid() { - return sdk.ErrInvalidCoins(msg.ReceiverAmount.String()) - } - if !msg.ReceiverAmount.IsPositive() { - return sdk.ErrInvalidCoins(msg.ReceiverAmount.String()) - } - // TODO check if Address valid? + // check if all fields present / not 0 valued + if len(msg.Sender) == 0 { + return sdk.ErrInvalidAddress(msg.Sender.String()) + } + if len(msg.Receiver) == 0 { + return sdk.ErrInvalidAddress(msg.Receiver.String()) + } + if len(msg.ReceiverAmount) == 0 { + return sdk.ErrInvalidCoins(msg.ReceiverAmount.String()) + } + // check id ≥ 0 + if msg.Id < 0 { + return sdk.ErrInvalidAddress(strconv.Itoa(int(msg.Id))) // TODO implement custom errors + } + // Check if coins are sorted, non zero, non negative + if !msg.ReceiverAmount.IsValid() { + return sdk.ErrInvalidCoins(msg.ReceiverAmount.String()) + } + if !msg.ReceiverAmount.IsPositive() { + return sdk.ErrInvalidCoins(msg.ReceiverAmount.String()) + } + // TODO check if Address valid? */ return nil } -func (msg MsgSubmitUpdate) GetSigners() []sdk.Address { +func (msg MsgSubmitUpdate) GetSigners() []sdk.AccAddress { // Signing not strictly necessary as signatures contained within the channel update. // TODO add signature by submitting address - return []sdk.Address{} + return []sdk.AccAddress{msg.submitter} } diff --git a/internal/x/paychan/wire.go b/internal/x/paychan/wire.go index 9d9e5eb3..98c7817e 100644 --- a/internal/x/paychan/wire.go +++ b/internal/x/paychan/wire.go @@ -4,14 +4,14 @@ import ( "github.com/cosmos/cosmos-sdk/wire" ) -/* func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(MsgCreate{}, "paychan/MsgCreate", nil) - cdc.RegisterConcrete(MsgClose{}, "paychan/MsgClose", nil) + cdc.RegisterConcrete(MsgSubmitUpdate{}, "paychan/MsgSubmitUpdate", nil) } var msgCdc = wire.NewCodec() +/* func init() { RegisterWire(msgCdc) // TODO is this needed?