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:
14
db.go
14
db.go
@@ -24,25 +24,25 @@ func pgConnect() error {
|
||||
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 (
|
||||
paymentSecret, destination []byte
|
||||
paymentHash, paymentSecret, destination []byte
|
||||
incomingAmountMsat, outgoingAmountMsat int64
|
||||
fundingTxID []byte
|
||||
fundingTxOutnum pgtype.Int4
|
||||
)
|
||||
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
|
||||
WHERE payment_hash=$1`,
|
||||
paymentHash).Scan(&paymentSecret, &destination, &incomingAmountMsat, &outgoingAmountMsat, &fundingTxID, &fundingTxOutnum)
|
||||
WHERE payment_hash=$1 OR sha256('probing-01:' || payment_hash)=$1`,
|
||||
htlcPaymentHash).Scan(&paymentHash, &paymentSecret, &destination, &incomingAmountMsat, &outgoingAmountMsat, &fundingTxID, &fundingTxOutnum)
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
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 {
|
||||
|
||||
8
go.mod
8
go.mod
@@ -4,16 +4,16 @@ go 1.14
|
||||
|
||||
require (
|
||||
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/golang/protobuf v1.4.2
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0
|
||||
github.com/jackc/pgtype v1.4.2
|
||||
github.com/jackc/pgx/v4 v4.8.1
|
||||
github.com/lightningnetwork/lightning-onion v1.0.1
|
||||
github.com/lightningnetwork/lnd v0.10.0-beta
|
||||
github.com/lightningnetwork/lightning-onion v1.0.2-0.20200501022730-3c8c8d0b89ea
|
||||
github.com/lightningnetwork/lnd v0.11.0-beta
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
|
||||
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
|
||||
|
||||
37
intercept.go
37
intercept.go
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/big"
|
||||
@@ -32,6 +33,23 @@ func checkPayment(incomingAmountMsat, outgoingAmountMsat int64) error {
|
||||
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) {
|
||||
capacity := incomingAmountMsat/1000 + additionalChannelCapacity
|
||||
channelPoint, err := client.OpenChannelSync(ctx, &lnrpc.OpenChannelRequest{
|
||||
@@ -104,15 +122,16 @@ func intercept() {
|
||||
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 {
|
||||
log.Printf("paymentInfo(%x) error: %v", request.PaymentHash, err)
|
||||
}
|
||||
log.Printf("paymentSecret: %x\ndestination:%x\nincomingAmountMsat:%v\noutgoingAmountMsat:%v\n\n",
|
||||
paymentSecret, destination, incomingAmountMsat, outgoingAmountMsat)
|
||||
log.Printf("paymentHash:%x\npaymentSecret:%x\ndestination:%x\nincomingAmountMsat:%v\noutgoingAmountMsat:%v\n\n",
|
||||
paymentHash, paymentSecret, destination, incomingAmountMsat, outgoingAmountMsat)
|
||||
if paymentSecret != nil {
|
||||
|
||||
if fundingTxID == nil {
|
||||
if bytes.Compare(paymentHash, request.PaymentHash) == 0 {
|
||||
fundingTxID, fundingTxOutnum, err = openChannel(clientCtx, client, request.PaymentHash, destination, incomingAmountMsat)
|
||||
log.Printf("openChannel(%x, %v) err: %v", destination, incomingAmountMsat, err)
|
||||
if err != nil {
|
||||
@@ -122,6 +141,18 @@ func intercept() {
|
||||
})
|
||||
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{
|
||||
IncomingCircuitKey: request.IncomingCircuitKey,
|
||||
Action: routerrpc.ResolveHoldForwardAction_FAIL,
|
||||
FailureCode: failureCode,
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
pubKey, err := btcec.ParsePubKey(destination, btcec.S256())
|
||||
|
||||
@@ -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