reuse route when fees insufficient and add rapid rebalance fee check

pull/49/head
ziggie 1 year ago
parent ec8e055340
commit a52771ddcc
No known key found for this signature in database
GPG Key ID: 1AFF9C4DCED6D666

@ -38,10 +38,16 @@ func (r *regolancer) invalidateInvoice(amount int64) {
delete(r.invoiceCache, amount)
}
func (r *regolancer) pay(ctx context.Context, amount int64, minAmount int64,
func (r *regolancer) pay(ctx context.Context, amount int64, minAmount int64, maxFeeMsat int64,
route *lnrpc.Route, probeSteps int) error {
fmt.Println()
defer fmt.Println()
if route.TotalFeesMsat > maxFeeMsat {
log.Printf("fee on the route exceeds our limits: %s ppm (max fee %s ppm)", formatFeePPM(amount*1000, route.TotalFeesMsat), formatFeePPM(amount*1000, maxFeeMsat))
return fmt.Errorf("fee-limit exceeded")
}
invoice, err := r.createInvoice(ctx, amount)
if err != nil {
log.Printf("Error creating invoice: %s", err)
@ -64,6 +70,7 @@ func (r *regolancer) pay(ctx context.Context, amount int64, minAmount int64,
Route: route,
})
if err != nil {
logErrorF("error sending payment %s", err)
return err
}
if result.Status == lnrpc.HTLCAttempt_FAILED {
@ -79,6 +86,7 @@ func (r *regolancer) pay(ctx context.Context, amount int64, minAmount int64,
return fmt.Errorf("error: %s @ %d", result.Failure.Code.String(),
result.Failure.FailureSourceIndex)
}
prevHop := route.Hops[result.Failure.FailureSourceIndex-1]
failedHop := route.Hops[result.Failure.FailureSourceIndex]
nodeCtx, cancel := context.WithTimeout(ctx, time.Second*time.Duration(params.TimeoutInfo))
@ -98,6 +106,20 @@ func (r *regolancer) pay(ctx context.Context, amount int64, minAmount int64,
node2name = node2.Node.Alias
}
log.Printf("%s %s ⇒ %s", faintWhiteColor(result.Failure.Code.String()), cyanColor(node1name), cyanColor(node2name))
if result.Failure.Code == lnrpc.Failure_FEE_INSUFFICIENT || result.Failure.Code == lnrpc.Failure_INCORRECT_CLTV_EXPIRY {
failedHop := route.Hops[result.Failure.FailureSourceIndex-1]
route, err = r.rebuildRoute(ctx, route, amount)
updatedHop := route.Hops[result.Failure.FailureSourceIndex-1]
if err == nil {
// compare hops to make sure we do not loop endlessly
if !compareHops(failedHop, updatedHop) {
log.Printf("received channelupdate after failure, trying again with amt %s and fee %s ppm",
hiWhiteColor(amount), formatFeePPM(amount*1000, route.TotalFeesMsat))
return r.pay(ctx, amount, minAmount, maxFeeMsat, route, probeSteps)
}
}
}
if result.Failure.Code == lnrpc.Failure_TEMPORARY_CHANNEL_FAILURE {
r.addFailedChan(node1.Node.PubKey, node2.Node.PubKey, prevHop.
AmtToForwardMsat)

@ -28,7 +28,7 @@ func (r *regolancer) tryRebalance(ctx context.Context, attempt *int) (err error,
}
routeCtx, routeCtxCancel := context.WithTimeout(attemptCtx, time.Second*time.Duration(params.TimeoutRoute))
defer routeCtxCancel()
routes, feeMsat, err := r.getRoutes(routeCtx, from, to, amt*1000)
routes, maxFeeMsat, err := r.getRoutes(routeCtx, from, to, amt*1000)
if err != nil {
if routeCtx.Err() == context.DeadlineExceeded {
log.Print(errColor("Timed out looking for a route"))
@ -40,9 +40,9 @@ func (r *regolancer) tryRebalance(ctx context.Context, attempt *int) (err error,
routeCtxCancel()
for _, route := range routes {
log.Printf("Attempt %s, amount: %s (max fee: %s sat | %s ppm )",
hiWhiteColorF("#%d", *attempt), hiWhiteColor(amt), formatFee(feeMsat), formatFeePPM(amt*1000, feeMsat))
hiWhiteColorF("#%d", *attempt), hiWhiteColor(amt), formatFee(maxFeeMsat), formatFeePPM(amt*1000, maxFeeMsat))
r.printRoute(attemptCtx, route)
err = r.pay(attemptCtx, amt, params.MinAmount, route, params.ProbeSteps)
err = r.pay(attemptCtx, amt, params.MinAmount, maxFeeMsat, route, params.ProbeSteps)
if err == nil {
if params.AllowRapidRebalance {
@ -65,7 +65,7 @@ func (r *regolancer) tryRebalance(ctx context.Context, attempt *int) (err error,
if err != nil {
log.Printf("Error rebuilding the route for probed payment: %s", errColor(err))
} else {
err = r.pay(ctx, amt, 0, probedRoute, 0)
err = r.pay(ctx, amt, 0, maxFeeMsat, probedRoute, 0)
if err == nil {
return nil, false
} else {
@ -74,6 +74,7 @@ func (r *regolancer) tryRebalance(ctx context.Context, attempt *int) (err error,
}
}
}
*attempt++
}
attemptCancel()
@ -206,7 +207,15 @@ func (r *regolancer) tryRapidRebalance(ctx context.Context, route *lnrpc.Route)
defer attemptCancel()
err = r.pay(attemptCtx, amtLocal, params.MinAmount, routeLocal, 0)
// make sure we account for fees when increasing the rebalance amount
maxFeeMsat, _, err := r.calcFeeMsat(ctx, from, to, amtLocal*1000)
if err != nil {
log.Printf(errColor("Error calculating fee: %s"), err)
return result, err
}
err = r.pay(attemptCtx, amtLocal, params.MinAmount, maxFeeMsat, routeLocal, 0)
attemptCancel()

@ -320,3 +320,9 @@ func getTarget(route *lnrpc.Route) uint64 {
return 0
}
func compareHops(hop1 *lnrpc.Hop, hop2 *lnrpc.Hop) bool {
return hop1.ChanId == hop2.ChanId &&
hop1.FeeMsat == hop2.FeeMsat &&
hop1.Expiry == hop2.Expiry
}

Loading…
Cancel
Save