Skip to content

Commit 478f242

Browse files
authored
Merge pull request #407 from carlaKC/355-surfaceloopingrpcerr
multi: surface grpc error codes from server to client
2 parents b9a3d1d + b8f1fd1 commit 478f242

File tree

6 files changed

+63
-8
lines changed

6 files changed

+63
-8
lines changed

client.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/lightninglabs/loop/loopdb"
1616
"github.com/lightninglabs/loop/swap"
1717
"github.com/lightninglabs/loop/sweep"
18+
"google.golang.org/grpc/status"
1819
)
1920

2021
var (
@@ -610,3 +611,17 @@ func (s *Client) LoopInTerms(ctx context.Context) (
610611

611612
return s.Server.GetLoopInTerms(ctx)
612613
}
614+
615+
// wrapGrpcError wraps the non-nil error provided with a message providing
616+
// additional context, preserving the grpc code returned with the original
617+
// error. If the original error has no grpc code, then codes.Unknown is used.
618+
func wrapGrpcError(message string, err error) error {
619+
// Since our error is non-nil, we don't need to worry about a nil
620+
// grpcStatus, we'll just get an unknown one if no code was passed back.
621+
grpcStatus, _ := status.FromError(err)
622+
623+
return status.Error(
624+
grpcStatus.Code(), fmt.Sprintf("%v: %v", message,
625+
grpcStatus.Message()),
626+
)
627+
}

client_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717
"github.com/lightningnetwork/lnd/lnrpc"
1818
"github.com/lightningnetwork/lnd/lntypes"
1919
"github.com/stretchr/testify/require"
20+
"google.golang.org/grpc/codes"
21+
"google.golang.org/grpc/status"
2022
)
2123

2224
var (
@@ -372,3 +374,39 @@ func testSuccess(ctx *testContext, amt btcutil.Amount, hash lntypes.Hash,
372374

373375
ctx.finish()
374376
}
377+
378+
// TestWrapGrpcError tests grpc error wrapping in the case where a grpc error
379+
// code is present, and when it is absent.
380+
func TestWrapGrpcError(t *testing.T) {
381+
tests := []struct {
382+
name string
383+
original error
384+
expectedCode codes.Code
385+
}{
386+
{
387+
name: "out of range error",
388+
original: status.Error(
389+
codes.OutOfRange, "err string",
390+
),
391+
expectedCode: codes.OutOfRange,
392+
},
393+
{
394+
name: "no grpc code",
395+
original: errors.New("no error code"),
396+
expectedCode: codes.Unknown,
397+
},
398+
}
399+
400+
for _, testCase := range tests {
401+
testCase := testCase
402+
403+
t.Run(testCase.name, func(t *testing.T) {
404+
err := wrapGrpcError("", testCase.original)
405+
require.Error(t, err, "test only expects errors")
406+
407+
status, ok := status.FromError(err)
408+
require.True(t, ok, "test expects grpc code")
409+
require.Equal(t, testCase.expectedCode, status.Code())
410+
})
411+
}
412+
}

loopin.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ import (
99
"sync"
1010
"time"
1111

12-
"github.com/btcsuite/btcutil"
13-
1412
"github.com/btcsuite/btcd/chaincfg/chainhash"
1513
"github.com/btcsuite/btcd/mempool"
1614
"github.com/btcsuite/btcd/wire"
15+
"github.com/btcsuite/btcutil"
1716
"github.com/lightninglabs/lndclient"
1817
"github.com/lightninglabs/loop/labels"
1918
"github.com/lightninglabs/loop/loopdb"
@@ -86,7 +85,7 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
8685
// request that we send to the server.
8786
quote, err := cfg.server.GetLoopInQuote(globalCtx, request.Amount)
8887
if err != nil {
89-
return nil, fmt.Errorf("loop in terms: %v", err)
88+
return nil, wrapGrpcError("loop in terms", err)
9089
}
9190

9291
swapFee := quote.SwapFee
@@ -172,7 +171,7 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
172171
)
173172
probeWaitCancel()
174173
if err != nil {
175-
return nil, fmt.Errorf("cannot initiate swap: %v", err)
174+
return nil, wrapGrpcError("cannot initiate swap", err)
176175
}
177176

178177
// Because the context is cancelled, it is guaranteed that we will be

loopin_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@ import (
44
"context"
55
"testing"
66

7+
"github.com/btcsuite/btcd/wire"
8+
"github.com/btcsuite/btcutil"
79
"github.com/lightninglabs/loop/loopdb"
810
"github.com/lightninglabs/loop/swap"
911
"github.com/lightninglabs/loop/test"
1012
"github.com/lightningnetwork/lnd/chainntnfs"
1113
"github.com/lightningnetwork/lnd/channeldb"
1214
"github.com/stretchr/testify/require"
13-
14-
"github.com/btcsuite/btcd/wire"
15-
"github.com/btcsuite/btcutil"
1615
)
1716

1817
var (

loopout.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig,
128128
receiverKey, request.SwapPublicationDeadline, request.Initiator,
129129
)
130130
if err != nil {
131-
return nil, fmt.Errorf("cannot initiate swap: %v", err)
131+
return nil, wrapGrpcError("cannot initiate swap", err)
132132
}
133133

134134
err = validateLoopOutContract(

release_notes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,7 @@ This file tracks release notes for the loop client.
1919
#### Breaking Changes
2020

2121
#### Bug Fixes
22+
* Grpc error codes returned by the swap server when swap initiation fails are
23+
now surfaced to the client. Previously these error codes would be returned
24+
as a string.
25+

0 commit comments

Comments
 (0)