diff --git a/internal/x/paychan/README.md b/internal/x/paychan/README.md index 720832e2..463f495c 100644 --- a/internal/x/paychan/README.md +++ b/internal/x/paychan/README.md @@ -2,7 +2,7 @@ This module implements simple but feature complete unidirectional payment channels. Channels can be opened by a sender and closed immediately by the receiver, or by the sender subject to a dispute period. There are no top-ups or partial withdrawals (yet). Channels support multiple currencies. ->Note: This is a work in progress. More feature planned. More test cases needed. +>Note: This module is still a bit rough around the edges. More feature planned. More test cases needed. # Usage @@ -15,7 +15,7 @@ Send a payment for 10 KVA. kvcli paychan pay --from --sen-amt 90KVA --rec-amt 10KVA --chan-id --filename payment.json --chain-id -Send the file payment.json to your receiver. Then they run the following to verify. +Send the file `payment.json` to your receiver. Then they run the following to verify. kvcli paychan verify --filename payment.json @@ -24,14 +24,17 @@ The receiver can close immediately at any time. kvcli paychan submit --from --payment payment.json --chain-id -The sender can close subject to a dispute period during which the receiver can overrule them. +The sender can submit a close request, causing the channel will close automatically after a dispute period. During this period a receiver can still close immediately. kvcli paychan submit --from --payment payment.json --chain-id +>Note: The dispute period on the testnet is 30 seconds for ease of testing. + ## Get info on a channel kvcli get --chan-id +This will print out a channel, if it exists, and any submitted close requests. # TODOs diff --git a/internal/x/paychan/client/cmd/cmd.go b/internal/x/paychan/client/cmd/cmd.go index 12dfd541..c7b8457f 100644 --- a/internal/x/paychan/client/cmd/cmd.go +++ b/internal/x/paychan/client/cmd/cmd.go @@ -264,7 +264,7 @@ func GetChannelCmd(cdc *wire.Codec, paychanStoreName string) *cobra.Command { cmd := &cobra.Command{ Use: "get", Short: "Get info on a channel.", - Long: "Get information on a non closed channel.", + Long: "Get the details of a non closed channel plus any submitted update waiting to be executed.", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { @@ -287,9 +287,27 @@ func GetChannelCmd(cdc *wire.Codec, paychanStoreName string) *cobra.Command { if err != nil { return err } - // print out json channel fmt.Println(string(jsonChannel)) + + // Get any submitted updates from the node + res, err = ctx.QueryStore(paychan.GetSubmittedUpdateKey(id), paychanStoreName) + if err != nil { + return err + } + // Print out the submited update if it exsits + if len(res) != 0 { + var submittedUpdate paychan.SubmittedUpdate + cdc.MustUnmarshalBinary(res, &submittedUpdate) + + // Convert the submitted update to a json object for pretty printing + jsonSU, err := wire.MarshalJSONIndent(cdc, submittedUpdate) + if err != nil { + return err + } + // print out json submitted update + fmt.Println(string(jsonSU)) + } return nil }, } diff --git a/internal/x/paychan/endblocker_test.go b/internal/x/paychan/endblocker_test.go index 655a2fa1..62fd276e 100644 --- a/internal/x/paychan/endblocker_test.go +++ b/internal/x/paychan/endblocker_test.go @@ -7,6 +7,8 @@ import ( ) func TestEndBlocker(t *testing.T) { + // TODO test that endBlocker doesn't close channels before the execution time + // SETUP accountSeeds := []string{"senderSeed", "receiverSeed"} ctx, _, channelKeeper, addrs, _, _, _ := createMockApp(accountSeeds) diff --git a/internal/x/paychan/keeper.go b/internal/x/paychan/keeper.go index 47bb90d1..14324795 100644 --- a/internal/x/paychan/keeper.go +++ b/internal/x/paychan/keeper.go @@ -283,7 +283,7 @@ func (k Keeper) getSubmittedUpdate(ctx sdk.Context, channelID ChannelID) (Submit // load from DB store := ctx.KVStore(k.storeKey) - bz := store.Get(k.getSubmittedUpdateKey(channelID)) + bz := store.Get(GetSubmittedUpdateKey(channelID)) var sUpdate SubmittedUpdate if bz == nil { @@ -301,16 +301,16 @@ 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 := GetSubmittedUpdateKey(sUpdate.ChannelID) store.Set(key, bz) // panics if something goes wrong } func (k Keeper) deleteSubmittedUpdate(ctx sdk.Context, channelID ChannelID) { store := ctx.KVStore(k.storeKey) - store.Delete(k.getSubmittedUpdateKey(channelID)) + store.Delete(GetSubmittedUpdateKey(channelID)) // TODO does this have return values? What happens when key doesn't exist? } -func (k Keeper) getSubmittedUpdateKey(channelID ChannelID) []byte { +func GetSubmittedUpdateKey(channelID ChannelID) []byte { return []byte(fmt.Sprintf("submittedUpdate:%d", channelID)) } diff --git a/internal/x/paychan/types.go b/internal/x/paychan/types.go index 76704ca7..57d44b52 100644 --- a/internal/x/paychan/types.go +++ b/internal/x/paychan/types.go @@ -16,7 +16,7 @@ type Channel struct { Coins sdk.Coins } -const ChannelDisputeTime = int64(2000) // measured in blocks TODO pick reasonable time +const ChannelDisputeTime = int64(6) // measured in blocks TODO pick reasonable time, add to channel or genesis type ChannelID int64 // TODO should this be positive only?