From 987e6a1ff58b4615747d7e2e075e90c0ecf1b3ae Mon Sep 17 00:00:00 2001 From: Yaacov Akiba Slama Date: Tue, 11 Aug 2020 17:16:04 +0300 Subject: [PATCH] Wait for the new channel to be active before resuming the htlc --- db.go | 4 +-- intercept.go | 71 +++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 58 insertions(+), 17 deletions(-) diff --git a/db.go b/db.go index 8283bc4..cdb5e36 100644 --- a/db.go +++ b/db.go @@ -24,7 +24,7 @@ func pgConnect() error { return nil } -func paymentInfo(paymentHash []byte) ([]byte, []byte, int64, int64, []byte, int32, error) { +func paymentInfo(paymentHash []byte) ([]byte, []byte, int64, int64, []byte, uint32, error) { var ( paymentSecret, destination []byte incomingAmountMsat, outgoingAmountMsat int64 @@ -42,7 +42,7 @@ func paymentInfo(paymentHash []byte) ([]byte, []byte, int64, int64, []byte, int3 } return nil, nil, 0, 0, nil, 0, err } - return paymentSecret, destination, incomingAmountMsat, outgoingAmountMsat, fundingTxID, fundingTxOutnum.Int, nil + return paymentSecret, destination, incomingAmountMsat, outgoingAmountMsat, fundingTxID, uint32(fundingTxOutnum.Int), nil } func setFundingTx(paymentHash, fundingTxID []byte, fundingTxOutnum int) error { diff --git a/intercept.go b/intercept.go index ead87e8..bf92c7b 100644 --- a/intercept.go +++ b/intercept.go @@ -7,6 +7,7 @@ import ( "log" "math/big" "os" + "time" "github.com/btcsuite/btcd/btcec" "github.com/lightningnetwork/lnd/lnrpc" @@ -21,7 +22,7 @@ import ( sphinx "github.com/lightningnetwork/lightning-onion" ) -func openChannel(ctx context.Context, client lnrpc.LightningClient, paymentHash, destination []byte, incomingAmountMsat int64) error { +func openChannel(ctx context.Context, client lnrpc.LightningClient, paymentHash, destination []byte, incomingAmountMsat int64) ([]byte, uint32, error) { capacity := incomingAmountMsat/1000 + channelFeeStartAmount channelPoint, err := client.OpenChannelSync(ctx, &lnrpc.OpenChannelRequest{ NodePubkey: destination, @@ -30,13 +31,13 @@ func openChannel(ctx context.Context, client lnrpc.LightningClient, paymentHash, Private: true, }) if err != nil { - return err + return nil, 0, err } err = setFundingTx(paymentHash, channelPoint.GetFundingTxidBytes(), int(channelPoint.OutputIndex)) - return err + return channelPoint.GetFundingTxidBytes(), channelPoint.OutputIndex, err } -func getChannel(ctx context.Context, client lnrpc.LightningClient, node []byte) uint64 { +func getChannel(ctx context.Context, client lnrpc.LightningClient, node []byte, channelPoint string) uint64 { r, err := client.ListChannels(ctx, &lnrpc.ListChannelsRequest{Peer: node}) if err != nil { log.Printf("client.ListChannels(%x) error: %v", node, err) @@ -44,7 +45,9 @@ func getChannel(ctx context.Context, client lnrpc.LightningClient, node []byte) } for _, c := range r.Channels { log.Printf("getChannel(%x): %v", node, c.ChanId) - return c.ChanId + if c.ChannelPoint == channelPoint && c.Active { + return c.ChanId + } } log.Printf("No channel found: getChannel(%x)", node) return 0 @@ -82,7 +85,7 @@ func intercept() { request.OnionBlob, ) - paymentSecret, destination, incomingAmountMsat, outgoingAmountMsat, fundingTxID, _, err := paymentInfo(request.PaymentHash) + paymentSecret, destination, incomingAmountMsat, outgoingAmountMsat, fundingTxID, fundingTxOutnum, err := paymentInfo(request.PaymentHash) if err != nil { log.Printf("paymentInfo(%x) error: %v", request.PaymentHash, err) } @@ -91,9 +94,14 @@ func intercept() { if paymentSecret != nil { if fundingTxID == nil { - err = openChannel(clientCtx, client, request.PaymentHash, destination, incomingAmountMsat) + fundingTxID, fundingTxOutnum, err = openChannel(clientCtx, client, request.PaymentHash, destination, incomingAmountMsat) log.Printf("openChannel(%x, %v) err: %v", destination, incomingAmountMsat, err) - //TODO: wait for the channel to be active + if err != nil { + interceptorClient.Send(&routerrpc.ForwardHtlcInterceptResponse{ + IncomingCircuitKey: request.IncomingCircuitKey, + Action: routerrpc.ResolveHoldForwardAction_FAIL, + }) + } } pubKey, err := btcec.ParsePubKey(destination, btcec.S256()) @@ -133,13 +141,11 @@ func intercept() { var onionBlob bytes.Buffer err = sphinxPacket.Encode(&onionBlob) log.Printf("sphinxPacket.Encode(): %v", err) - interceptorClient.Send(&routerrpc.ForwardHtlcInterceptResponse{ - IncomingCircuitKey: request.IncomingCircuitKey, - Action: routerrpc.ResolveHoldForwardAction_RESUME, - OutgoingAmountMsat: uint64(amt), - OutgoingRequestedChanId: getChannel(clientCtx, client, destination), - OnionBlob: onionBlob.Bytes(), - }) + channelPoint := fmt.Sprintf("%x:%v", fundingTxID, fundingTxOutnum) + go resumeOrCancel( + clientCtx, interceptorClient, request.IncomingCircuitKey, destination, + channelPoint, uint64(amt), onionBlob.Bytes(), + ) } else { interceptorClient.Send(&routerrpc.ForwardHtlcInterceptResponse{ @@ -152,3 +158,38 @@ func intercept() { } } } + +func resumeOrCancel( + ctx context.Context, + interceptorClient routerrpc.Router_HtlcInterceptorClient, + incomingCircuitKey *routerrpc.CircuitKey, + destination []byte, + channelPoint string, + outgoingAmountMsat uint64, + onionBlob []byte, +) { + deadline := time.Now().Add(10 * time.Second) + for { + chanID := getChannel(ctx, client, destination, channelPoint) + if chanID != 0 { + interceptorClient.Send(&routerrpc.ForwardHtlcInterceptResponse{ + IncomingCircuitKey: incomingCircuitKey, + Action: routerrpc.ResolveHoldForwardAction_RESUME, + OutgoingAmountMsat: outgoingAmountMsat, + OutgoingRequestedChanId: chanID, + OnionBlob: onionBlob, + }) + return + } + log.Printf("getChannel(%x, %v) returns 0", destination, channelPoint) + if time.Now().After(deadline) { + log.Printf("Stop retrying getChannel(%x, %v)", destination, channelPoint) + break + } + time.Sleep(1 * time.Second) + } + interceptorClient.Send(&routerrpc.ForwardHtlcInterceptResponse{ + IncomingCircuitKey: incomingCircuitKey, + Action: routerrpc.ResolveHoldForwardAction_FAIL, + }) +}