diff --git a/plugins/renepay/mcf.c b/plugins/renepay/mcf.c index 2e2fdaffc..7d7da870f 100644 --- a/plugins/renepay/mcf.c +++ b/plugins/renepay/mcf.c @@ -256,6 +256,55 @@ static const s64 MU_MAX = 128; * I hope this will clarify my future self when I forget. * * */ + +/* + * We want to use the whole number here for convenience, but + * we can't us a union, since bit order is implementation-defined and + * we want chanidx on the highest bits: + * + * [ 0 1 2 3 4 5 6 ... 31 ] + * dual part chandir chanidx + */ +struct arc { + u32 idx; +}; + +#define ARC_DUAL_BITOFF (0) +#define ARC_PART_BITOFF (1) +#define ARC_CHANDIR_BITOFF (1 + PARTS_BITS) +#define ARC_CHANIDX_BITOFF (1 + PARTS_BITS + 1) +#define ARC_CHANIDX_BITS (32 - ARC_CHANIDX_BITOFF) + +static inline void arc_to_parts(struct arc arc, + u32 *chanidx, + int *chandir, + u32 *part, + bool *dual) +{ + if (chanidx) + *chanidx = (arc.idx >> ARC_CHANIDX_BITOFF); + if (chandir) + *chandir = (arc.idx >> ARC_CHANDIR_BITOFF) & 1; + if (part) + *part = (arc.idx >> ARC_PART_BITOFF) & ((1 << PARTS_BITS)-1); + if (dual) + *dual = (arc.idx >> ARC_DUAL_BITOFF) & 1; +} + +static inline struct arc arc_from_parts(u32 chanidx, int chandir, u32 part, bool dual) +{ + struct arc arc; + + assert(part < CHANNEL_PARTS); + assert(chandir == 0 || chandir == 1); + assert(chanidx < (1U << ARC_CHANIDX_BITS)); + arc.idx = ((u32)dual << ARC_DUAL_BITOFF) + | (part << ARC_PART_BITOFF) + | ((u32)chandir << ARC_CHANDIR_BITOFF) + | (chanidx << ARC_CHANIDX_BITOFF); + return arc; +} + typedef union { struct{ diff --git a/plugins/renepay/test/run-arc.c b/plugins/renepay/test/run-arc.c new file mode 100644 index 000000000..09d2f675f --- /dev/null +++ b/plugins/renepay/test/run-arc.c @@ -0,0 +1,114 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../mcf.c" + +/* update-mocks isn't quiet smart enough for this, so place here */ +struct pay_plugin *const pay_plugin; + +/* AUTOGENERATED MOCKS START */ +/* Generated stub for flow_complete */ +void flow_complete(struct flow *flow UNNEEDED, + const struct gossmap *gossmap UNNEEDED, + struct chan_extra_map *chan_extra_map UNNEEDED, + struct amount_msat delivered UNNEEDED) +{ fprintf(stderr, "flow_complete called!\n"); abort(); } +/* Generated stub for flow_set_fee */ +struct amount_msat flow_set_fee(struct flow **flows UNNEEDED) +{ fprintf(stderr, "flow_set_fee called!\n"); abort(); } +/* Generated stub for flow_set_probability */ +double flow_set_probability( + struct flow ** flows UNNEEDED, + const struct gossmap *const gossmap UNNEEDED, + struct chan_extra_map * chan_extra_map UNNEEDED) +{ fprintf(stderr, "flow_set_probability called!\n"); abort(); } +/* Generated stub for get_chan_extra_half_by_chan */ +struct chan_extra_half *get_chan_extra_half_by_chan(const struct gossmap *gossmap UNNEEDED, + struct chan_extra_map *chan_extra_map UNNEEDED, + const struct gossmap_chan *chan UNNEEDED, + int dir UNNEEDED) +{ fprintf(stderr, "get_chan_extra_half_by_chan called!\n"); abort(); } +/* Generated stub for linear_fee_cost */ +s64 linear_fee_cost( + const struct gossmap_chan *c UNNEEDED, + const int dir UNNEEDED, + double base_fee_penalty UNNEEDED, + double delay_feefactor UNNEEDED) +{ fprintf(stderr, "linear_fee_cost called!\n"); abort(); } +/* AUTOGENERATED MOCKS END */ + +int main(int argc, char *argv[]) +{ + bool dual; + u32 part; + int chandir; + u32 chanidx; + + common_setup(argv[0]); + + for (int i = 0; i < 32; i++) { + for (int j = 0; j < 32; j++) { + for (int k = 0; k < 32; k++) { + struct arc a, a2; + + a.idx = (1U << i) | (1U << j) | (1U << k); + arc_to_parts(a, &chanidx, &chandir, &part, &dual); + a2 = arc_from_parts(chanidx, chandir, part, dual); + assert(a.idx == a2.idx); + } + } + } + + /* Test all chanidx */ + for (int i = 0; i < (1U << ARC_CHANIDX_BITS); i++) { + struct arc a = arc_from_parts(i, chandir, part, dual); + + arc_to_parts(a, &chanidx, NULL, NULL, NULL); + assert(chanidx == i); + } + + /* Test both chandir */ + for (int i = 0; i < 2; i++) { + struct arc a = arc_from_parts(chanidx, i, part, dual); + + arc_to_parts(a, NULL, &chandir, NULL, NULL); + assert(chandir == i); + } + + /* Test all parts */ + for (int i = 0; i < CHANNEL_PARTS; i++) { + struct arc a = arc_from_parts(chanidx, chandir, i, dual); + + arc_to_parts(a, NULL, NULL, &part, NULL); + assert(part == i); + } + + /* Test both dual */ + for (int i = 0; i < 2; i++) { + struct arc a = arc_from_parts(chanidx, chandir, part, i); + + arc_to_parts(a, NULL, NULL, NULL, &dual); + assert(dual == i); + +/* This code not converted yet! */ +#if 0 + assert(arc_is_dual(a) == dual); + + a = arc_dual(a); + arc_to_parts(a, NULL, NULL, NULL, &dual); + assert(dual == !i); + assert(arc_is_dual(a) == dual); +#endif + } + + common_shutdown(); +} +