Skip to content

Commit 969e300

Browse files
committed
loop: add cancel swap to server interface
1 parent 71501ef commit 969e300

File tree

2 files changed

+115
-0
lines changed

2 files changed

+115
-0
lines changed

server_mock_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ type serverMock struct {
4343
// preimagePush is a channel that preimage pushes are sent into.
4444
preimagePush chan lntypes.Preimage
4545

46+
// cancelSwap is a channel that swap cancelations are sent into.
47+
cancelSwap chan *outCancelDetails
48+
4649
lnd *test.LndMockServices
4750
}
4851

@@ -59,6 +62,7 @@ func newServerMock(lnd *test.LndMockServices) *serverMock {
5962
height: 600,
6063

6164
preimagePush: make(chan lntypes.Preimage),
65+
cancelSwap: make(chan *outCancelDetails),
6266

6367
lnd: lnd,
6468
}
@@ -178,6 +182,14 @@ func (s *serverMock) PushLoopOutPreimage(_ context.Context,
178182
return nil
179183
}
180184

185+
// CancelLoopOutSwap pushes a request to cancel a swap into our mock's channel.
186+
func (s *serverMock) CancelLoopOutSwap(ctx context.Context,
187+
details *outCancelDetails) error {
188+
189+
s.cancelSwap <- details
190+
return nil
191+
}
192+
181193
func (s *serverMock) GetLoopInTerms(ctx context.Context) (
182194
*LoopInTerms, error) {
183195

swap_server_client.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/lightninglabs/aperture/lsat"
1818
"github.com/lightninglabs/loop/loopdb"
1919
"github.com/lightninglabs/loop/looprpc"
20+
"github.com/lightningnetwork/lnd/lnrpc"
2021
"github.com/lightningnetwork/lnd/lntypes"
2122
"github.com/lightningnetwork/lnd/routing/route"
2223
"github.com/lightningnetwork/lnd/tor"
@@ -74,6 +75,10 @@ type swapServerClient interface {
7475
// SubscribeLoopInUpdates subscribes to loop in server state.
7576
SubscribeLoopInUpdates(ctx context.Context,
7677
hash lntypes.Hash) (<-chan *ServerUpdate, <-chan error, error)
78+
79+
// CancelLoopOutSwap cancels a loop out swap.
80+
CancelLoopOutSwap(ctx context.Context,
81+
details *outCancelDetails) error
7782
}
7883

7984
type grpcSwapServerClient struct {
@@ -456,6 +461,104 @@ func (s *grpcSwapServerClient) makeServerUpdate(ctx context.Context,
456461
return updateChan, errChan
457462
}
458463

464+
// paymentType is an enum representing different types of off-chain payments
465+
// made by a swap.
466+
type paymentType uint8
467+
468+
const (
469+
// paymentTypePrepay indicates that we could not route the prepay.
470+
paymentTypePrepay paymentType = iota
471+
472+
// paymentTypeInvoice indicates that we could not route the swap
473+
// invoice.
474+
paymentTypeInvoice
475+
)
476+
477+
// routeCancelMetadata contains cancelation information for swaps that are
478+
// canceled because the client could not route off-chain to the server.
479+
type routeCancelMetadata struct {
480+
// paymentType is the type of payment that failed.
481+
paymentType paymentType
482+
483+
// attempts is the set of htlc attempts made by the client, reporting
484+
// the distance from the invoice's destination node that a failure
485+
// occurred.
486+
attempts []uint32
487+
488+
// failureReason is the reason that the payment failed.
489+
failureReason lnrpc.PaymentFailureReason
490+
}
491+
492+
// outCancelDetails contains the informaton required to cancel a loop out swap.
493+
type outCancelDetails struct {
494+
// Hash is the swap's hash.
495+
hash lntypes.Hash
496+
497+
// paymentAddr is the payment address for the swap's invoice.
498+
paymentAddr [32]byte
499+
500+
// metadata contains additional information about the swap.
501+
metadata routeCancelMetadata
502+
}
503+
504+
// CancelLoopOutSwap sends an instruction to the server to cancel a loop out
505+
// swap.
506+
func (s *grpcSwapServerClient) CancelLoopOutSwap(ctx context.Context,
507+
details *outCancelDetails) error {
508+
509+
req := &looprpc.CancelLoopOutSwapRequest{
510+
ProtocolVersion: loopdb.CurrentRPCProtocolVersion,
511+
SwapHash: details.hash[:],
512+
PaymentAddress: details.paymentAddr[:],
513+
}
514+
515+
var err error
516+
req.CancelInfo, err = rpcRouteCancel(details)
517+
if err != nil {
518+
return err
519+
}
520+
521+
_, err = s.server.CancelLoopOutSwap(ctx, req)
522+
return err
523+
}
524+
525+
func rpcRouteCancel(details *outCancelDetails) (
526+
*looprpc.CancelLoopOutSwapRequest_RouteCancel, error) {
527+
528+
attempts := make([]*looprpc.HtlcAttempt, len(details.metadata.attempts))
529+
for i, remaining := range details.metadata.attempts {
530+
attempts[i] = &looprpc.HtlcAttempt{
531+
RemainingHops: remaining,
532+
}
533+
}
534+
535+
resp := &looprpc.CancelLoopOutSwapRequest_RouteCancel{
536+
RouteCancel: &looprpc.RouteCancel{
537+
Attempts: attempts,
538+
// We can cast our lnd failure reason to a loop payment
539+
// failure reason because these values are copied 1:1
540+
// from lnd.
541+
Failure: looprpc.PaymentFailureReason(
542+
details.metadata.failureReason,
543+
),
544+
},
545+
}
546+
547+
switch details.metadata.paymentType {
548+
case paymentTypePrepay:
549+
resp.RouteCancel.RouteType = looprpc.RoutePaymentType_PREPAY_ROUTE
550+
551+
case paymentTypeInvoice:
552+
resp.RouteCancel.RouteType = looprpc.RoutePaymentType_INVOICE_ROUTE
553+
554+
default:
555+
return nil, fmt.Errorf("unknown payment type: %v",
556+
details.metadata.paymentType)
557+
}
558+
559+
return resp, nil
560+
}
561+
459562
// getSwapServerConn returns a connection to the swap server. A non-empty
460563
// proxyAddr indicates that a SOCKS proxy found at the address should be used to
461564
// establish the connection.

0 commit comments

Comments
 (0)