| 58 | } |
| 59 | |
| 60 | static enum renepay_errorcode |
| 61 | route_check_constraints(struct route *route, struct gossmap *gossmap, |
| 62 | struct uncertainty *uncertainty, |
| 63 | bitmap *disabled_bitmap) |
| 64 | { |
| 65 | assert(route); |
| 66 | assert(route->hops); |
| 67 | const size_t pathlen = tal_count(route->hops); |
| 68 | if (pathlen == 0) |
| 69 | return RENEPAY_NOERROR; |
| 70 | if (!amount_msat_eq(route->amount_deliver, |
| 71 | route->hops[pathlen - 1].amount)) |
| 72 | return RENEPAY_PRECONDITION_ERROR; |
| 73 | if (!amount_msat_eq(route->amount_sent, route->hops[0].amount)) |
| 74 | return RENEPAY_PRECONDITION_ERROR; |
| 75 | |
| 76 | for (size_t i = 0; i < pathlen; i++) { |
| 77 | struct route_hop *hop = &route->hops[i]; |
| 78 | int dir = hop->direction; |
| 79 | struct gossmap_chan *chan = |
| 80 | gossmap_find_chan(gossmap, &hop->scid); |
| 81 | assert(chan); |
| 82 | struct chan_extra *ce = |
| 83 | uncertainty_find_channel(uncertainty, hop->scid); |
| 84 | |
| 85 | // check that we stay within the htlc max and min limits |
| 86 | if (amount_msat_greater(hop->amount, |
| 87 | gossmap_chan_htlc_max(chan, dir)) || |
| 88 | amount_msat_less(hop->amount, |
| 89 | gossmap_chan_htlc_min(chan, dir))) { |
| 90 | bitmap_set_bit(disabled_bitmap, |
| 91 | gossmap_chan_idx(gossmap, chan) * 2 + |
| 92 | dir); |
| 93 | return RENEPAY_BAD_CHANNEL; |
| 94 | } |
| 95 | |
| 96 | // check that the sum of all htlcs and this amount does not |
| 97 | // exceed the maximum known by our knowledge |
| 98 | struct amount_msat total_htlcs = ce->half[dir].htlc_total; |
| 99 | if (!amount_msat_add(&total_htlcs, total_htlcs, hop->amount)) |
| 100 | return RENEPAY_AMOUNT_OVERFLOW; |
| 101 | |
| 102 | if (amount_msat_greater(total_htlcs, ce->half[dir].known_max)) |
| 103 | return RENEPAY_UNEXPECTED; |
| 104 | } |
| 105 | return RENEPAY_NOERROR; |
| 106 | } |
| 107 | |
| 108 | static void tal_report_error(const tal_t *ctx, enum jsonrpc_errcode *ecode, |
| 109 | const char **fail, |
no test coverage detected