mirror of
https://github.com/aljazceru/lspd.git
synced 2025-12-21 07:44:22 +01:00
Handle interception probing payments
probing payments uses a probing payment hash which is:
sha256("probing-01:" || payment_hash).
When the interceptor detects such a hash for a payment which is supposed
to trigger a channel creation , it checks if the destination is online,
and if online, fails with INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS error in
order to let the payer knows that the payment would be successful.
This commit is contained in:
20
db.go
20
db.go
@@ -24,25 +24,25 @@ func pgConnect() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func paymentInfo(paymentHash []byte) ([]byte, []byte, int64, int64, []byte, uint32, error) {
|
func paymentInfo(htlcPaymentHash []byte) ([]byte, []byte, []byte, int64, int64, []byte, uint32, error) {
|
||||||
var (
|
var (
|
||||||
paymentSecret, destination []byte
|
paymentHash, paymentSecret, destination []byte
|
||||||
incomingAmountMsat, outgoingAmountMsat int64
|
incomingAmountMsat, outgoingAmountMsat int64
|
||||||
fundingTxID []byte
|
fundingTxID []byte
|
||||||
fundingTxOutnum pgtype.Int4
|
fundingTxOutnum pgtype.Int4
|
||||||
)
|
)
|
||||||
err := pgxPool.QueryRow(context.Background(),
|
err := pgxPool.QueryRow(context.Background(),
|
||||||
`SELECT payment_secret, destination, incoming_amount_msat, outgoing_amount_msat, funding_tx_id, funding_tx_outnum
|
`SELECT payment_hash, payment_secret, destination, incoming_amount_msat, outgoing_amount_msat, funding_tx_id, funding_tx_outnum
|
||||||
FROM payments
|
FROM payments
|
||||||
WHERE payment_hash=$1`,
|
WHERE payment_hash=$1 OR sha256('probing-01:' || payment_hash)=$1`,
|
||||||
paymentHash).Scan(&paymentSecret, &destination, &incomingAmountMsat, &outgoingAmountMsat, &fundingTxID, &fundingTxOutnum)
|
htlcPaymentHash).Scan(&paymentHash, &paymentSecret, &destination, &incomingAmountMsat, &outgoingAmountMsat, &fundingTxID, &fundingTxOutnum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == pgx.ErrNoRows {
|
if err == pgx.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
return nil, nil, 0, 0, nil, 0, err
|
return nil, nil, nil, 0, 0, nil, 0, err
|
||||||
}
|
}
|
||||||
return paymentSecret, destination, incomingAmountMsat, outgoingAmountMsat, fundingTxID, uint32(fundingTxOutnum.Int), nil
|
return paymentHash, paymentSecret, destination, incomingAmountMsat, outgoingAmountMsat, fundingTxID, uint32(fundingTxOutnum.Int), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setFundingTx(paymentHash, fundingTxID []byte, fundingTxOutnum int) error {
|
func setFundingTx(paymentHash, fundingTxID []byte, fundingTxOutnum int) error {
|
||||||
|
|||||||
8
go.mod
8
go.mod
@@ -4,16 +4,16 @@ go 1.14
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aws/aws-sdk-go v1.30.20
|
github.com/aws/aws-sdk-go v1.30.20
|
||||||
github.com/btcsuite/btcd v0.20.1-beta
|
github.com/btcsuite/btcd v0.20.1-beta.0.20200730232343-1db1b6f8217f
|
||||||
github.com/caddyserver/certmagic v0.11.2
|
github.com/caddyserver/certmagic v0.11.2
|
||||||
github.com/golang/protobuf v1.4.2
|
github.com/golang/protobuf v1.4.2
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0
|
||||||
github.com/jackc/pgtype v1.4.2
|
github.com/jackc/pgtype v1.4.2
|
||||||
github.com/jackc/pgx/v4 v4.8.1
|
github.com/jackc/pgx/v4 v4.8.1
|
||||||
github.com/lightningnetwork/lightning-onion v1.0.1
|
github.com/lightningnetwork/lightning-onion v1.0.2-0.20200501022730-3c8c8d0b89ea
|
||||||
github.com/lightningnetwork/lnd v0.10.0-beta
|
github.com/lightningnetwork/lnd v0.11.0-beta
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
|
||||||
google.golang.org/grpc v1.31.0
|
google.golang.org/grpc v1.31.0
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/lightningnetwork/lnd v0.10.0-beta => github.com/breez/lnd v0.10.0-beta.rc6.0.20200727142715-f67a1052c0e0
|
replace github.com/lightningnetwork/lnd v0.11.0-beta => github.com/breez/lnd v0.11.0-beta.rc4.0.20201101122458-227226f00b18
|
||||||
|
|||||||
43
intercept.go
43
intercept.go
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/big"
|
"math/big"
|
||||||
@@ -32,6 +33,23 @@ func checkPayment(incomingAmountMsat, outgoingAmountMsat int64) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isConnected(ctx context.Context, client lnrpc.LightningClient, destination []byte) error {
|
||||||
|
pubKey := hex.EncodeToString(destination)
|
||||||
|
r, err := client.ListPeers(ctx, &lnrpc.ListPeersRequest{LatestError: true})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("client.ListPeers() error: %v", err)
|
||||||
|
return fmt.Errorf("client.ListPeers() error: %w", err)
|
||||||
|
}
|
||||||
|
for _, peer := range r.Peers {
|
||||||
|
if pubKey == peer.PubKey {
|
||||||
|
log.Printf("destination online: %x", destination)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Printf("destination offline: %x", destination)
|
||||||
|
return fmt.Errorf("destination offline")
|
||||||
|
}
|
||||||
|
|
||||||
func openChannel(ctx context.Context, client lnrpc.LightningClient, paymentHash, destination []byte, incomingAmountMsat int64) ([]byte, uint32, error) {
|
func openChannel(ctx context.Context, client lnrpc.LightningClient, paymentHash, destination []byte, incomingAmountMsat int64) ([]byte, uint32, error) {
|
||||||
capacity := incomingAmountMsat/1000 + additionalChannelCapacity
|
capacity := incomingAmountMsat/1000 + additionalChannelCapacity
|
||||||
channelPoint, err := client.OpenChannelSync(ctx, &lnrpc.OpenChannelRequest{
|
channelPoint, err := client.OpenChannelSync(ctx, &lnrpc.OpenChannelRequest{
|
||||||
@@ -104,21 +122,34 @@ func intercept() {
|
|||||||
request.OnionBlob,
|
request.OnionBlob,
|
||||||
)
|
)
|
||||||
|
|
||||||
paymentSecret, destination, incomingAmountMsat, outgoingAmountMsat, fundingTxID, fundingTxOutnum, err := paymentInfo(request.PaymentHash)
|
paymentHash, paymentSecret, destination, incomingAmountMsat, outgoingAmountMsat, fundingTxID, fundingTxOutnum, err := paymentInfo(request.PaymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("paymentInfo(%x) error: %v", request.PaymentHash, err)
|
log.Printf("paymentInfo(%x) error: %v", request.PaymentHash, err)
|
||||||
}
|
}
|
||||||
log.Printf("paymentSecret: %x\ndestination:%x\nincomingAmountMsat:%v\noutgoingAmountMsat:%v\n\n",
|
log.Printf("paymentHash:%x\npaymentSecret:%x\ndestination:%x\nincomingAmountMsat:%v\noutgoingAmountMsat:%v\n\n",
|
||||||
paymentSecret, destination, incomingAmountMsat, outgoingAmountMsat)
|
paymentHash, paymentSecret, destination, incomingAmountMsat, outgoingAmountMsat)
|
||||||
if paymentSecret != nil {
|
if paymentSecret != nil {
|
||||||
|
|
||||||
if fundingTxID == nil {
|
if fundingTxID == nil {
|
||||||
fundingTxID, fundingTxOutnum, err = openChannel(clientCtx, client, request.PaymentHash, destination, incomingAmountMsat)
|
if bytes.Compare(paymentHash, request.PaymentHash) == 0 {
|
||||||
log.Printf("openChannel(%x, %v) err: %v", destination, incomingAmountMsat, err)
|
fundingTxID, fundingTxOutnum, err = openChannel(clientCtx, client, request.PaymentHash, destination, incomingAmountMsat)
|
||||||
if err != nil {
|
log.Printf("openChannel(%x, %v) err: %v", destination, incomingAmountMsat, err)
|
||||||
|
if err != nil {
|
||||||
|
interceptorClient.Send(&routerrpc.ForwardHtlcInterceptResponse{
|
||||||
|
IncomingCircuitKey: request.IncomingCircuitKey,
|
||||||
|
Action: routerrpc.ResolveHoldForwardAction_FAIL,
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else { //probing
|
||||||
|
failureCode := routerrpc.ForwardHtlcInterceptResponse_TEMPORARY_CHANNEL_FAILURE
|
||||||
|
if err := isConnected(clientCtx, client, destination); err == nil {
|
||||||
|
failureCode = routerrpc.ForwardHtlcInterceptResponse_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS
|
||||||
|
}
|
||||||
interceptorClient.Send(&routerrpc.ForwardHtlcInterceptResponse{
|
interceptorClient.Send(&routerrpc.ForwardHtlcInterceptResponse{
|
||||||
IncomingCircuitKey: request.IncomingCircuitKey,
|
IncomingCircuitKey: request.IncomingCircuitKey,
|
||||||
Action: routerrpc.ResolveHoldForwardAction_FAIL,
|
Action: routerrpc.ResolveHoldForwardAction_FAIL,
|
||||||
|
FailureCode: failureCode,
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX probe_payment_hash;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
CREATE INDEX probe_payment_hash ON public.payments (sha256('probing-01:' || payment_hash));
|
||||||
Reference in New Issue
Block a user