@@ -347,60 +347,35 @@ static struct amount_msat linear_flows_cost(struct flow **flows,
347
347
return total ;
348
348
}
349
349
350
- /* Returns an error message, or sets *routes */
351
- static const char * get_routes (const tal_t * ctx ,
352
- struct command * cmd ,
353
- const struct node_id * source ,
354
- const struct node_id * dest ,
355
- struct amount_msat amount ,
356
- struct amount_msat maxfee ,
357
- u32 finalcltv ,
358
- u32 maxdelay ,
359
- const char * * layers ,
360
- struct gossmap_localmods * localmods ,
361
- const struct layer * local_layer ,
362
- bool single_path ,
363
- struct route * * * routes ,
364
- struct amount_msat * * amounts ,
365
- const struct additional_cost_htable * additional_costs ,
366
- double * probability )
367
- {
368
- struct askrene * askrene = get_askrene (cmd -> plugin );
369
- struct route_query * rq = tal (ctx , struct route_query );
370
- struct flow * * flows ;
371
- const struct gossmap_node * srcnode , * dstnode ;
372
- const char * ret ;
373
- struct timerel time_delta ;
374
- struct timemono time_start = time_mono ();
375
-
376
- if (gossmap_refresh (askrene -> gossmap )) {
377
- /* FIXME: gossmap_refresh callbacks to we can update in place */
378
- tal_free (askrene -> capacities );
379
- askrene -> capacities = get_capacities (askrene , askrene -> plugin , askrene -> gossmap );
380
- }
381
-
382
- rq -> cmd = cmd ;
383
- rq -> plugin = cmd -> plugin ;
384
- rq -> gossmap = askrene -> gossmap ;
385
- rq -> reserved = askrene -> reserved ;
386
- rq -> layers = tal_arr (rq , const struct layer * , 0 );
387
- rq -> capacities = tal_dup_talarr (rq , fp16_t , askrene -> capacities );
388
- rq -> additional_costs = additional_costs ;
350
+ struct getroutes_info {
351
+ struct command * cmd ;
352
+ struct node_id * source , * dest ;
353
+ struct amount_msat * amount , * maxfee ;
354
+ u32 * finalcltv , * maxdelay ;
355
+ const char * * layers ;
356
+ struct additional_cost_htable * additional_costs ;
357
+ /* Non-NULL if we are told to use "auto.localchans" */
358
+ struct layer * local_layer ;
359
+ };
389
360
361
+ static void apply_layers (struct askrene * askrene , struct route_query * rq ,
362
+ struct gossmap_localmods * localmods ,
363
+ const struct getroutes_info * info )
364
+ {
390
365
/* Layers must exist, but might be special ones! */
391
- for (size_t i = 0 ; i < tal_count (layers ); i ++ ) {
392
- const struct layer * l = find_layer (askrene , layers [i ]);
366
+ for (size_t i = 0 ; i < tal_count (info -> layers ); i ++ ) {
367
+ const struct layer * l = find_layer (askrene , info -> layers [i ]);
393
368
if (!l ) {
394
- if (streq (layers [i ], "auto.localchans" )) {
369
+ if (streq (info -> layers [i ], "auto.localchans" )) {
395
370
plugin_log (rq -> plugin , LOG_DBG , "Adding auto.localchans" );
396
- l = local_layer ;
397
- } else if (streq (layers [i ], "auto.no_mpp_support" )) {
371
+ l = info -> local_layer ;
372
+ } else if (streq (info -> layers [i ], "auto.no_mpp_support" )) {
398
373
plugin_log (rq -> plugin , LOG_DBG , "Adding auto.no_mpp_support, sorry" );
399
- l = remove_small_channel_layer (layers , askrene , amount , localmods );
374
+ l = remove_small_channel_layer (info -> layers , askrene , * info -> amount , localmods );
400
375
} else {
401
- assert (streq (layers [i ], "auto.sourcefree" ));
376
+ assert (streq (info -> layers [i ], "auto.sourcefree" ));
402
377
plugin_log (rq -> plugin , LOG_DBG , "Adding auto.sourcefree" );
403
- l = source_free_layer (layers , askrene , source , localmods );
378
+ l = source_free_layer (info -> layers , askrene , info -> source , localmods );
404
379
}
405
380
}
406
381
@@ -412,46 +387,14 @@ static const char *get_routes(const tal_t *ctx,
412
387
* override them (incl local channels) */
413
388
layer_clear_overridden_capacities (l , askrene -> gossmap , rq -> capacities );
414
389
}
390
+ }
415
391
416
- /* Clear scids with reservations, too, so we don't have to look up
417
- * all the time! */
418
- reserves_clear_capacities (askrene -> reserved , askrene -> gossmap , rq -> capacities );
419
-
420
- gossmap_apply_localmods (askrene -> gossmap , localmods );
421
-
422
- /* localmods can add channels, so we need to allocate biases array *afterwards* */
423
- rq -> biases = tal_arrz (rq , s8 , gossmap_max_chan_idx (askrene -> gossmap ) * 2 );
424
-
425
- /* Note any channel biases */
426
- for (size_t i = 0 ; i < tal_count (rq -> layers ); i ++ )
427
- layer_apply_biases (rq -> layers [i ], askrene -> gossmap , rq -> biases );
428
-
429
- srcnode = gossmap_find_node (askrene -> gossmap , source );
430
- if (!srcnode ) {
431
- ret = rq_log (ctx , rq , LOG_INFORM ,
432
- "Unknown source node %s" ,
433
- fmt_node_id (tmpctx , source ));
434
- goto fail ;
435
- }
436
-
437
- dstnode = gossmap_find_node (askrene -> gossmap , dest );
438
- if (!dstnode ) {
439
- ret = rq_log (ctx , rq , LOG_INFORM ,
440
- "Unknown destination node %s" ,
441
- fmt_node_id (tmpctx , dest ));
442
- goto fail ;
443
- }
444
-
445
- /* FIXME: single_path should signal a change in algorithm. */
446
- ret = default_routes (rq , rq , srcnode , dstnode , amount , single_path ,
447
- maxfee , finalcltv , maxdelay , & flows , probability );
448
- if (ret ) {
449
- goto fail ;
450
- }
451
- assert (tal_count (flows ) > 0 );
452
- rq_log (tmpctx , rq , LOG_DBG , "Final answer has %zu flows" ,
453
- tal_count (flows ));
454
-
392
+ static void convert_flows_to_routes (const tal_t * ctx , struct route_query * rq ,
393
+ struct route * * * routes ,
394
+ struct amount_msat * * amounts ,
395
+ u32 finalcltv ,
396
+ struct flow * * flows )
397
+ {
455
398
/* Convert back into routes, with delay and other information fixed */
456
399
* routes = tal_arr (ctx , struct route * , tal_count (flows ));
457
400
* amounts = tal_arr (ctx , struct amount_msat , tal_count (flows ));
@@ -485,26 +428,9 @@ static const char *get_routes(const tal_t *ctx,
485
428
rh -> delay = delay ;
486
429
}
487
430
(* amounts )[i ] = flows [i ]-> delivers ;
488
- rq_log (tmpctx , rq , LOG_INFORM , "Flow %zu/%zu: %s" ,
489
- i , tal_count (flows ),
431
+ rq_log (tmpctx , rq , LOG_INFORM , "Flow %zu/%zu: %s" , i , tal_count (flows ),
490
432
fmt_route (tmpctx , r , (* amounts )[i ], finalcltv ));
491
433
}
492
-
493
- gossmap_remove_localmods (askrene -> gossmap , localmods );
494
- time_delta = timemono_between (time_mono (), time_start );
495
- rq_log (tmpctx , rq , LOG_DBG , "get_routes completed in %" PRIu64 " ms" ,
496
- time_to_msec (time_delta ));
497
- return NULL ;
498
-
499
- /* Explicit failure path keeps the compiler (gcc version 12.3.0 -O3) from
500
- * warning about uninitialized variables in the caller */
501
- fail :
502
- assert (ret != NULL );
503
- gossmap_remove_localmods (askrene -> gossmap , localmods );
504
- time_delta = timemono_between (time_mono (), time_start );
505
- rq_log (tmpctx , rq , LOG_DBG , "get_routes failed after %" PRIu64 " ms" ,
506
- time_to_msec (time_delta ));
507
- return ret ;
508
434
}
509
435
510
436
void get_constraints (const struct route_query * rq ,
@@ -543,61 +469,164 @@ void get_constraints(const struct route_query *rq,
543
469
reserve_sub (rq -> reserved , & scidd , max );
544
470
}
545
471
546
- struct getroutes_info {
547
- struct command * cmd ;
548
- struct node_id * source , * dest ;
549
- struct amount_msat * amount , * maxfee ;
550
- u32 * finalcltv , * maxdelay ;
551
- const char * * layers ;
552
- struct additional_cost_htable * additional_costs ;
553
- /* Non-NULL if we are told to use "auto.localchans" */
554
- struct layer * local_layer ;
555
- };
472
+ static void json_add_getroutes (
473
+ struct json_stream * js ,
474
+ struct route * * routes ,
475
+ /* FIXME: can't we deduce these amounts from the routes themselves */
476
+ struct amount_msat * amounts ,
477
+ double probability ,
478
+ /* FIXME: can't we have different final_cltv for every route? */
479
+ u32 final_cltv )
480
+ {
481
+ json_add_u64 (js , "probability_ppm" , (u64 )(probability * 1000000 ));
482
+ json_array_start (js , "routes" );
483
+ for (size_t i = 0 ; i < tal_count (routes ); i ++ ) {
484
+ json_object_start (js , NULL );
485
+ json_add_u64 (js , "probability_ppm" ,
486
+ (u64 )(routes [i ]-> success_prob * 1000000 ));
487
+ json_add_amount_msat (js , "amount_msat" , amounts [i ]);
488
+ json_add_u32 (js , "final_cltv" , final_cltv );
489
+ json_array_start (js , "path" );
490
+ for (size_t j = 0 ; j < tal_count (routes [i ]-> hops ); j ++ ) {
491
+ struct short_channel_id_dir scidd ;
492
+ const struct route_hop * r = & routes [i ]-> hops [j ];
493
+ json_object_start (js , NULL );
494
+ scidd .scid = r -> scid ;
495
+ scidd .dir = r -> direction ;
496
+ json_add_short_channel_id_dir (
497
+ js , "short_channel_id_dir" , scidd );
498
+ json_add_node_id (js , "next_node_id" , & r -> node_id );
499
+ json_add_amount_msat (js , "amount_msat" , r -> amount );
500
+ json_add_u32 (js , "delay" , r -> delay );
501
+ json_object_end (js );
502
+ }
503
+ json_array_end (js );
504
+ json_object_end (js );
505
+ }
506
+ json_array_end (js );
507
+ }
556
508
557
509
static struct command_result * do_getroutes (struct command * cmd ,
558
510
struct gossmap_localmods * localmods ,
559
511
const struct getroutes_info * info )
560
512
{
513
+ bool localmods_applied = false;
561
514
const char * err ;
562
515
double probability ;
563
516
struct amount_msat * amounts ;
564
517
struct route * * routes ;
518
+ struct flow * * flows ;
565
519
struct json_stream * response ;
566
520
567
- err = get_routes (cmd , cmd ,
568
- info -> source , info -> dest ,
569
- * info -> amount , * info -> maxfee , * info -> finalcltv ,
570
- * info -> maxdelay , info -> layers , localmods , info -> local_layer ,
571
- have_layer (info -> layers , "auto.no_mpp_support" ),
572
- & routes , & amounts , info -> additional_costs , & probability );
573
- if (err )
574
- return command_fail (cmd , PAY_ROUTE_NOT_FOUND , "%s" , err );
521
+ /* get me the global state structure */
522
+ struct askrene * askrene = get_askrene (cmd -> plugin );
575
523
576
- response = jsonrpc_stream_success (cmd );
577
- json_add_u64 (response , "probability_ppm" , (u64 )(probability * 1000000 ));
578
- json_array_start (response , "routes" );
579
- for (size_t i = 0 ; i < tal_count (routes ); i ++ ) {
580
- json_object_start (response , NULL );
581
- json_add_u64 (response , "probability_ppm" , (u64 )(routes [i ]-> success_prob * 1000000 ));
582
- json_add_amount_msat (response , "amount_msat" , amounts [i ]);
583
- json_add_u32 (response , "final_cltv" , * info -> finalcltv );
584
- json_array_start (response , "path" );
585
- for (size_t j = 0 ; j < tal_count (routes [i ]-> hops ); j ++ ) {
586
- struct short_channel_id_dir scidd ;
587
- const struct route_hop * r = & routes [i ]-> hops [j ];
588
- json_object_start (response , NULL );
589
- scidd .scid = r -> scid ;
590
- scidd .dir = r -> direction ;
591
- json_add_short_channel_id_dir (response , "short_channel_id_dir" , scidd );
592
- json_add_node_id (response , "next_node_id" , & r -> node_id );
593
- json_add_amount_msat (response , "amount_msat" , r -> amount );
594
- json_add_u32 (response , "delay" , r -> delay );
595
- json_object_end (response );
524
+ /* update the gossmap */
525
+ if (gossmap_refresh (askrene -> gossmap )) {
526
+ /* FIXME: gossmap_refresh callbacks to we can update in place */
527
+ tal_free (askrene -> capacities );
528
+ askrene -> capacities =
529
+ get_capacities (askrene , askrene -> plugin , askrene -> gossmap );
530
+ }
531
+
532
+ /* build this request structure */
533
+ struct route_query * rq = tal (cmd , struct route_query );
534
+ rq -> cmd = cmd ;
535
+ rq -> plugin = cmd -> plugin ;
536
+ rq -> gossmap = askrene -> gossmap ;
537
+ rq -> reserved = askrene -> reserved ;
538
+ rq -> layers = tal_arr (rq , const struct layer * , 0 );
539
+ rq -> capacities = tal_dup_talarr (rq , fp16_t , askrene -> capacities );
540
+ /* FIXME: we still need to do something useful with these */
541
+ rq -> additional_costs = info -> additional_costs ;
542
+
543
+ /* apply selected layers to the localmods */
544
+ apply_layers (askrene , rq , localmods , info );
545
+
546
+ /* Clear scids with reservations, too, so we don't have to look up
547
+ * all the time! */
548
+ reserves_clear_capacities (askrene -> reserved , askrene -> gossmap ,
549
+ rq -> capacities );
550
+
551
+ /* we temporarily apply localmods */
552
+ gossmap_apply_localmods (askrene -> gossmap , localmods );
553
+ localmods_applied = true;
554
+
555
+ /* localmods can add channels, so we need to allocate biases array
556
+ * *afterwards* */
557
+ rq -> biases =
558
+ tal_arrz (rq , s8 , gossmap_max_chan_idx (askrene -> gossmap ) * 2 );
559
+
560
+ /* Note any channel biases */
561
+ for (size_t i = 0 ; i < tal_count (rq -> layers ); i ++ )
562
+ layer_apply_biases (rq -> layers [i ], askrene -> gossmap , rq -> biases );
563
+
564
+ /* checkout the source */
565
+ const struct gossmap_node * srcnode =
566
+ gossmap_find_node (askrene -> gossmap , info -> source );
567
+ if (!srcnode ) {
568
+ err = rq_log (tmpctx , rq , LOG_INFORM , "Unknown source node %s" ,
569
+ fmt_node_id (tmpctx , info -> source ));
570
+ goto fail ;
571
+ }
572
+
573
+ /* checkout the destination */
574
+ const struct gossmap_node * dstnode =
575
+ gossmap_find_node (askrene -> gossmap , info -> dest );
576
+ if (!dstnode ) {
577
+ err = rq_log (tmpctx , rq , LOG_INFORM ,
578
+ "Unknown destination node %s" ,
579
+ fmt_node_id (tmpctx , info -> dest ));
580
+ goto fail ;
581
+ }
582
+
583
+ /* Compute the routes. At this point we might select between multiple
584
+ * algorithms. */
585
+ struct timemono time_start = time_mono ();
586
+ err = default_routes (rq , rq , srcnode , dstnode , * info -> amount ,
587
+ /* only one path? = */
588
+ have_layer (info -> layers , "auto.no_mpp_support" ),
589
+ * info -> maxfee , * info -> finalcltv , * info -> maxdelay ,
590
+ & flows , & probability );
591
+ struct timerel time_delta = timemono_between (time_mono (), time_start );
592
+
593
+ /* log the time of computation */
594
+ rq_log (tmpctx , rq , LOG_INFORM , "get_routes %s %" PRIu64 " ms" ,
595
+ err ? "failed after" : "completed in" ,
596
+ time_delta_ms (time_delta ));
597
+
598
+ fail :
599
+ /* if we have an error we end the execution here */
600
+ if (err ) {
601
+ /* Safety check, remove localmods only if we applied it. */
602
+ if (localmods_applied ){
603
+ gossmap_remove_localmods (askrene -> gossmap , localmods );
604
+ localmods_applied = false;
596
605
}
597
- json_array_end (response );
598
- json_object_end (response );
606
+ return command_fail (cmd , PAY_ROUTE_NOT_FOUND , "%s" , err );
599
607
}
600
- json_array_end (response );
608
+
609
+ /* otherwise we continue */
610
+ assert (tal_count (flows ) > 0 );
611
+ rq_log (tmpctx , rq , LOG_DBG , "Final answer has %zu flows" ,
612
+ tal_count (flows ));
613
+
614
+ /* convert flows to routes */
615
+ convert_flows_to_routes (rq , rq , & routes , & amounts , * info -> finalcltv ,
616
+ flows );
617
+ assert (tal_count (routes ) == tal_count (flows ));
618
+ assert (tal_count (amounts ) == tal_count (flows ));
619
+
620
+ /* At last we remove the localmods from the gossmap. */
621
+ if (localmods_applied ) {
622
+ gossmap_remove_localmods (askrene -> gossmap , localmods );
623
+ localmods_applied = false;
624
+ }
625
+
626
+ /* output the results */
627
+ response = jsonrpc_stream_success (cmd );
628
+ json_add_getroutes (response , routes , amounts , probability ,
629
+ * info -> finalcltv );
601
630
return command_finished (cmd , response );
602
631
}
603
632
0 commit comments