mirror of
https://github.com/aljazceru/lspd.git
synced 2026-02-18 12:34:22 +01:00
move lnd specific onion creation to lnd
This commit is contained in:
@@ -14,12 +14,7 @@ import (
|
||||
"github.com/breez/lspd/config"
|
||||
"github.com/breez/lspd/lightning"
|
||||
"github.com/breez/lspd/notifications"
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
sphinx "github.com/lightningnetwork/lightning-onion"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/record"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"golang.org/x/sync/singleflight"
|
||||
)
|
||||
|
||||
@@ -40,13 +35,14 @@ var (
|
||||
)
|
||||
|
||||
type InterceptResult struct {
|
||||
Action InterceptAction
|
||||
FailureCode InterceptFailureCode
|
||||
Destination []byte
|
||||
AmountMsat uint64
|
||||
ChannelPoint *wire.OutPoint
|
||||
ChannelId uint64
|
||||
OnionBlob []byte
|
||||
Action InterceptAction
|
||||
FailureCode InterceptFailureCode
|
||||
Destination []byte
|
||||
AmountMsat uint64
|
||||
TotalAmountMsat uint64
|
||||
ChannelPoint *wire.OutPoint
|
||||
ChannelId uint64
|
||||
PaymentSecret []byte
|
||||
}
|
||||
|
||||
type Interceptor struct {
|
||||
@@ -230,81 +226,9 @@ func (i *Interceptor) Intercept(scid *basetypes.ShortChannelID, reqPaymentHash [
|
||||
}
|
||||
}
|
||||
|
||||
pubKey, err := btcec.ParsePubKey(destination)
|
||||
if err != nil {
|
||||
log.Printf("btcec.ParsePubKey(%x): %v", destination, err)
|
||||
return InterceptResult{
|
||||
Action: INTERCEPT_FAIL_HTLC_WITH_CODE,
|
||||
FailureCode: FAILURE_TEMPORARY_CHANNEL_FAILURE,
|
||||
}, nil
|
||||
}
|
||||
|
||||
sessionKey, err := btcec.NewPrivateKey()
|
||||
if err != nil {
|
||||
log.Printf("btcec.NewPrivateKey(): %v", err)
|
||||
return InterceptResult{
|
||||
Action: INTERCEPT_FAIL_HTLC_WITH_CODE,
|
||||
FailureCode: FAILURE_TEMPORARY_CHANNEL_FAILURE,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var bigProd, bigAmt big.Int
|
||||
amt := (bigAmt.Div(bigProd.Mul(big.NewInt(outgoingAmountMsat), big.NewInt(int64(reqOutgoingAmountMsat))), big.NewInt(incomingAmountMsat))).Int64()
|
||||
|
||||
var addr [32]byte
|
||||
copy(addr[:], paymentSecret)
|
||||
hop := route.Hop{
|
||||
AmtToForward: lnwire.MilliSatoshi(amt),
|
||||
OutgoingTimeLock: reqOutgoingExpiry,
|
||||
MPP: record.NewMPP(lnwire.MilliSatoshi(outgoingAmountMsat), addr),
|
||||
CustomRecords: make(record.CustomSet),
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
err = hop.PackHopPayload(&b, uint64(0))
|
||||
if err != nil {
|
||||
log.Printf("hop.PackHopPayload(): %v", err)
|
||||
return InterceptResult{
|
||||
Action: INTERCEPT_FAIL_HTLC_WITH_CODE,
|
||||
FailureCode: FAILURE_TEMPORARY_CHANNEL_FAILURE,
|
||||
}, nil
|
||||
}
|
||||
|
||||
payload, err := sphinx.NewHopPayload(nil, b.Bytes())
|
||||
if err != nil {
|
||||
log.Printf("sphinx.NewHopPayload(): %v", err)
|
||||
return InterceptResult{
|
||||
Action: INTERCEPT_FAIL_HTLC_WITH_CODE,
|
||||
FailureCode: FAILURE_TEMPORARY_CHANNEL_FAILURE,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var sphinxPath sphinx.PaymentPath
|
||||
sphinxPath[0] = sphinx.OnionHop{
|
||||
NodePub: *pubKey,
|
||||
HopPayload: payload,
|
||||
}
|
||||
sphinxPacket, err := sphinx.NewOnionPacket(
|
||||
&sphinxPath, sessionKey, reqPaymentHash,
|
||||
sphinx.DeterministicPacketFiller,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("sphinx.NewOnionPacket(): %v", err)
|
||||
return InterceptResult{
|
||||
Action: INTERCEPT_FAIL_HTLC_WITH_CODE,
|
||||
FailureCode: FAILURE_TEMPORARY_CHANNEL_FAILURE,
|
||||
}, nil
|
||||
}
|
||||
var onionBlob bytes.Buffer
|
||||
err = sphinxPacket.Encode(&onionBlob)
|
||||
if err != nil {
|
||||
log.Printf("sphinxPacket.Encode(): %v", err)
|
||||
return InterceptResult{
|
||||
Action: INTERCEPT_FAIL_HTLC_WITH_CODE,
|
||||
FailureCode: FAILURE_TEMPORARY_CHANNEL_FAILURE,
|
||||
}, nil
|
||||
}
|
||||
|
||||
deadline := time.Now().Add(60 * time.Second)
|
||||
|
||||
for {
|
||||
@@ -334,12 +258,13 @@ func (i *Interceptor) Intercept(scid *basetypes.ShortChannelID, reqPaymentHash [
|
||||
}
|
||||
|
||||
return InterceptResult{
|
||||
Action: INTERCEPT_RESUME_WITH_ONION,
|
||||
Destination: destination,
|
||||
ChannelPoint: channelPoint,
|
||||
ChannelId: channelID,
|
||||
AmountMsat: uint64(amt),
|
||||
OnionBlob: onionBlob.Bytes(),
|
||||
Action: INTERCEPT_RESUME_WITH_ONION,
|
||||
Destination: destination,
|
||||
ChannelPoint: channelPoint,
|
||||
ChannelId: channelID,
|
||||
PaymentSecret: paymentSecret,
|
||||
AmountMsat: uint64(amt),
|
||||
TotalAmountMsat: uint64(outgoingAmountMsat),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package lnd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"log"
|
||||
"sync"
|
||||
@@ -9,8 +10,13 @@ import (
|
||||
"github.com/breez/lspd/basetypes"
|
||||
"github.com/breez/lspd/config"
|
||||
"github.com/breez/lspd/interceptor"
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
sphinx "github.com/lightningnetwork/lightning-onion"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/record"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
@@ -133,13 +139,23 @@ func (i *LndHtlcInterceptor) intercept() error {
|
||||
interceptResult := i.interceptor.Intercept(&scid, request.PaymentHash, request.OutgoingAmountMsat, request.OutgoingExpiry, request.IncomingExpiry)
|
||||
switch interceptResult.Action {
|
||||
case interceptor.INTERCEPT_RESUME_WITH_ONION:
|
||||
interceptorClient.Send(&routerrpc.ForwardHtlcInterceptResponse{
|
||||
IncomingCircuitKey: request.IncomingCircuitKey,
|
||||
Action: routerrpc.ResolveHoldForwardAction_RESUME,
|
||||
OutgoingAmountMsat: interceptResult.AmountMsat,
|
||||
OutgoingRequestedChanId: uint64(interceptResult.ChannelId),
|
||||
OnionBlob: interceptResult.OnionBlob,
|
||||
})
|
||||
onion, err := i.constructOnion(interceptResult, request.OutgoingExpiry, request.PaymentHash)
|
||||
if err == nil {
|
||||
interceptorClient.Send(&routerrpc.ForwardHtlcInterceptResponse{
|
||||
IncomingCircuitKey: request.IncomingCircuitKey,
|
||||
Action: routerrpc.ResolveHoldForwardAction_RESUME,
|
||||
OutgoingAmountMsat: interceptResult.AmountMsat,
|
||||
OutgoingRequestedChanId: uint64(interceptResult.ChannelId),
|
||||
OnionBlob: onion,
|
||||
})
|
||||
} else {
|
||||
interceptorClient.Send(&routerrpc.ForwardHtlcInterceptResponse{
|
||||
IncomingCircuitKey: request.IncomingCircuitKey,
|
||||
Action: routerrpc.ResolveHoldForwardAction_FAIL,
|
||||
FailureCode: lnrpc.Failure_TEMPORARY_CHANNEL_FAILURE,
|
||||
})
|
||||
}
|
||||
|
||||
case interceptor.INTERCEPT_FAIL_HTLC_WITH_CODE:
|
||||
interceptorClient.Send(&routerrpc.ForwardHtlcInterceptResponse{
|
||||
IncomingCircuitKey: request.IncomingCircuitKey,
|
||||
@@ -179,3 +195,65 @@ func (i *LndHtlcInterceptor) mapFailureCode(original interceptor.InterceptFailur
|
||||
return lnrpc.Failure_TEMPORARY_CHANNEL_FAILURE
|
||||
}
|
||||
}
|
||||
|
||||
func (i *LndHtlcInterceptor) constructOnion(
|
||||
interceptResult interceptor.InterceptResult,
|
||||
reqOutgoingExpiry uint32,
|
||||
reqPaymentHash []byte,
|
||||
) ([]byte, error) {
|
||||
pubKey, err := btcec.ParsePubKey(interceptResult.Destination)
|
||||
if err != nil {
|
||||
log.Printf("btcec.ParsePubKey(%x): %v", interceptResult.Destination, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sessionKey, err := btcec.NewPrivateKey()
|
||||
if err != nil {
|
||||
log.Printf("btcec.NewPrivateKey(): %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var addr [32]byte
|
||||
copy(addr[:], interceptResult.PaymentSecret)
|
||||
hop := route.Hop{
|
||||
AmtToForward: lnwire.MilliSatoshi(interceptResult.AmountMsat),
|
||||
OutgoingTimeLock: reqOutgoingExpiry,
|
||||
MPP: record.NewMPP(lnwire.MilliSatoshi(interceptResult.TotalAmountMsat), addr),
|
||||
CustomRecords: make(record.CustomSet),
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
err = hop.PackHopPayload(&b, uint64(0))
|
||||
if err != nil {
|
||||
log.Printf("hop.PackHopPayload(): %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
payload, err := sphinx.NewHopPayload(nil, b.Bytes())
|
||||
if err != nil {
|
||||
log.Printf("sphinx.NewHopPayload(): %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var sphinxPath sphinx.PaymentPath
|
||||
sphinxPath[0] = sphinx.OnionHop{
|
||||
NodePub: *pubKey,
|
||||
HopPayload: payload,
|
||||
}
|
||||
sphinxPacket, err := sphinx.NewOnionPacket(
|
||||
&sphinxPath, sessionKey, reqPaymentHash,
|
||||
sphinx.DeterministicPacketFiller,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("sphinx.NewOnionPacket(): %v", err)
|
||||
return nil, err
|
||||
}
|
||||
var onionBlob bytes.Buffer
|
||||
err = sphinxPacket.Encode(&onionBlob)
|
||||
if err != nil {
|
||||
log.Printf("sphinxPacket.Encode(): %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return onionBlob.Bytes(), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user