diff --git a/api/api_full.go b/api/api_full.go index f913483b3..8ae857dfd 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -421,7 +421,8 @@ type FullNode interface { PaychGet(ctx context.Context, from, to address.Address, amt types.BigInt) (*ChannelInfo, error) PaychGetWaitReady(context.Context, cid.Cid) (address.Address, error) - PaychAvailableFunds(from, to address.Address) (*ChannelAvailableFunds, error) + PaychAvailableFunds(ch address.Address) (*ChannelAvailableFunds, error) + PaychAvailableFundsByFromTo(from, to address.Address) (*ChannelAvailableFunds, error) PaychList(context.Context) ([]address.Address, error) PaychStatus(context.Context, address.Address) (*PaychStatus, error) PaychSettle(context.Context, address.Address) (cid.Cid, error) @@ -540,7 +541,12 @@ type ChannelInfo struct { } type ChannelAvailableFunds struct { + // Channel is the address of the channel Channel *address.Address + // From is the from address of the channel (channel creator) + From address.Address + // To is the to address of the channel + To address.Address // ConfirmedAmt is the amount of funds that have been confirmed on-chain // for the channel ConfirmedAmt types.BigInt diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index dff614001..e2444f16b 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -207,22 +207,23 @@ type FullNodeStruct struct { MarketEnsureAvailable func(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"` - PaychGet func(ctx context.Context, from, to address.Address, amt types.BigInt) (*api.ChannelInfo, error) `perm:"sign"` - PaychGetWaitReady func(context.Context, cid.Cid) (address.Address, error) `perm:"sign"` - PaychAvailableFunds func(address.Address, address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"` - PaychList func(context.Context) ([]address.Address, error) `perm:"read"` - PaychStatus func(context.Context, address.Address) (*api.PaychStatus, error) `perm:"read"` - PaychSettle func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` - PaychCollect func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` - PaychAllocateLane func(context.Context, address.Address) (uint64, error) `perm:"sign"` - PaychNewPayment func(ctx context.Context, from, to address.Address, vouchers []api.VoucherSpec) (*api.PaymentInfo, error) `perm:"sign"` - PaychVoucherCheck func(context.Context, *paych.SignedVoucher) error `perm:"read"` - PaychVoucherCheckValid func(context.Context, address.Address, *paych.SignedVoucher) error `perm:"read"` - PaychVoucherCheckSpendable func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) `perm:"read"` - PaychVoucherAdd func(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error) `perm:"write"` - PaychVoucherCreate func(context.Context, address.Address, big.Int, uint64) (*api.VoucherCreateResult, error) `perm:"sign"` - PaychVoucherList func(context.Context, address.Address) ([]*paych.SignedVoucher, error) `perm:"write"` - PaychVoucherSubmit func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) `perm:"sign"` + PaychGet func(ctx context.Context, from, to address.Address, amt types.BigInt) (*api.ChannelInfo, error) `perm:"sign"` + PaychGetWaitReady func(context.Context, cid.Cid) (address.Address, error) `perm:"sign"` + PaychAvailableFunds func(address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"` + PaychAvailableFundsByFromTo func(address.Address, address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"` + PaychList func(context.Context) ([]address.Address, error) `perm:"read"` + PaychStatus func(context.Context, address.Address) (*api.PaychStatus, error) `perm:"read"` + PaychSettle func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` + PaychCollect func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` + PaychAllocateLane func(context.Context, address.Address) (uint64, error) `perm:"sign"` + PaychNewPayment func(ctx context.Context, from, to address.Address, vouchers []api.VoucherSpec) (*api.PaymentInfo, error) `perm:"sign"` + PaychVoucherCheck func(context.Context, *paych.SignedVoucher) error `perm:"read"` + PaychVoucherCheckValid func(context.Context, address.Address, *paych.SignedVoucher) error `perm:"read"` + PaychVoucherCheckSpendable func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) `perm:"read"` + PaychVoucherAdd func(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error) `perm:"write"` + PaychVoucherCreate func(context.Context, address.Address, big.Int, uint64) (*api.VoucherCreateResult, error) `perm:"sign"` + PaychVoucherList func(context.Context, address.Address) ([]*paych.SignedVoucher, error) `perm:"write"` + PaychVoucherSubmit func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) `perm:"sign"` } } @@ -905,8 +906,12 @@ func (c *FullNodeStruct) PaychGetWaitReady(ctx context.Context, sentinel cid.Cid return c.Internal.PaychGetWaitReady(ctx, sentinel) } -func (c *FullNodeStruct) PaychAvailableFunds(from address.Address, to address.Address) (*api.ChannelAvailableFunds, error) { - return c.Internal.PaychAvailableFunds(from, to) +func (c *FullNodeStruct) PaychAvailableFunds(ch address.Address) (*api.ChannelAvailableFunds, error) { + return c.Internal.PaychAvailableFunds(ch) +} + +func (c *FullNodeStruct) PaychAvailableFundsByFromTo(from, to address.Address) (*api.ChannelAvailableFunds, error) { + return c.Internal.PaychAvailableFundsByFromTo(from, to) } func (c *FullNodeStruct) PaychList(ctx context.Context) ([]address.Address, error) { diff --git a/cli/paych.go b/cli/paych.go index 11b550cc6..6e2104551 100644 --- a/cli/paych.go +++ b/cli/paych.go @@ -8,6 +8,8 @@ import ( "sort" "strings" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/paychmgr" "github.com/filecoin-project/go-address" @@ -80,13 +82,13 @@ var paychAddFundsCmd = &cli.Command{ }, } -var paychStatusCmd = &cli.Command{ - Name: "status", - Usage: "Show the status of an outbound payment channel between fromAddress and toAddress", +var paychStatusByFromToCmd = &cli.Command{ + Name: "status-by-from-to", + Usage: "Show the status of an active outbound payment channel by from/to addresses", ArgsUsage: "[fromAddress toAddress]", Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 2 { - return ShowHelp(cctx, fmt.Errorf("must pass two arguments: ")) + return ShowHelp(cctx, fmt.Errorf("must pass two arguments: ")) } from, err := address.NewFromString(cctx.Args().Get(0)) @@ -105,52 +107,86 @@ var paychStatusCmd = &cli.Command{ } defer closer() - avail, err := api.PaychAvailableFunds(from, to) + avail, err := api.PaychAvailableFundsByFromTo(from, to) if err != nil { return err } - if avail.Channel == nil { - if avail.PendingWaitSentinel != nil { - fmt.Fprint(cctx.App.Writer, "Creating channel\n") - fmt.Fprintf(cctx.App.Writer, " From: %s\n", from) - fmt.Fprintf(cctx.App.Writer, " To: %s\n", to) - fmt.Fprintf(cctx.App.Writer, " Pending Amt: %d\n", avail.PendingAmt) - fmt.Fprintf(cctx.App.Writer, " Wait Sentinel: %s\n", avail.PendingWaitSentinel) - return nil - } - fmt.Fprint(cctx.App.Writer, "Channel does not exist\n") - fmt.Fprintf(cctx.App.Writer, " From: %s\n", from) - fmt.Fprintf(cctx.App.Writer, " To: %s\n", to) - return nil - } - - if avail.PendingWaitSentinel != nil { - fmt.Fprint(cctx.App.Writer, "Adding Funds to channel\n") - } else { - fmt.Fprint(cctx.App.Writer, "Channel exists\n") - } - - nameValues := [][]string{ - {"Channel", avail.Channel.String()}, - {"From", from.String()}, - {"To", to.String()}, - {"Confirmed Amt", fmt.Sprintf("%d", avail.ConfirmedAmt)}, - {"Pending Amt", fmt.Sprintf("%d", avail.PendingAmt)}, - {"Queued Amt", fmt.Sprintf("%d", avail.QueuedAmt)}, - {"Voucher Redeemed Amt", fmt.Sprintf("%d", avail.VoucherReedeemedAmt)}, - } - if avail.PendingWaitSentinel != nil { - nameValues = append(nameValues, []string{ - "Add Funds Wait Sentinel", - avail.PendingWaitSentinel.String(), - }) - } - fmt.Fprint(cctx.App.Writer, formatNameValues(nameValues)) + paychStatus(cctx.App.Writer, avail) return nil }, } +var paychStatusCmd = &cli.Command{ + Name: "status", + Usage: "Show the status of an outbound payment channel", + ArgsUsage: "[channelAddress]", + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 1 { + return ShowHelp(cctx, fmt.Errorf("must pass an argument: ")) + } + + ch, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return ShowHelp(cctx, fmt.Errorf("failed to parse channel address: %s", err)) + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + avail, err := api.PaychAvailableFunds(ch) + if err != nil { + return err + } + + paychStatus(cctx.App.Writer, avail) + return nil + }, +} + +func paychStatus(writer io.Writer, avail *api.ChannelAvailableFunds) { + if avail.Channel == nil { + if avail.PendingWaitSentinel != nil { + fmt.Fprint(writer, "Creating channel\n") + fmt.Fprintf(writer, " From: %s\n", avail.From) + fmt.Fprintf(writer, " To: %s\n", avail.To) + fmt.Fprintf(writer, " Pending Amt: %d\n", avail.PendingAmt) + fmt.Fprintf(writer, " Wait Sentinel: %s\n", avail.PendingWaitSentinel) + return + } + fmt.Fprint(writer, "Channel does not exist\n") + fmt.Fprintf(writer, " From: %s\n", avail.From) + fmt.Fprintf(writer, " To: %s\n", avail.To) + return + } + + if avail.PendingWaitSentinel != nil { + fmt.Fprint(writer, "Adding Funds to channel\n") + } else { + fmt.Fprint(writer, "Channel exists\n") + } + + nameValues := [][]string{ + {"Channel", avail.Channel.String()}, + {"From", avail.From.String()}, + {"To", avail.To.String()}, + {"Confirmed Amt", fmt.Sprintf("%d", avail.ConfirmedAmt)}, + {"Pending Amt", fmt.Sprintf("%d", avail.PendingAmt)}, + {"Queued Amt", fmt.Sprintf("%d", avail.QueuedAmt)}, + {"Voucher Redeemed Amt", fmt.Sprintf("%d", avail.VoucherReedeemedAmt)}, + } + if avail.PendingWaitSentinel != nil { + nameValues = append(nameValues, []string{ + "Add Funds Wait Sentinel", + avail.PendingWaitSentinel.String(), + }) + } + fmt.Fprint(writer, formatNameValues(nameValues)) +} + func formatNameValues(nameValues [][]string) string { maxLen := 0 for _, nv := range nameValues { diff --git a/cli/paych_test.go b/cli/paych_test.go index d4089c4ab..9b21d8070 100644 --- a/cli/paych_test.go +++ b/cli/paych_test.go @@ -117,7 +117,7 @@ func TestPaymentChannelStatus(t *testing.T) { creatorCLI := mockCLI.client(paymentCreator.ListenAddr) cmd := []string{creatorAddr.String(), receiverAddr.String()} - out := creatorCLI.runCmd(paychStatusCmd, cmd) + out := creatorCLI.runCmd(paychStatusByFromToCmd, cmd) fmt.Println(out) noChannelState := "Channel does not exist" require.Regexp(t, regexp.MustCompile(noChannelState), out) @@ -133,7 +133,7 @@ func TestPaymentChannelStatus(t *testing.T) { // Wait for the output to stop being "Channel does not exist" for regexp.MustCompile(noChannelState).MatchString(out) { cmd = []string{creatorAddr.String(), receiverAddr.String()} - out = creatorCLI.runCmd(paychStatusCmd, cmd) + out = creatorCLI.runCmd(paychStatusByFromToCmd, cmd) } fmt.Println(out) @@ -153,7 +153,7 @@ func TestPaymentChannelStatus(t *testing.T) { // Wait for create channel to complete chstr := <-create - cmd = []string{creatorAddr.String(), receiverAddr.String()} + cmd = []string{chstr} out = creatorCLI.runCmd(paychStatusCmd, cmd) fmt.Println(out) // Output should have the channel address @@ -169,7 +169,7 @@ func TestPaymentChannelStatus(t *testing.T) { cmd = []string{chAddr.String(), fmt.Sprintf("%d", voucherAmt)} creatorCLI.runCmd(paychVoucherCreateCmd, cmd) - cmd = []string{creatorAddr.String(), receiverAddr.String()} + cmd = []string{chstr} out = creatorCLI.runCmd(paychStatusCmd, cmd) fmt.Println(out) voucherAmtAtto := types.BigMul(types.NewInt(voucherAmt), types.NewInt(build.FilecoinPrecision)) diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index bba212d45..dd5c13815 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -98,6 +98,7 @@ * [Paych](#Paych) * [PaychAllocateLane](#PaychAllocateLane) * [PaychAvailableFunds](#PaychAvailableFunds) + * [PaychAvailableFundsByFromTo](#PaychAvailableFundsByFromTo) * [PaychCollect](#PaychCollect) * [PaychGet](#PaychGet) * [PaychGetWaitReady](#PaychGetWaitReady) @@ -2239,6 +2240,27 @@ There are not yet any comments for this method. Perms: sign +Inputs: `null` + +Response: +```json +{ + "Channel": "\u003cempty\u003e", + "From": "t01234", + "To": "t01234", + "ConfirmedAmt": "0", + "PendingAmt": "0", + "PendingWaitSentinel": null, + "QueuedAmt": "0", + "VoucherReedeemedAmt": "0" +} +``` + +### PaychAvailableFundsByFromTo +There are not yet any comments for this method. + +Perms: sign + Inputs: ```json [ @@ -2250,6 +2272,8 @@ Response: ```json { "Channel": "\u003cempty\u003e", + "From": "t01234", + "To": "t01234", "ConfirmedAmt": "0", "PendingAmt": "0", "PendingWaitSentinel": null, diff --git a/node/impl/paych/paych.go b/node/impl/paych/paych.go index e998f969f..84c2cc030 100644 --- a/node/impl/paych/paych.go +++ b/node/impl/paych/paych.go @@ -39,8 +39,12 @@ func (a *PaychAPI) PaychGet(ctx context.Context, from, to address.Address, amt t }, nil } -func (a *PaychAPI) PaychAvailableFunds(from, to address.Address) (*api.ChannelAvailableFunds, error) { - return a.PaychMgr.AvailableFunds(from, to) +func (a *PaychAPI) PaychAvailableFunds(ch address.Address) (*api.ChannelAvailableFunds, error) { + return a.PaychMgr.AvailableFunds(ch) +} + +func (a *PaychAPI) PaychAvailableFundsByFromTo(from, to address.Address) (*api.ChannelAvailableFunds, error) { + return a.PaychMgr.AvailableFundsByFromTo(from, to) } func (a *PaychAPI) PaychGetWaitReady(ctx context.Context, sentinel cid.Cid) (address.Address, error) { diff --git a/paychmgr/manager.go b/paychmgr/manager.go index d1fd715ef..00d796eea 100644 --- a/paychmgr/manager.go +++ b/paychmgr/manager.go @@ -141,13 +141,48 @@ func (pm *Manager) GetPaych(ctx context.Context, from, to address.Address, amt t return chanAccessor.getPaych(ctx, amt) } -func (pm *Manager) AvailableFunds(from address.Address, to address.Address) (*api.ChannelAvailableFunds, error) { - chanAccessor, err := pm.accessorByFromTo(from, to) +func (pm *Manager) AvailableFunds(ch address.Address) (*api.ChannelAvailableFunds, error) { + ca, err := pm.accessorByAddress(ch) if err != nil { return nil, err } - return chanAccessor.availableFunds() + ci, err := ca.getChannelInfo(ch) + if err != nil { + return nil, err + } + + return ca.availableFunds(ci.ChannelID) +} + +func (pm *Manager) AvailableFundsByFromTo(from address.Address, to address.Address) (*api.ChannelAvailableFunds, error) { + ca, err := pm.accessorByFromTo(from, to) + if err != nil { + return nil, err + } + + ci, err := ca.outboundActiveByFromTo(from, to) + if err == ErrChannelNotTracked { + // If there is no active channel between from / to we still want to + // return an empty ChannelAvailableFunds, so that clients can check + // for the existence of a channel between from / to without getting + // an error. + return &api.ChannelAvailableFunds{ + Channel: nil, + From: from, + To: to, + ConfirmedAmt: types.NewInt(0), + PendingAmt: types.NewInt(0), + PendingWaitSentinel: nil, + QueuedAmt: types.NewInt(0), + VoucherReedeemedAmt: types.NewInt(0), + }, nil + } + if err != nil { + return nil, err + } + + return ca.availableFunds(ci.ChannelID) } // GetPaychWaitReady waits until the create channel / add funds message with the diff --git a/paychmgr/paych.go b/paychmgr/paych.go index be43aaf9b..dd655b3e6 100644 --- a/paychmgr/paych.go +++ b/paychmgr/paych.go @@ -20,7 +20,7 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/account" "github.com/filecoin-project/specs-actors/actors/builtin/paych" - xerrors "golang.org/x/xerrors" + "golang.org/x/xerrors" ) // insufficientFundsErr indicates that there are not enough funds in the @@ -81,6 +81,13 @@ func (ca *channelAccessor) getChannelInfo(addr address.Address) (*ChannelInfo, e return ca.store.ByAddress(addr) } +func (ca *channelAccessor) outboundActiveByFromTo(from, to address.Address) (*ChannelInfo, error) { + ca.lk.Lock() + defer ca.lk.Unlock() + + return ca.store.OutboundActiveByFromTo(from, to) +} + // createVoucher creates a voucher with the given specification, setting its // nonce, signing the voucher and storing it in the local datastore. // If there are not enough funds in the channel to create the voucher, returns diff --git a/paychmgr/paychget_test.go b/paychmgr/paychget_test.go index 8eff08bdd..07c84e764 100644 --- a/paychmgr/paychget_test.go +++ b/paychmgr/paychget_test.go @@ -921,7 +921,7 @@ func TestPaychAvailableFunds(t *testing.T) { require.NoError(t, err) // No channel created yet so available funds should be all zeroes - av, err := mgr.AvailableFunds(from, to) + av, err := mgr.AvailableFundsByFromTo(from, to) require.NoError(t, err) require.Nil(t, av.Channel) require.Nil(t, av.PendingWaitSentinel) @@ -936,7 +936,7 @@ func TestPaychAvailableFunds(t *testing.T) { require.NoError(t, err) // Available funds should reflect create channel message sent - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFundsByFromTo(from, to) require.NoError(t, err) require.Nil(t, av.Channel) require.EqualValues(t, 0, av.ConfirmedAmt.Int64()) @@ -964,7 +964,7 @@ func TestPaychAvailableFunds(t *testing.T) { waitForQueueSize(t, mgr, from, to, 1) // Available funds should now include queued funds - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFundsByFromTo(from, to) require.NoError(t, err) require.Nil(t, av.Channel) require.NotNil(t, av.PendingWaitSentinel) @@ -1009,7 +1009,7 @@ func TestPaychAvailableFunds(t *testing.T) { // Available funds should now include the channel and also a wait sentinel // for the add funds message - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFunds(ch) require.NoError(t, err) require.NotNil(t, av.Channel) require.NotNil(t, av.PendingWaitSentinel) @@ -1031,7 +1031,7 @@ func TestPaychAvailableFunds(t *testing.T) { require.NoError(t, err) // Available funds should no longer have a wait sentinel - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFunds(ch) require.NoError(t, err) require.NotNil(t, av.Channel) require.Nil(t, av.PendingWaitSentinel) @@ -1052,7 +1052,7 @@ func TestPaychAvailableFunds(t *testing.T) { _, err = mgr.AddVoucherOutbound(ctx, ch, voucher, nil, types.NewInt(0)) require.NoError(t, err) - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFunds(ch) require.NoError(t, err) require.NotNil(t, av.Channel) require.Nil(t, av.PendingWaitSentinel) diff --git a/paychmgr/simple.go b/paychmgr/simple.go index 88d94645e..561f2dfc7 100644 --- a/paychmgr/simple.go +++ b/paychmgr/simple.go @@ -187,11 +187,11 @@ func (ca *channelAccessor) enqueue(task *fundsReq) { defer ca.lk.Unlock() ca.fundsReqQueue = append(ca.fundsReqQueue, task) - go ca.processQueue() // nolint: errcheck + go ca.processQueue("") // nolint: errcheck } // Run the operations in the queue -func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { +func (ca *channelAccessor) processQueue(channelID string) (*api.ChannelAvailableFunds, error) { ca.lk.Lock() defer ca.lk.Unlock() @@ -200,7 +200,7 @@ func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { // If there's nothing in the queue, bail out if len(ca.fundsReqQueue) == 0 { - return ca.currentAvailableFunds(types.NewInt(0)) + return ca.currentAvailableFunds(channelID, types.NewInt(0)) } // Merge all pending requests into one. @@ -211,7 +211,7 @@ func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { if amt.IsZero() { // Note: The amount can be zero if requests are cancelled as we're // building the mergedFundsReq - return ca.currentAvailableFunds(amt) + return ca.currentAvailableFunds(channelID, amt) } res := ca.processTask(merged.ctx, amt) @@ -221,7 +221,7 @@ func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { if res == nil { // Stop processing the fundsReqQueue and wait. When the event occurs it will // call processQueue() again - return ca.currentAvailableFunds(amt) + return ca.currentAvailableFunds(channelID, amt) } // Finished processing so clear the queue @@ -230,7 +230,7 @@ func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { // Call the task callback with its results merged.onComplete(res) - return ca.currentAvailableFunds(types.NewInt(0)) + return ca.currentAvailableFunds(channelID, types.NewInt(0)) } // filterQueue filters cancelled requests out of the queue @@ -283,25 +283,16 @@ func (ca *channelAccessor) msgWaitComplete(mcid cid.Cid, err error) { // The queue may have been waiting for msg completion to proceed, so // process the next queue item if len(ca.fundsReqQueue) > 0 { - go ca.processQueue() // nolint: errcheck + go ca.processQueue("") // nolint: errcheck } } -func (ca *channelAccessor) currentAvailableFunds(queuedAmt types.BigInt) (*api.ChannelAvailableFunds, error) { - channelInfo, err := ca.store.OutboundActiveByFromTo(ca.from, ca.to) - if err == ErrChannelNotTracked { - // If the channel does not exist we still want to return an empty - // ChannelAvailableFunds, so that clients can check for the existence - // of a channel between from / to without getting an error. - return &api.ChannelAvailableFunds{ - Channel: nil, - ConfirmedAmt: types.NewInt(0), - PendingAmt: types.NewInt(0), - PendingWaitSentinel: nil, - QueuedAmt: queuedAmt, - VoucherReedeemedAmt: types.NewInt(0), - }, nil +func (ca *channelAccessor) currentAvailableFunds(channelID string, queuedAmt types.BigInt) (*api.ChannelAvailableFunds, error) { + if len(channelID) == 0 { + return nil, nil } + + channelInfo, err := ca.store.ByChannelID(channelID) if err != nil { return nil, err } @@ -335,6 +326,8 @@ func (ca *channelAccessor) currentAvailableFunds(queuedAmt types.BigInt) (*api.C return &api.ChannelAvailableFunds{ Channel: channelInfo.Channel, + From: channelInfo.from(), + To: channelInfo.to(), ConfirmedAmt: channelInfo.Amount, PendingAmt: channelInfo.PendingAmount, PendingWaitSentinel: waitSentinel, @@ -713,6 +706,6 @@ func (ca *channelAccessor) msgPromise(ctx context.Context, mcid cid.Cid) chan on return promise } -func (ca *channelAccessor) availableFunds() (*api.ChannelAvailableFunds, error) { - return ca.processQueue() +func (ca *channelAccessor) availableFunds(channelID string) (*api.ChannelAvailableFunds, error) { + return ca.processQueue(channelID) } diff --git a/paychmgr/store.go b/paychmgr/store.go index 4a5a4f49f..46249fa36 100644 --- a/paychmgr/store.go +++ b/paychmgr/store.go @@ -86,6 +86,20 @@ type ChannelInfo struct { Settling bool } +func (ci *ChannelInfo) from() address.Address { + if ci.Direction == DirOutbound { + return ci.Control + } + return ci.Target +} + +func (ci *ChannelInfo) to() address.Address { + if ci.Direction == DirOutbound { + return ci.Target + } + return ci.Control +} + // infoForVoucher gets the VoucherInfo for the given voucher. // returns nil if the channel doesn't have the voucher. func (ci *ChannelInfo) infoForVoucher(sv *paych.SignedVoucher) (*VoucherInfo, error) {