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