multi: Fix final hop payload size for AMP payments.

This commit is contained in:
ziggie
2024-02-03 12:09:11 +00:00
parent ff30ff40bf
commit 4732c09a26
7 changed files with 44 additions and 1 deletions

View File

@@ -104,6 +104,10 @@ func testSendPaymentAMPInvoiceCase(ht *lntest.HarnessTest,
// expect an extra invoice to appear in the ListInvoices response, since // expect an extra invoice to appear in the ListInvoices response, since
// a new invoice will be JIT inserted under a different payment address // a new invoice will be JIT inserted under a different payment address
// than the one in the invoice. // than the one in the invoice.
//
// NOTE: This will only work when the peer has spontaneous AMP payments
// enabled otherwise no invoice under a different payment_addr will be
// found.
var ( var (
expNumInvoices = 1 expNumInvoices = 1
externalPayAddr []byte externalPayAddr []byte

View File

@@ -967,6 +967,9 @@ func (r *RouterBackend) extractIntentFromSendRequest(
// pseudo-reusable, e.g. the invoice parameters are // pseudo-reusable, e.g. the invoice parameters are
// reused (amt, cltv, hop hints, etc) even though the // reused (amt, cltv, hop hints, etc) even though the
// payments will share different payment hashes. // payments will share different payment hashes.
//
// NOTE: This will only work when the peer has
// spontaneous AMP payments enabled.
if len(rpcPayReq.PaymentAddr) > 0 { if len(rpcPayReq.PaymentAddr) > 0 {
var addr [32]byte var addr [32]byte
copy(addr[:], rpcPayReq.PaymentAddr) copy(addr[:], rpcPayReq.PaymentAddr)

View File

@@ -19,6 +19,16 @@ type AMP struct {
childIndex uint32 childIndex uint32
} }
// MaxAmpPayLoadSize is an AMP Record which when serialized to a tlv record uses
// the maximum payload size. The `childIndex` is created randomly and is a
// 4 byte `varint` type so we make sure we use an index which will be encoded in
// 4 bytes.
var MaxAmpPayLoadSize = AMP{
rootShare: [32]byte{},
setID: [32]byte{},
childIndex: 0x80000000,
}
// NewAMP generate a new AMP record with the given root_share, set_id, and // NewAMP generate a new AMP record with the given root_share, set_id, and
// child_index. // child_index.
func NewAMP(rootShare, setID [32]byte, childIndex uint32) *AMP { func NewAMP(rootShare, setID [32]byte, childIndex uint32) *AMP {

View File

@@ -408,6 +408,11 @@ type RestrictParams struct {
// invoices. // invoices.
PaymentAddr *[32]byte PaymentAddr *[32]byte
// Amp signals to the pathfinder that this payment is an AMP payment
// and therefore it needs to account for additional AMP data in the
// final hop payload size calculation.
Amp *AMPOptions
// Metadata is additional data that is sent along with the payment to // Metadata is additional data that is sent along with the payment to
// the payee. // the payee.
Metadata []byte Metadata []byte
@@ -1134,12 +1139,21 @@ func lastHopPayloadSize(r *RestrictParams, finalHtlcExpiry int32,
mpp = record.NewMPP(amount, *r.PaymentAddr) mpp = record.NewMPP(amount, *r.PaymentAddr)
} }
var amp *record.AMP
if r.Amp != nil {
// The AMP payload is not easy accessible at this point but we
// are only interested in the size of the payload so we just use
// the AMP record dummy.
amp = &record.MaxAmpPayLoadSize
}
finalHop := route.Hop{ finalHop := route.Hop{
AmtToForward: amount, AmtToForward: amount,
OutgoingTimeLock: uint32(finalHtlcExpiry), OutgoingTimeLock: uint32(finalHtlcExpiry),
CustomRecords: r.DestCustomRecords, CustomRecords: r.DestCustomRecords,
LegacyPayload: legacy, LegacyPayload: legacy,
MPP: mpp, MPP: mpp,
AMP: amp,
Metadata: r.Metadata, Metadata: r.Metadata,
} }

View File

@@ -3469,6 +3469,7 @@ func TestLastHopPayloadSize(t *testing.T) {
) )
_, blindedPoint = btcec.PrivKeyFromBytes([]byte{5}) _, blindedPoint = btcec.PrivKeyFromBytes([]byte{5})
paymentAddr = &[32]byte{1} paymentAddr = &[32]byte{1}
ampOptions = &AMPOptions{}
amtToForward = lnwire.MilliSatoshi(10000) amtToForward = lnwire.MilliSatoshi(10000)
finalHopExpiry int32 = 144 finalHopExpiry int32 = 144
@@ -3510,6 +3511,7 @@ func TestLastHopPayloadSize(t *testing.T) {
PaymentAddr: paymentAddr, PaymentAddr: paymentAddr,
DestCustomRecords: customRecords, DestCustomRecords: customRecords,
Metadata: metadata, Metadata: metadata,
Amp: ampOptions,
}, },
amount: amtToForward, amount: amtToForward,
finalHopExpiry: finalHopExpiry, finalHopExpiry: finalHopExpiry,
@@ -3524,6 +3526,7 @@ func TestLastHopPayloadSize(t *testing.T) {
PaymentAddr: paymentAddr, PaymentAddr: paymentAddr,
DestCustomRecords: customRecords, DestCustomRecords: customRecords,
Metadata: metadata, Metadata: metadata,
Amp: ampOptions,
}, },
amount: amtToForward, amount: amtToForward,
finalHopExpiry: finalHopExpiry, finalHopExpiry: finalHopExpiry,
@@ -3560,6 +3563,13 @@ func TestLastHopPayloadSize(t *testing.T) {
) )
} }
// In case it's an AMP payment we use the max AMP record
// size to estimate the final hop size.
var amp *record.AMP
if tc.restrictions.Amp != nil {
amp = &record.MaxAmpPayLoadSize
}
var finalHop route.Hop var finalHop route.Hop
if tc.restrictions.BlindedPayment != nil { if tc.restrictions.BlindedPayment != nil {
blindedPath := tc.restrictions.BlindedPayment. blindedPath := tc.restrictions.BlindedPayment.
@@ -3586,6 +3596,7 @@ func TestLastHopPayloadSize(t *testing.T) {
OutgoingTimeLock: uint32(tc.finalHopExpiry), OutgoingTimeLock: uint32(tc.finalHopExpiry),
Metadata: tc.restrictions.Metadata, Metadata: tc.restrictions.Metadata,
MPP: mpp, MPP: mpp,
AMP: amp,
CustomRecords: tc.restrictions.DestCustomRecords, CustomRecords: tc.restrictions.DestCustomRecords,
} }
} }

View File

@@ -628,7 +628,7 @@ func (p *paymentLifecycle) createNewPaymentAttempt(rt *route.Route,
return nil, err return nil, err
} }
// It this shard carries MPP or AMP options, add them to the last hop // If this shard carries MPP or AMP options, add them to the last hop
// on the route. // on the route.
hop := rt.Hops[len(rt.Hops)-1] hop := rt.Hops[len(rt.Hops)-1]
if shard.MPP() != nil { if shard.MPP() != nil {

View File

@@ -258,6 +258,7 @@ func (p *paymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi,
DestCustomRecords: p.payment.DestCustomRecords, DestCustomRecords: p.payment.DestCustomRecords,
DestFeatures: p.payment.DestFeatures, DestFeatures: p.payment.DestFeatures,
PaymentAddr: p.payment.PaymentAddr, PaymentAddr: p.payment.PaymentAddr,
Amp: p.payment.amp,
Metadata: p.payment.Metadata, Metadata: p.payment.Metadata,
} }