66#include <plugins/askrene/flow.h>
77#include <plugins/askrene/refine.h>
88#include <plugins/askrene/reserve.h>
9+ #include <string.h>
910
1011/* Channel data for fast retrieval. */
1112struct channel_data {
@@ -35,8 +36,8 @@ static void destroy_reservations(struct reserve_hop *rhops, struct askrene *askr
3536 reserve_remove (askrene -> reserved , & rhops [i ]);
3637}
3738
38- static struct reserve_hop * new_reservations (const tal_t * ctx ,
39- const struct route_query * rq )
39+ struct reserve_hop * new_reservations (const tal_t * ctx ,
40+ const struct route_query * rq )
4041{
4142 struct reserve_hop * rhops = tal_arr (ctx , struct reserve_hop , 0 );
4243
@@ -108,9 +109,9 @@ static void subtract_reservation(struct reserve_hop **reservations,
108109 reserve_add (askrene -> reserved , prev , rq -> cmd -> id );
109110}
110111
111- static void create_flow_reservations (const struct route_query * rq ,
112- struct reserve_hop * * reservations ,
113- const struct flow * flow )
112+ void create_flow_reservations (const struct route_query * rq ,
113+ struct reserve_hop * * reservations ,
114+ const struct flow * flow )
114115{
115116 struct amount_msat msat ;
116117
@@ -170,6 +171,32 @@ static void change_flow_delivers(const struct route_query *rq,
170171 create_flow_reservations (rq , reservations , flow );
171172}
172173
174+ bool create_flow_reservations_verify (const struct route_query * rq ,
175+ struct reserve_hop * * reservations ,
176+ const struct flow * flow )
177+ {
178+ struct amount_msat msat ;
179+ msat = flow -> delivers ;
180+ for (int i = tal_count (flow -> path ) - 1 ; i >= 0 ; i -- ) {
181+ struct amount_msat known_min , known_max ;
182+ const struct half_chan * h = flow_edge (flow , i );
183+ struct amount_msat amount_to_reserve = msat ;
184+ struct short_channel_id_dir scidd ;
185+
186+ get_scidd (rq -> gossmap , flow , i , & scidd );
187+ get_constraints (rq , flow -> path [i ], flow -> dirs [i ], & known_min ,
188+ & known_max );
189+ if (amount_msat_greater (amount_to_reserve , known_max ))
190+ return false;
191+
192+ if (!amount_msat_add_fee (& msat , h -> base_fee ,
193+ h -> proportional_fee ))
194+ abort ();
195+ }
196+ create_flow_reservations (rq , reservations , flow );
197+ return true;
198+ }
199+
173200/* We use an fp16_t approximatin for htlc_max/min: this gets the exact value. */
174201static struct amount_msat get_chan_htlc_max (const struct route_query * rq ,
175202 const struct gossmap_chan * c ,
@@ -846,6 +873,24 @@ static struct amount_msat remove_excess(struct flow **flows,
846873 return all_deliver ;
847874}
848875
876+ static void write_selected_flows (const tal_t * ctx , size_t * flows_index ,
877+ struct flow * * * flows )
878+ {
879+ struct flow * * tmp_flows = tal_arr (ctx , struct flow * , 0 );
880+ for (size_t i = 0 ; i < tal_count (flows_index ); i ++ ) {
881+ tal_arr_expand (& tmp_flows , (* flows )[flows_index [i ]]);
882+ (* flows )[flows_index [i ]] = NULL ;
883+ }
884+ for (size_t i = 0 ; i < tal_count (* flows ); i ++ ) {
885+ (* flows )[i ] = tal_free ((* flows )[i ]);
886+ }
887+ tal_resize (flows , 0 );
888+ for (size_t i = 0 ; i < tal_count (tmp_flows ); i ++ ) {
889+ tal_arr_expand (flows , tmp_flows [i ]);
890+ }
891+ tal_free (tmp_flows );
892+ }
893+
849894/* FIXME: on failure return error message */
850895const char * refine_flows (const tal_t * ctx , struct route_query * rq ,
851896 struct amount_msat deliver , struct flow * * * flows )
@@ -911,18 +956,7 @@ const char *refine_flows(const tal_t *ctx, struct route_query *rq,
911956 }
912957
913958 /* finally write the remaining flows */
914- struct flow * * tmp_flows = tal_arr (working_ctx , struct flow * , 0 );
915- for (size_t i = 0 ; i < tal_count (flows_index ); i ++ ) {
916- tal_arr_expand (& tmp_flows , (* flows )[flows_index [i ]]);
917- (* flows )[flows_index [i ]] = NULL ;
918- }
919- for (size_t i = 0 ; i < tal_count (* flows ); i ++ ) {
920- (* flows )[i ] = tal_free ((* flows )[i ]);
921- }
922- tal_resize (flows , 0 );
923- for (size_t i = 0 ; i < tal_count (tmp_flows ); i ++ ) {
924- tal_arr_expand (flows , tmp_flows [i ]);
925- }
959+ write_selected_flows (working_ctx , flows_index , flows );
926960
927961 tal_free (working_ctx );
928962 return NULL ;
@@ -931,3 +965,80 @@ const char *refine_flows(const tal_t *ctx, struct route_query *rq,
931965 tal_free (working_ctx );
932966 return error_message ;
933967}
968+
969+ /* Order of flows according to path string */
970+ static int cmppath_flows (const size_t * a , const size_t * b , char * * paths_str )
971+ {
972+ return strcmp (paths_str [* a ], paths_str [* b ]);
973+ }
974+
975+ void squash_flows (const tal_t * ctx , struct route_query * rq ,
976+ struct flow * * * flows )
977+ {
978+ const tal_t * working_ctx = tal (ctx , tal_t );
979+ size_t * flows_index = tal_arrz (working_ctx , size_t , tal_count (* flows ));
980+ char * * paths_str = tal_arrz (working_ctx , char * , tal_count (* flows ));
981+ struct channel_data * * channel_mpp_cache =
982+ new_channel_mpp_cache (working_ctx , rq , * flows );
983+ struct amount_msat * max_deliverable = tal_arrz (
984+ working_ctx , struct amount_msat , tal_count (channel_mpp_cache ));
985+
986+ for (size_t i = 0 ; i < tal_count (flows_index ); i ++ ) {
987+ struct flow * flow = (* flows )[i ];
988+ struct short_channel_id_dir scidd ;
989+ flows_index [i ] = i ;
990+ paths_str [i ] = tal_strdup (working_ctx , "" );
991+ max_deliverable [i ] = path_max_deliverable (channel_mpp_cache [i ]);
992+
993+ for (size_t j = 0 ; j < tal_count (flow -> path ); j ++ ) {
994+ scidd .scid =
995+ gossmap_chan_scid (rq -> gossmap , flow -> path [j ]);
996+ scidd .dir = flow -> dirs [j ];
997+ tal_append_fmt (
998+ & paths_str [i ], "%s%s" , j > 0 ? "->" : "" ,
999+ fmt_short_channel_id_dir (working_ctx , & scidd ));
1000+ }
1001+ }
1002+
1003+ asort (flows_index , tal_count (flows_index ), cmppath_flows , paths_str );
1004+ for (size_t i = 0 ; i < tal_count (flows_index ); i ++ ) {
1005+ const size_t j = i + 1 ;
1006+ struct amount_msat combined ;
1007+ struct amount_msat max = max_deliverable [flows_index [i ]];
1008+
1009+ /* same path? We merge */
1010+ while (j < tal_count (flows_index ) &&
1011+ cmppath_flows (& flows_index [i ],
1012+ & flows_index [j ],
1013+ paths_str ) == 0 ) {
1014+ if (!amount_msat_add (
1015+ & combined , (* flows )[flows_index [i ]]-> delivers ,
1016+ (* flows )[flows_index [j ]]-> delivers ))
1017+ abort ();
1018+ /* do we break any HTLC max limits */
1019+ if (amount_msat_greater (combined , max ))
1020+ break ;
1021+ (* flows )[flows_index [i ]]-> delivers = combined ;
1022+ tal_arr_remove (& flows_index , j );
1023+ }
1024+ }
1025+
1026+ write_selected_flows (working_ctx , flows_index , flows );
1027+
1028+ tal_free (working_ctx );
1029+ }
1030+
1031+ double flows_probability (const tal_t * ctx , struct route_query * rq ,
1032+ struct flow * * * flows )
1033+ {
1034+ const tal_t * working_ctx = tal (ctx , tal_t );
1035+ struct reserve_hop * reservations = new_reservations (working_ctx , rq );
1036+ double probability = 1.0 ;
1037+
1038+ for (size_t i = 0 ; i < tal_count (* flows ); i ++ ) {
1039+ probability *= flow_probability ((* flows )[i ], rq );
1040+ create_flow_reservations (rq , & reservations , (* flows )[i ]);
1041+ }
1042+ tal_free (working_ctx );
1043+ return probability ;
1044+ }
0 commit comments