multi: surface server swap initiation grpc error codes

Formatting our error was stifling any grpc error returned by the
server. Instead, we bubble up our grpc error, setting an unknown
code if the server did not specifically return an error code.
pull/407/head
carla 3 years ago
parent e7ee29bd83
commit d1c26a20da
No known key found for this signature in database
GPG Key ID: 4CA7FE54A6213C91

@ -15,6 +15,7 @@ import (
"github.com/lightninglabs/loop/loopdb"
"github.com/lightninglabs/loop/swap"
"github.com/lightninglabs/loop/sweep"
"google.golang.org/grpc/status"
)
var (
@ -610,3 +611,17 @@ func (s *Client) LoopInTerms(ctx context.Context) (
return s.Server.GetLoopInTerms(ctx)
}
// wrapGrpcError wraps the non-nil error provided with a message providing
// additional context, preserving the grpc code returned with the original
// error. If the original error has no grpc code, then codes.Unknown is used.
func wrapGrpcError(message string, err error) error {
// Since our error is non-nil, we don't need to worry about a nil
// grpcStatus, we'll just get an unknown one if no code was passed back.
grpcStatus, _ := status.FromError(err)
return status.Error(
grpcStatus.Code(), fmt.Sprintf("%v: %v", message,
grpcStatus.Message()),
)
}

@ -17,6 +17,8 @@ import (
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
var (
@ -372,3 +374,39 @@ func testSuccess(ctx *testContext, amt btcutil.Amount, hash lntypes.Hash,
ctx.finish()
}
// TestWrapGrpcError tests grpc error wrapping in the case where a grpc error
// code is present, and when it is absent.
func TestWrapGrpcError(t *testing.T) {
tests := []struct {
name string
original error
expectedCode codes.Code
}{
{
name: "out of range error",
original: status.Error(
codes.OutOfRange, "err string",
),
expectedCode: codes.OutOfRange,
},
{
name: "no grpc code",
original: errors.New("no error code"),
expectedCode: codes.Unknown,
},
}
for _, testCase := range tests {
testCase := testCase
t.Run(testCase.name, func(t *testing.T) {
err := wrapGrpcError("", testCase.original)
require.Error(t, err, "test only expects errors")
status, ok := status.FromError(err)
require.True(t, ok, "test expects grpc code")
require.Equal(t, testCase.expectedCode, status.Code())
})
}
}

@ -9,11 +9,10 @@ import (
"sync"
"time"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/mempool"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightninglabs/lndclient"
"github.com/lightninglabs/loop/labels"
"github.com/lightninglabs/loop/loopdb"
@ -86,7 +85,7 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
// request that we send to the server.
quote, err := cfg.server.GetLoopInQuote(globalCtx, request.Amount)
if err != nil {
return nil, fmt.Errorf("loop in terms: %v", err)
return nil, wrapGrpcError("loop in terms", err)
}
swapFee := quote.SwapFee
@ -172,7 +171,7 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
)
probeWaitCancel()
if err != nil {
return nil, fmt.Errorf("cannot initiate swap: %v", err)
return nil, wrapGrpcError("cannot initiate swap", err)
}
// Because the context is cancelled, it is guaranteed that we will be

@ -4,15 +4,14 @@ import (
"context"
"testing"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightninglabs/loop/loopdb"
"github.com/lightninglabs/loop/swap"
"github.com/lightninglabs/loop/test"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/stretchr/testify/require"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
var (

@ -128,7 +128,7 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig,
receiverKey, request.SwapPublicationDeadline, request.Initiator,
)
if err != nil {
return nil, fmt.Errorf("cannot initiate swap: %v", err)
return nil, wrapGrpcError("cannot initiate swap", err)
}
err = validateLoopOutContract(

Loading…
Cancel
Save