routerrpc+routing: set AMP options for payments specified as AMP in SendPayment

This commit is contained in:
Johan T. Halseth 2021-03-31 12:44:59 +02:00
parent 8f57dcf28f
commit c4fc72d573
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26
2 changed files with 94 additions and 16 deletions

@ -2,6 +2,7 @@ package routerrpc
import ( import (
"context" "context"
"crypto/rand"
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
@ -741,17 +742,6 @@ func (r *RouterBackend) extractIntentFromSendRequest(
payIntent.Amount = reqAmt payIntent.Amount = reqAmt
// Payment hash.
paymentHash, err := lntypes.MakeHash(rpcPayReq.PaymentHash)
if err != nil {
return nil, err
}
err = payIntent.SetPaymentHash(paymentHash)
if err != nil {
return nil, err
}
// Parse destination feature bits. // Parse destination feature bits.
features, err := UnmarshalFeatures(rpcPayReq.DestFeatures) features, err := UnmarshalFeatures(rpcPayReq.DestFeatures)
if err != nil { if err != nil {
@ -766,13 +756,82 @@ func (r *RouterBackend) extractIntentFromSendRequest(
} }
} }
// If the payment addresses is specified, then we'll also // If this is an AMP payment, we must generate the initial
// populate that now as well. // randomness.
if len(rpcPayReq.PaymentAddr) != 0 { if rpcPayReq.Amp {
var payAddr [32]byte // If no destination features were specified, we set
copy(payAddr[:], rpcPayReq.PaymentAddr) // those necessary for AMP payments.
if features == nil {
ampFeatures := []lnrpc.FeatureBit{
lnrpc.FeatureBit_TLV_ONION_OPT,
lnrpc.FeatureBit_PAYMENT_ADDR_OPT,
lnrpc.FeatureBit_MPP_OPT,
lnrpc.FeatureBit_AMP_OPT,
}
features, err = UnmarshalFeatures(ampFeatures)
if err != nil {
return nil, err
}
}
// First make sure the destination supports AMP.
if !features.HasFeature(lnwire.AMPOptional) {
return nil, fmt.Errorf("destination doesn't " +
"support AMP payments")
}
// If no payment address is set, generate a random one.
var payAddr [32]byte
if len(rpcPayReq.PaymentAddr) == 0 {
_, err = rand.Read(payAddr[:])
if err != nil {
return nil, err
}
} else {
copy(payAddr[:], rpcPayReq.PaymentAddr)
}
payIntent.PaymentAddr = &payAddr payIntent.PaymentAddr = &payAddr
// Generate random SetID and root share.
var setID [32]byte
_, err = rand.Read(setID[:])
if err != nil {
return nil, err
}
var rootShare [32]byte
_, err = rand.Read(rootShare[:])
if err != nil {
return nil, err
}
err := payIntent.SetAMP(&routing.AMPOptions{
SetID: setID,
RootShare: rootShare,
})
if err != nil {
return nil, err
}
} else {
// Payment hash.
paymentHash, err := lntypes.MakeHash(rpcPayReq.PaymentHash)
if err != nil {
return nil, err
}
err = payIntent.SetPaymentHash(paymentHash)
if err != nil {
return nil, err
}
// If the payment addresses is specified, then we'll
// also populate that now as well.
if len(rpcPayReq.PaymentAddr) != 0 {
var payAddr [32]byte
copy(payAddr[:], rpcPayReq.PaymentAddr)
payIntent.PaymentAddr = &payAddr
}
} }
payIntent.DestFeatures = features payIntent.DestFeatures = features

@ -1806,14 +1806,33 @@ type AMPOptions struct {
// SetPaymentHash sets the given hash as the payment's overall hash. This // SetPaymentHash sets the given hash as the payment's overall hash. This
// should only be used for non-AMP payments. // should only be used for non-AMP payments.
func (l *LightningPayment) SetPaymentHash(hash lntypes.Hash) error { func (l *LightningPayment) SetPaymentHash(hash lntypes.Hash) error {
if l.amp != nil {
return fmt.Errorf("cannot set payment hash for AMP payment")
}
l.paymentHash = &hash l.paymentHash = &hash
return nil return nil
} }
// SetAMP sets the given AMP options for the payment.
func (l *LightningPayment) SetAMP(amp *AMPOptions) error {
if l.paymentHash != nil {
return fmt.Errorf("cannot set amp options for payment " +
"with payment hash")
}
l.amp = amp
return nil
}
// Identifier returns a 32-byte slice that uniquely identifies this single // Identifier returns a 32-byte slice that uniquely identifies this single
// payment. For non-AMP payments this will be the payment hash, for AMP // payment. For non-AMP payments this will be the payment hash, for AMP
// payments this will be the used SetID. // payments this will be the used SetID.
func (l *LightningPayment) Identifier() [32]byte { func (l *LightningPayment) Identifier() [32]byte {
if l.amp != nil {
return l.amp.SetID
}
return *l.paymentHash return *l.paymentHash
} }