Merge pull request #3172 from joostjager/sendtoroute-timeout

routing+lnrpc: move default payment timeout out of router
This commit is contained in:
Wilmer Paulino 2019-06-11 16:27:19 -07:00 committed by GitHub
commit c4546081c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 25 additions and 20 deletions

@ -182,10 +182,10 @@ func (p *paymentLifecycle) resumePayment() ([32]byte, *route.Route, error) {
func (p *paymentLifecycle) createNewPaymentAttempt() (lnwire.ShortChannelID, func (p *paymentLifecycle) createNewPaymentAttempt() (lnwire.ShortChannelID,
*lnwire.UpdateAddHTLC, error) { *lnwire.UpdateAddHTLC, error) {
// Before we attempt this next payment, we'll check to see if // Before we attempt this next payment, we'll check to see if either
// either we've gone past the payment attempt timeout, or the // we've gone past the payment attempt timeout, or the router is
// router is exiting. In either case, we'll stop this payment // exiting. In either case, we'll stop this payment attempt short. If a
// attempt short. // timeout is not applicable, timeoutChan will be nil.
select { select {
case <-p.timeoutChan: case <-p.timeoutChan:
// Mark the payment as failed because of the // Mark the payment as failed because of the

@ -29,10 +29,10 @@ import (
) )
const ( const (
// defaultPayAttemptTimeout is a duration that we'll use to determine // DefaultPayAttemptTimeout is the default payment attempt timeout. The
// if we should give up on a payment attempt. This will be used if a // payment attempt timeout defines the duration after which we stop
// value isn't specified in the LightningNode struct. // trying more routes for a payment.
defaultPayAttemptTimeout = time.Duration(time.Second * 60) DefaultPayAttemptTimeout = time.Duration(time.Second * 60)
// DefaultChannelPruneExpiry is the default duration used to determine // DefaultChannelPruneExpiry is the default duration used to determine
// if a channel should be pruned or not. // if a channel should be pruned or not.
@ -525,6 +525,9 @@ func (r *ChannelRouter) Start() error {
// We create a dummy, empty payment session such that // We create a dummy, empty payment session such that
// we won't make another payment attempt when the // we won't make another payment attempt when the
// result for the in-flight attempt is received. // result for the in-flight attempt is received.
//
// PayAttemptTime doesn't need to be set, as there is
// only a single attempt.
paySession := r.cfg.MissionControl.NewPaymentSessionEmpty() paySession := r.cfg.MissionControl.NewPaymentSessionEmpty()
lPayment := &LightningPayment{ lPayment := &LightningPayment{
@ -1532,7 +1535,8 @@ type LightningPayment struct {
// PayAttemptTimeout is a timeout value that we'll use to determine // PayAttemptTimeout is a timeout value that we'll use to determine
// when we should should abandon the payment attempt after consecutive // when we should should abandon the payment attempt after consecutive
// payment failure. This prevents us from attempting to send a payment // payment failure. This prevents us from attempting to send a payment
// indefinitely. // indefinitely. A zero value means the payment will never time out.
//
// TODO(halseth): make wallclock time to allow resume after startup. // TODO(halseth): make wallclock time to allow resume after startup.
PayAttemptTimeout time.Duration PayAttemptTimeout time.Duration
@ -1661,8 +1665,11 @@ func (r *ChannelRouter) SendToRoute(hash lntypes.Hash, route *route.Route) (
// Create a (mostly) dummy payment, as the created payment session is // Create a (mostly) dummy payment, as the created payment session is
// not going to do path finding. // not going to do path finding.
// TODO(halseth): sendPayment doesn't relly need LightningPayment, make // TODO(halseth): sendPayment doesn't really need LightningPayment, make
// it take just needed fields instead. // it take just needed fields instead.
//
// PayAttemptTime doesn't need to be set, as there is only a single
// attempt.
payment := &LightningPayment{ payment := &LightningPayment{
PaymentHash: hash, PaymentHash: hash,
} }
@ -1728,22 +1735,12 @@ func (r *ChannelRouter) sendPayment(
return [32]byte{}, nil, err return [32]byte{}, nil, err
} }
var payAttemptTimeout time.Duration
if payment.PayAttemptTimeout == time.Duration(0) {
payAttemptTimeout = defaultPayAttemptTimeout
} else {
payAttemptTimeout = payment.PayAttemptTimeout
}
timeoutChan := time.After(payAttemptTimeout)
// Now set up a paymentLifecycle struct with these params, such that we // Now set up a paymentLifecycle struct with these params, such that we
// can resume the payment from the current state. // can resume the payment from the current state.
p := &paymentLifecycle{ p := &paymentLifecycle{
router: r, router: r,
payment: payment, payment: payment,
paySession: paySession, paySession: paySession,
timeoutChan: timeoutChan,
currentHeight: currentHeight, currentHeight: currentHeight,
finalCLTVDelta: uint16(payment.FinalCLTVDelta), finalCLTVDelta: uint16(payment.FinalCLTVDelta),
attempt: existingAttempt, attempt: existingAttempt,
@ -1751,6 +1748,13 @@ func (r *ChannelRouter) sendPayment(
lastError: nil, lastError: nil,
} }
// If a timeout is specified, create a timeout channel. If no timeout is
// specified, the channel is left nil and will never abort the payment
// loop.
if payment.PayAttemptTimeout != 0 {
p.timeoutChan = time.After(payment.PayAttemptTimeout)
}
return p.resumePayment() return p.resumePayment()
} }

@ -3070,6 +3070,7 @@ func (r *rpcServer) dispatchPaymentIntent(
RouteHints: payIntent.routeHints, RouteHints: payIntent.routeHints,
OutgoingChannelID: payIntent.outgoingChannelID, OutgoingChannelID: payIntent.outgoingChannelID,
PaymentRequest: payIntent.payReq, PaymentRequest: payIntent.payReq,
PayAttemptTimeout: routing.DefaultPayAttemptTimeout,
} }
preImage, route, routerErr = r.server.chanRouter.SendPayment( preImage, route, routerErr = r.server.chanRouter.SendPayment(