@ -4,9 +4,12 @@ import (
"context"
"encoding/hex"
"fmt"
"log"
"math/rand"
"time"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
)
func calcFeeMsat ( amtMsat int64 , policy * lnrpc . RoutingPolicy ) float64 {
@ -73,16 +76,16 @@ func (r *regolancer) printRoute(route *lnrpc.Route) {
return
}
errs := ""
fmt . Printf ( "%s %s\n" , faintWhiteColor ( "Total fee:" ) , hiWhiteColor ( ( route . TotalFeesMsat - route . Hops [ 0 ] . FeeMsat ) / 1000 ) )
fmt . Printf ( "%s %s\n" , faintWhiteColor ( "Total fee:" ) , hiWhiteColor ( route . TotalFeesMsat / 1000 ) )
for i , hop := range route . Hops {
nodeInfo , err := r . getNodeInfo ( hop . PubKey )
if err != nil {
errs = errs + err . Error ( ) + "\n"
continue
}
fee := hiWhiteColorF ( "%-6 d", hop . FeeMsat )
if i == 0 {
fee = hiWhiteColorF ( "%-6s" , "" )
fee := hiWhiteColorF ( "%-6 s", "" )
if i > 0 {
hiWhiteColorF ( "%-6d" , route . Hops [ i - 1 ] . FeeMsat )
}
fmt . Printf ( "%s %s %s\n" , faintWhiteColor ( hop . ChanId ) , fee , cyanColor ( nodeInfo . Node . Alias ) )
}
@ -90,3 +93,70 @@ func (r *regolancer) printRoute(route *lnrpc.Route) {
fmt . Println ( errColor ( errs ) )
}
}
func ( r * regolancer ) rebuildRoute ( route * lnrpc . Route , amount int64 ) ( * lnrpc . Route , error ) {
pks := [ ] [ ] byte { }
for _ , h := range route . Hops {
pk , _ := hex . DecodeString ( h . PubKey )
pks = append ( pks , pk )
}
resultRoute , err := r . routerClient . BuildRoute ( context . Background ( ) , & routerrpc . BuildRouteRequest {
AmtMsat : amount * 1000 ,
OutgoingChanId : route . Hops [ 0 ] . ChanId ,
HopPubkeys : pks ,
FinalCltvDelta : 144 ,
} )
return resultRoute . Route , err
}
func ( r * regolancer ) probeRoute ( route * lnrpc . Route , goodAmount , badAmount , amount int64 , steps int ) ( maxAmount int64 ,
goodRoute * lnrpc . Route , err error ) {
goodRoute , err = r . rebuildRoute ( route , amount )
if err != nil {
return 0 , nil , err
}
fakeHash := make ( [ ] byte , 32 )
rand . Read ( fakeHash )
result , err := r . routerClient . SendToRouteV2 ( context . Background ( ) ,
& routerrpc . SendToRouteRequest {
PaymentHash : fakeHash ,
Route : goodRoute ,
} )
if err != nil {
return
}
if result . Status == lnrpc . HTLCAttempt_SUCCEEDED {
return 0 , nil , fmt . Errorf ( "this should never happen" )
}
if result . Status == lnrpc . HTLCAttempt_FAILED {
if result . Failure . Code == lnrpc . Failure_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS { // payment can succeed
if steps == 1 || amount == badAmount {
log . Printf ( "%s is the best amount" , hiWhiteColor ( amount ) )
return amount , goodRoute , nil
}
nextAmount := amount + ( badAmount - amount ) / 2
log . Printf ( "%s is good enough, trying amount %s, %s steps left" ,
hiWhiteColor ( amount ) , hiWhiteColor ( nextAmount ) , hiWhiteColor ( steps - 1 ) )
return r . probeRoute ( route , amount , badAmount , nextAmount , steps - 1 )
}
if result . Failure . Code == lnrpc . Failure_TEMPORARY_CHANNEL_FAILURE {
if steps == 1 {
bestAmount := hiWhiteColor ( goodAmount )
if goodAmount == 0 {
bestAmount = hiWhiteColor ( "unknown" )
}
log . Printf ( "%s is too much, best amount is %s" , hiWhiteColor ( amount ) , bestAmount )
return goodAmount , goodRoute , nil
}
nextAmount := amount + ( goodAmount - amount ) / 2
log . Printf ( "%s is too much, lowering amount to %s, %s steps left" ,
hiWhiteColor ( amount ) , hiWhiteColor ( nextAmount ) , hiWhiteColor ( steps - 1 ) )
return r . probeRoute ( route , goodAmount , amount , nextAmount , steps - 1 )
}
if result . Failure . Code == lnrpc . Failure_FEE_INSUFFICIENT {
log . Printf ( "Fee insufficient, retrying..." )
return r . probeRoute ( route , goodAmount , badAmount , amount , steps )
}
}
return 0 , nil , fmt . Errorf ( "unknown error: %+v" , result )
}