@@ -331,60 +331,35 @@ const char *fmt_flow_full(const tal_t *ctx,
331331 return str ;
332332}
333333
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+ };
373344
345+ static void apply_layers (struct askrene * askrene , struct route_query * rq ,
346+ struct gossmap_localmods * localmods ,
347+ const struct getroutes_info * info )
348+ {
374349 /* 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 ]);
377352 if (!l ) {
378- if (streq (layers [i ], "auto.localchans" )) {
353+ if (streq (info -> layers [i ], "auto.localchans" )) {
379354 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" )) {
382357 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 );
384359 } else {
385- assert (streq (layers [i ], "auto.sourcefree" ));
360+ assert (streq (info -> layers [i ], "auto.sourcefree" ));
386361 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 );
388363 }
389364 }
390365
@@ -396,46 +371,14 @@ static const char *get_routes(const tal_t *ctx,
396371 * override them (incl local channels) */
397372 layer_clear_overridden_capacities (l , askrene -> gossmap , rq -> capacities );
398373 }
374+ }
399375
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+ {
439382 /* Convert back into routes, with delay and other information fixed */
440383 * routes = tal_arr (ctx , struct route * , tal_count (flows ));
441384 * amounts = tal_arr (ctx , struct amount_msat , tal_count (flows ));
@@ -473,22 +416,6 @@ static const char *get_routes(const tal_t *ctx,
473416 i , tal_count (flows ),
474417 fmt_route (tmpctx , r , (* amounts )[i ], finalcltv ));
475418 }
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 ;
492419}
493420
494421void get_constraints (const struct route_query * rq ,
@@ -527,61 +454,162 @@ void get_constraints(const struct route_query *rq,
527454 reserve_sub (rq -> reserved , & scidd , max );
528455}
529456
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+ }
540491
541492static struct command_result * do_getroutes (struct command * cmd ,
542493 struct gossmap_localmods * localmods ,
543494 const struct getroutes_info * info )
544495{
496+ bool localmods_applied = false;
545497 const char * err ;
546498 double probability ;
547499 struct amount_msat * amounts ;
548500 struct route * * routes ;
501+ struct flow * * flows ;
549502 struct json_stream * response ;
550503
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 );
559506
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;
580588 }
581- json_array_end (response );
582- json_object_end (response );
589+ return command_fail (cmd , PAY_ROUTE_NOT_FOUND , "%s" , err );
583590 }
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 );
585613 return command_finished (cmd , response );
586614}
587615
0 commit comments