@@ -688,6 +688,53 @@ static struct amount_msat path_max_deliverable(struct channel_data *path)
688688 return deliver ;
689689}
690690
691+ // TODO: unit test:
692+ // -> make a path
693+ // -> compute x = path_min_deliverable
694+ // -> check that htlc_min are all satisfied
695+ // -> check that (x-1) at least one htlc_min is violated
696+ /* The least amount that we can deliver at the destination such that when one
697+ * computes the hop amounts backwards the htlc_min are always met. */
698+ static struct amount_msat path_min_deliverable (struct channel_data * path )
699+ {
700+ struct amount_msat least_send = AMOUNT_MSAT (1 );
701+ const size_t pathlen = tal_count (path );
702+ for (size_t i = pathlen - 1 ; i < pathlen ; i -- ) {
703+ least_send = amount_msat_max (least_send , path [i ].htlc_min );
704+ if (!amount_msat_add_fee (& least_send , path [i ].fee_base_msat ,
705+ path [i ].fee_proportional_millionths ))
706+ abort ();
707+ }
708+ /* least_send: is the least amount we can send in order to deliver at
709+ * least 1 msat at the destination. */
710+ struct amount_msat least_destination = least_send ;
711+ for (size_t i = 0 ; i < pathlen ; i ++ ) {
712+ struct amount_msat in_value = least_destination ;
713+ struct amount_msat out_value =
714+ amount_msat_sub_fee (in_value , path [i ].fee_base_msat ,
715+ path [i ].fee_proportional_millionths );
716+ assert (amount_msat_greater_eq (out_value , path [i ].htlc_min ));
717+ struct amount_msat x = out_value ;
718+ if (!amount_msat_add_fee (& x , path [i ].fee_base_msat ,
719+ path [i ].fee_proportional_millionths ))
720+ abort ();
721+ /* if the in_value computed from the out_value is smaller than
722+ * it should, then we add 1msat */
723+ if (amount_msat_less (x , in_value ) &&
724+ !amount_msat_accumulate (& out_value , AMOUNT_MSAT (1 )))
725+ abort ();
726+ /* check conditions */
727+ assert (amount_msat_greater_eq (out_value , path [i ].htlc_min ));
728+ x = out_value ;
729+ assert (
730+ amount_msat_add_fee (& x , path [i ].fee_base_msat ,
731+ path [i ].fee_proportional_millionths ) &&
732+ amount_msat_greater_eq (x , in_value ));
733+ least_destination = out_value ;
734+ }
735+ return least_destination ;
736+ }
737+
691738static struct amount_msat sum_all_deliver (struct flow * * flows ,
692739 size_t * flows_index )
693740{
@@ -773,6 +820,7 @@ const char *refine_flows(const tal_t *ctx, struct route_query *rq,
773820{
774821 const tal_t * working_ctx = tal (ctx , tal_t );
775822 struct amount_msat * max_deliverable ;
823+ struct amount_msat * min_deliverable ;
776824 struct channel_data * * channel_mpp_cache ;
777825 size_t * flows_index ;
778826
@@ -781,11 +829,14 @@ const char *refine_flows(const tal_t *ctx, struct route_query *rq,
781829 channel_mpp_cache = new_channel_mpp_cache (working_ctx , rq , * flows );
782830 max_deliverable = tal_arrz (working_ctx , struct amount_msat ,
783831 tal_count (channel_mpp_cache ));
832+ min_deliverable = tal_arrz (working_ctx , struct amount_msat ,
833+ tal_count (channel_mpp_cache ));
784834 flows_index = tal_arrz (working_ctx , size_t , tal_count (* flows ));
785835 for (size_t i = 0 ; i < tal_count (channel_mpp_cache ); i ++ ) {
786836 // FIXME: does path_max_deliverable work for a single
787837 // channel with 0 fees?
788838 max_deliverable [i ] = path_max_deliverable (channel_mpp_cache [i ]);
839+ min_deliverable [i ] = path_min_deliverable (channel_mpp_cache [i ]);
789840 /* We use an array of indexes to keep track of the order
790841 * of the flows. Likewise flows can be removed by simply
791842 * shrinking the flows_index array. */
@@ -802,6 +853,18 @@ const char *refine_flows(const tal_t *ctx, struct route_query *rq,
802853 /* remove excess from MCF granularity if any */
803854 remove_excess (* flows , & flows_index , deliver );
804855
856+ /* detect htlc_min violations */
857+ for (size_t i = 0 ; i < tal_count (flows_index );) {
858+ size_t k = flows_index [i ];
859+ if (amount_msat_greater_eq ((* flows )[k ]-> delivers ,
860+ min_deliverable [k ])) {
861+ i ++ ;
862+ continue ;
863+ }
864+ /* htlc_min is not met for this flow */
865+ tal_arr_remove (& flows_index , i );
866+ }
867+
805868 /* remove 0 amount flows if any */
806869 asort (flows_index , tal_count (flows_index ), revcmp_flows , * flows );
807870 for (int i = tal_count (flows_index ) - 1 ; i >= 0 ; i -- ) {
0 commit comments