Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

routing+rpc: enable senders to set a custom first-hop TLV blob for update_add_htlc #8618

Open
3 tasks
Roasbeef opened this issue Apr 3, 2024 · 3 comments · May be fixed by #8660
Open
3 tasks

routing+rpc: enable senders to set a custom first-hop TLV blob for update_add_htlc #8618

Roasbeef opened this issue Apr 3, 2024 · 3 comments · May be fixed by #8660
Assignees
Labels
enhancement Improvements to existing features / behaviour protocol routing tlv

Comments

@Roasbeef
Copy link
Member

Roasbeef commented Apr 3, 2024

Protocol improvement proposals such as the endorsement bit require the ability for an implementation to set a new TLV value (so far none are used) within the update_add_htlc message. We should add such an ability to facilitate such improvement proposals.

Today the LightningPayment struct houses all payment details requested by the sender, we can set a custom TLV blob for the last hop, but not yet the first hop:

lnd/routing/router.go

Lines 2228 to 2329 in b117551

// LightningPayment describes a payment to be sent through the network to the
// final destination.
type LightningPayment struct {
// Target is the node in which the payment should be routed towards.
Target route.Vertex
// Amount is the value of the payment to send through the network in
// milli-satoshis.
Amount lnwire.MilliSatoshi
// FeeLimit is the maximum fee in millisatoshis that the payment should
// accept when sending it through the network. The payment will fail
// if there isn't a route with lower fees than this limit.
FeeLimit lnwire.MilliSatoshi
// CltvLimit is the maximum time lock that is allowed for attempts to
// complete this payment.
CltvLimit uint32
// paymentHash is the r-hash value to use within the HTLC extended to
// the first hop. This won't be set for AMP payments.
paymentHash *lntypes.Hash
// amp is an optional field that is set if and only if this is am AMP
// payment.
amp *AMPOptions
// FinalCLTVDelta is the CTLV expiry delta to use for the _final_ hop
// in the route. This means that the final hop will have a CLTV delta
// of at least: currentHeight + FinalCLTVDelta.
FinalCLTVDelta uint16
// PayAttemptTimeout is a timeout value that we'll use to determine
// when we should should abandon the payment attempt after consecutive
// payment failure. This prevents us from attempting to send a payment
// indefinitely. A zero value means the payment will never time out.
//
// TODO(halseth): make wallclock time to allow resume after startup.
PayAttemptTimeout time.Duration
// RouteHints represents the different routing hints that can be used to
// assist a payment in reaching its destination successfully. These
// hints will act as intermediate hops along the route.
//
// NOTE: This is optional unless required by the payment. When providing
// multiple routes, ensure the hop hints within each route are chained
// together and sorted in forward order in order to reach the
// destination successfully.
RouteHints [][]zpay32.HopHint
// OutgoingChannelIDs is the list of channels that are allowed for the
// first hop. If nil, any channel may be used.
OutgoingChannelIDs []uint64
// LastHop is the pubkey of the last node before the final destination
// is reached. If nil, any node may be used.
LastHop *route.Vertex
// DestFeatures specifies the set of features we assume the final node
// has for pathfinding. Typically these will be taken directly from an
// invoice, but they can also be manually supplied or assumed by the
// sender. If a nil feature vector is provided, the router will try to
// fallback to the graph in order to load a feature vector for a node in
// the public graph.
DestFeatures *lnwire.FeatureVector
// PaymentAddr is the payment address specified by the receiver. This
// field should be a random 32-byte nonce presented in the receiver's
// invoice to prevent probing of the destination.
PaymentAddr *[32]byte
// PaymentRequest is an optional payment request that this payment is
// attempting to complete.
PaymentRequest []byte
// DestCustomRecords are TLV records that are to be sent to the final
// hop in the new onion payload format. If the destination does not
// understand this new onion payload format, then the payment will
// fail.
DestCustomRecords record.CustomSet
// MaxParts is the maximum number of partial payments that may be used
// to complete the full amount.
MaxParts uint32
// MaxShardAmt is the largest shard that we'll attempt to split using.
// If this field is set, and we need to split, rather than attempting
// half of the original payment amount, we'll use this value if half
// the payment amount is greater than it.
//
// NOTE: This field is _optional_.
MaxShardAmt *lnwire.MilliSatoshi
// TimePref is the time preference for this payment. Set to -1 to
// optimize for fees only, to 1 to optimize for reliability only or a
// value in between for a mix.
TimePref float64
// Metadata is additional data that is sent along with the payment to
// the payee.
Metadata []byte
}

We should add another custom blob here, then ensure that we include it once we go to make the UpdateAddHTLC message to send to the first hop:

// Craft an HTLC packet to send to the htlcswitch. The metadata within
// this packet will be used to route the payment through the network,
// starting with the first-hop.
htlcAdd := &lnwire.UpdateAddHTLC{
Amount: rt.TotalAmount,
Expiry: rt.TotalTimeLock,
PaymentHash: *attempt.Hash,
}
// Generate the raw encoded sphinx packet to be included along
// with the htlcAdd message that we send directly to the
// switch.
onionBlob, _, err := generateSphinxPacket(
&rt, attempt.Hash[:], attempt.SessionKey(),
)
if err != nil {
log.Errorf("Failed to create onion blob: attempt=%d in "+
"payment=%v, err:%v", attempt.AttemptID,
p.identifier, err)
return p.failAttempt(attempt.AttemptID, err)
}
copy(htlcAdd.OnionBlob[:], onionBlob)
// Send it to the Switch. When this method returns we assume
// the Switch successfully has persisted the payment attempt,
// such that we can resume waiting for the result after a
// restart.
err = p.router.cfg.Payer.SendHTLC(firstHop, attempt.AttemptID, htlcAdd)

Steps To Completion

  • Add new field to LightningPayment

  • Thread through context to the paymentLifecycle struct.

  • Add a slim RPC cut out so we can write an itest in addition to unit tests. The itest can set a custom value for the first hop, then use the HTLCInterceptor to ensure that the value was properly set.

@Roasbeef Roasbeef added enhancement Improvements to existing features / behaviour routing tlv protocol labels Apr 3, 2024
@dstadulis
Copy link
Collaborator

@GeorgeTsagk will work on this
@saubyk will assign soon

@carlaKC
Copy link
Collaborator

carlaKC commented Apr 15, 2024

👀 sign me up for some review when this is ready

@dstadulis
Copy link
Collaborator

fixed by #8660

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Improvements to existing features / behaviour protocol routing tlv
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants