2023-07-31 03:51:22 +02:00
|
|
|
#ifndef LIGHTNING_PLUGINS_RENEPAY_FLOW_H
|
|
|
|
#define LIGHTNING_PLUGINS_RENEPAY_FLOW_H
|
|
|
|
#include "config.h"
|
|
|
|
#include <bitcoin/short_channel_id.h>
|
|
|
|
#include <ccan/htable/htable_type.h>
|
|
|
|
#include <common/amount.h>
|
|
|
|
#include <common/gossmap.h>
|
2023-11-17 14:03:06 +01:00
|
|
|
|
2023-07-31 03:51:22 +02:00
|
|
|
|
|
|
|
// TODO(eduardo): a hard coded constant to indicate a limit on any channel
|
|
|
|
// capacity. Channels for which the capacity is unknown (because they are not
|
|
|
|
// announced) use this value. It makes sense, because if we don't even know the
|
|
|
|
// channel capacity the liquidity could be anything but it will never be greater
|
|
|
|
// than the global number of msats.
|
|
|
|
// It remains to be checked if this value does not lead to overflow somewhere in
|
|
|
|
// the code.
|
|
|
|
#define MAX_CAP (AMOUNT_MSAT(21000000*MSAT_PER_BTC))
|
|
|
|
|
|
|
|
/* Any implementation needs to keep some data on channels which are
|
|
|
|
* in-use (or about which we have extra information). We use a hash
|
|
|
|
* table here, since most channels are not in use. */
|
|
|
|
// TODO(eduardo): if we know the liquidity of channel (X,dir) is [A,B]
|
|
|
|
// then we also know that the liquidity of channel (X,!dir) is [Cap-B,Cap-A].
|
|
|
|
// This means that it is redundant to store known_min and known_max for both
|
|
|
|
// halves of the channel and it also means that once we update the knowledge of
|
|
|
|
// (X,dir) the knowledge of (X,!dir) is updated as well.
|
|
|
|
struct chan_extra {
|
|
|
|
struct short_channel_id scid;
|
|
|
|
struct amount_msat capacity;
|
|
|
|
|
|
|
|
struct chan_extra_half {
|
|
|
|
/* How many htlcs we've directed through it */
|
|
|
|
size_t num_htlcs;
|
|
|
|
|
|
|
|
/* The total size of those HTLCs */
|
|
|
|
struct amount_msat htlc_total;
|
|
|
|
|
|
|
|
/* The known minimum / maximum capacity (if nothing known, 0/capacity */
|
|
|
|
struct amount_msat known_min, known_max;
|
|
|
|
} half[2];
|
|
|
|
};
|
|
|
|
|
2023-07-31 03:51:25 +02:00
|
|
|
bool chan_extra_is_busy(const struct chan_extra *const ce);
|
2023-07-31 03:51:22 +02:00
|
|
|
|
|
|
|
static inline const struct short_channel_id
|
|
|
|
chan_extra_scid(const struct chan_extra *cd)
|
|
|
|
{
|
|
|
|
return cd->scid;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline size_t hash_scid(const struct short_channel_id scid)
|
|
|
|
{
|
|
|
|
/* scids cost money to generate, so simple hash works here */
|
|
|
|
return (scid.u64 >> 32)
|
|
|
|
^ (scid.u64 >> 16)
|
|
|
|
^ scid.u64;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool chan_extra_eq_scid(const struct chan_extra *cd,
|
|
|
|
const struct short_channel_id scid)
|
|
|
|
{
|
|
|
|
return short_channel_id_eq(&scid, &cd->scid);
|
|
|
|
}
|
|
|
|
|
|
|
|
HTABLE_DEFINE_TYPE(struct chan_extra,
|
|
|
|
chan_extra_scid, hash_scid, chan_extra_eq_scid,
|
|
|
|
chan_extra_map);
|
|
|
|
|
|
|
|
/* Helpers for chan_extra_map */
|
|
|
|
/* Channel knowledge invariants:
|
|
|
|
*
|
|
|
|
* 0<=a<=b<=capacity
|
|
|
|
*
|
|
|
|
* a_inv = capacity-b
|
|
|
|
* b_inv = capacity-a
|
|
|
|
*
|
|
|
|
* where a,b are the known minimum and maximum liquidities, and a_inv and b_inv
|
|
|
|
* are the known minimum and maximum liquidities for the channel in the opposite
|
|
|
|
* direction.
|
|
|
|
*
|
|
|
|
* Knowledge update operations can be:
|
|
|
|
*
|
|
|
|
* 1. set liquidity (x)
|
|
|
|
* (a,b) -> (x,x)
|
|
|
|
*
|
|
|
|
* The entropy is minimum here (=0).
|
|
|
|
*
|
|
|
|
* 2. can send (x):
|
|
|
|
* xb = min(x,capacity)
|
|
|
|
* (a,b) -> (max(a,xb),max(b,xb))
|
|
|
|
*
|
|
|
|
* If x<=a then there is no new knowledge and the entropy remains
|
|
|
|
* the same.
|
|
|
|
* If x>a the entropy decreases.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* 3. can't send (x):
|
|
|
|
* xb = max(0,x-1)
|
|
|
|
* (a,b) -> (min(a,xb),min(b,xb))
|
|
|
|
*
|
|
|
|
* If x>b there is no new knowledge and the entropy remains.
|
|
|
|
* If x<=b then the entropy decreases.
|
|
|
|
*
|
|
|
|
* 4. sent success (x):
|
|
|
|
* (a,b) -> (max(0,a-x),max(0,b-x))
|
|
|
|
*
|
|
|
|
* If x<=a there is no new knowledge and the entropy remains.
|
|
|
|
* If a<x then the entropy decreases.
|
|
|
|
*
|
|
|
|
* 5. relax (x,y):
|
|
|
|
*
|
|
|
|
* (a,b) -> (max(0,a-x),min(capacity,b+y))
|
|
|
|
*
|
|
|
|
* Entropy increases unless it is already maximum.
|
|
|
|
* */
|
|
|
|
|
|
|
|
const char *fmt_chan_extra_map(
|
|
|
|
const tal_t *ctx,
|
|
|
|
struct chan_extra_map* chan_extra_map);
|
|
|
|
|
plugins/renepay: neaten the command notifications.
It now looks like (for test_hardmpp):
```
# we have computed a set of 1 flows with probability 0.328, fees 0msat and delay 23
# Flow 1: amount=1800000000msat prob=0.328 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0->-103x3x0/1->
# Flow 1: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 1: Failure of 1800000000msat for 103x5x0/0 capacity [0msat,3000000000msat] -> [0msat,1799999999msat]
# we have computed a set of 2 flows with probability 0.115, fees 0msat and delay 23
# Flow 2: amount=500000000msat prob=0.475 fees=0msat delay=12 path=-103x6x0/0(min=max=4294967295msat)->-103x1x0/1->-103x4x0/1->
# Flow 3: amount=1300000000msat prob=0.242 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1799999999msat)->-103x3x0/1->
# Flow 3: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 3: Failure of 1300000000msat for 103x5x0/0 capacity [0msat,1799999999msat] -> [0msat,1299999999msat]
# we have computed a set of 2 flows with probability 0.084, fees 0msat and delay 23
# Flow 4: amount=260000000msat prob=0.467 fees=0msat delay=12 path=-103x6x0/0(500000000msat in 1 htlcs,min=max=4294967295msat)->-103x1x0/1(500000000msat in 1 htlcs)->-103x4x0/1(500000000msat in 1 htlcs)->
# Flow 5: amount=1040000000msat prob=0.179 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1299999999msat)->-103x3x0/1->
# Flow 5: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 5: Failure of 1040000000msat for 103x5x0/0 capacity [0msat,1299999999msat] -> [0msat,1039999999msat]
# we have computed a set of 2 flows with probability 0.052, fees 0msat and delay 23
# Flow 6: amount=120000000msat prob=0.494 fees=0msat delay=12 path=-103x6x0/0(760000000msat in 2 htlcs,min=max=4294967295msat)->-103x1x0/1(760000000msat in 2 htlcs)->-103x4x0/1(760000000msat in 2 htlcs)->
# Flow 7: amount=920000000msat prob=0.105 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1039999999msat)->-103x3x0/1->
# Flow 7: Success
```
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2023-08-21 07:38:46 +02:00
|
|
|
/* Returns "" if nothing useful known about channel, otherwise
|
|
|
|
* "(details)" */
|
|
|
|
const char *fmt_chan_extra_details(const tal_t *ctx,
|
2023-12-18 14:18:00 +01:00
|
|
|
const struct chan_extra_map* chan_extra_map,
|
plugins/renepay: neaten the command notifications.
It now looks like (for test_hardmpp):
```
# we have computed a set of 1 flows with probability 0.328, fees 0msat and delay 23
# Flow 1: amount=1800000000msat prob=0.328 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0->-103x3x0/1->
# Flow 1: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 1: Failure of 1800000000msat for 103x5x0/0 capacity [0msat,3000000000msat] -> [0msat,1799999999msat]
# we have computed a set of 2 flows with probability 0.115, fees 0msat and delay 23
# Flow 2: amount=500000000msat prob=0.475 fees=0msat delay=12 path=-103x6x0/0(min=max=4294967295msat)->-103x1x0/1->-103x4x0/1->
# Flow 3: amount=1300000000msat prob=0.242 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1799999999msat)->-103x3x0/1->
# Flow 3: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 3: Failure of 1300000000msat for 103x5x0/0 capacity [0msat,1799999999msat] -> [0msat,1299999999msat]
# we have computed a set of 2 flows with probability 0.084, fees 0msat and delay 23
# Flow 4: amount=260000000msat prob=0.467 fees=0msat delay=12 path=-103x6x0/0(500000000msat in 1 htlcs,min=max=4294967295msat)->-103x1x0/1(500000000msat in 1 htlcs)->-103x4x0/1(500000000msat in 1 htlcs)->
# Flow 5: amount=1040000000msat prob=0.179 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1299999999msat)->-103x3x0/1->
# Flow 5: Failed at node #1 (WIRE_TEMPORARY_CHANNEL_FAILURE): failed: WIRE_TEMPORARY_CHANNEL_FAILURE (reply from remote)
# Flow 5: Failure of 1040000000msat for 103x5x0/0 capacity [0msat,1299999999msat] -> [0msat,1039999999msat]
# we have computed a set of 2 flows with probability 0.052, fees 0msat and delay 23
# Flow 6: amount=120000000msat prob=0.494 fees=0msat delay=12 path=-103x6x0/0(760000000msat in 2 htlcs,min=max=4294967295msat)->-103x1x0/1(760000000msat in 2 htlcs)->-103x4x0/1(760000000msat in 2 htlcs)->
# Flow 7: amount=920000000msat prob=0.105 fees=0msat delay=12 path=-103x2x0/1(min=max=4294967295msat)->-103x5x0/0(max=1039999999msat)->-103x3x0/1->
# Flow 7: Success
```
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2023-08-21 07:38:46 +02:00
|
|
|
const struct short_channel_id_dir *scidd);
|
|
|
|
|
2023-07-31 03:51:22 +02:00
|
|
|
/* Creates a new chan_extra and adds it to the chan_extra_map. */
|
|
|
|
struct chan_extra *new_chan_extra(
|
|
|
|
struct chan_extra_map *chan_extra_map,
|
|
|
|
const struct short_channel_id scid,
|
|
|
|
struct amount_msat capacity);
|
|
|
|
|
|
|
|
|
|
|
|
/* Helper to find the min of two amounts */
|
|
|
|
static inline struct amount_msat amount_msat_min(
|
|
|
|
struct amount_msat a,
|
|
|
|
struct amount_msat b)
|
|
|
|
{
|
|
|
|
return amount_msat_less(a,b) ? a : b;
|
|
|
|
}
|
|
|
|
/* Helper to find the max of two amounts */
|
|
|
|
static inline struct amount_msat amount_msat_max(
|
|
|
|
struct amount_msat a,
|
|
|
|
struct amount_msat b)
|
|
|
|
{
|
|
|
|
return amount_msat_greater(a,b) ? a : b;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the knowledge that this (channel,direction) can send x msat.*/
|
2023-12-18 14:18:00 +01:00
|
|
|
bool chan_extra_can_send(const tal_t *ctx,
|
|
|
|
struct chan_extra_map *chan_extra_map,
|
2023-08-21 07:37:07 +02:00
|
|
|
const struct short_channel_id_dir *scidd,
|
2023-12-24 10:28:55 +01:00
|
|
|
char **fail);
|
2023-07-31 03:51:22 +02:00
|
|
|
|
|
|
|
/* Update the knowledge that this (channel,direction) cannot send x msat.*/
|
2023-12-18 14:18:00 +01:00
|
|
|
bool chan_extra_cannot_send(const tal_t *ctx,
|
|
|
|
struct chan_extra_map *chan_extra_map,
|
2023-08-21 07:37:07 +02:00
|
|
|
const struct short_channel_id_dir *scidd,
|
2023-12-24 10:28:55 +01:00
|
|
|
char **fail);
|
2023-07-31 03:51:22 +02:00
|
|
|
|
|
|
|
/* Update the knowledge that this (channel,direction) has liquidity x.*/
|
2023-12-18 14:18:00 +01:00
|
|
|
bool chan_extra_set_liquidity(const tal_t *ctx,
|
|
|
|
struct chan_extra_map *chan_extra_map,
|
2023-08-21 07:37:07 +02:00
|
|
|
const struct short_channel_id_dir *scidd,
|
2023-12-18 14:18:00 +01:00
|
|
|
struct amount_msat x, char **fail);
|
2023-07-31 03:51:22 +02:00
|
|
|
|
|
|
|
/* Update the knowledge that this (channel,direction) has sent x msat.*/
|
2023-12-18 14:18:00 +01:00
|
|
|
bool chan_extra_sent_success(const tal_t *ctx,
|
|
|
|
struct chan_extra_map *chan_extra_map,
|
2023-08-21 07:37:07 +02:00
|
|
|
const struct short_channel_id_dir *scidd,
|
2023-12-18 14:18:00 +01:00
|
|
|
struct amount_msat x, char **fail);
|
2023-07-31 03:51:22 +02:00
|
|
|
|
2023-07-31 03:51:25 +02:00
|
|
|
/* Forget the channel information by a fraction of the capacity. */
|
2023-12-18 14:18:00 +01:00
|
|
|
bool chan_extra_relax_fraction(const tal_t *ctx, struct chan_extra *ce,
|
|
|
|
double fraction, char **fail);
|
2023-07-31 03:51:22 +02:00
|
|
|
|
|
|
|
/* Returns either NULL, or an entry from the hash */
|
|
|
|
struct chan_extra_half *get_chan_extra_half_by_scid(struct chan_extra_map *chan_extra_map,
|
2023-08-21 07:37:07 +02:00
|
|
|
const struct short_channel_id_dir *scidd);
|
2023-07-31 03:51:22 +02:00
|
|
|
/* If the channel is not registered, then a new entry is created. scid must be
|
|
|
|
* present in the gossmap. */
|
|
|
|
struct chan_extra_half *
|
|
|
|
get_chan_extra_half_by_chan_verify(
|
|
|
|
const struct gossmap *gossmap,
|
|
|
|
struct chan_extra_map *chan_extra_map,
|
|
|
|
const struct gossmap_chan *chan,
|
|
|
|
int dir);
|
|
|
|
|
|
|
|
/* Helper if we have a gossmap_chan */
|
|
|
|
struct chan_extra_half *get_chan_extra_half_by_chan(const struct gossmap *gossmap,
|
|
|
|
struct chan_extra_map *chan_extra_map,
|
|
|
|
const struct gossmap_chan *chan,
|
|
|
|
int dir);
|
|
|
|
|
|
|
|
/* An actual partial flow. */
|
|
|
|
struct flow {
|
2023-07-31 03:51:25 +02:00
|
|
|
const struct gossmap_chan **path;
|
2023-07-31 03:51:22 +02:00
|
|
|
/* The directions to traverse. */
|
|
|
|
int *dirs;
|
|
|
|
/* Amounts for this flow (fees mean this shrinks across path). */
|
|
|
|
struct amount_msat *amounts;
|
|
|
|
/* Probability of success (0-1) */
|
|
|
|
double success_prob;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Helper to access the half chan at flow index idx */
|
|
|
|
const struct half_chan *flow_edge(const struct flow *flow, size_t idx);
|
|
|
|
|
|
|
|
/* A big number, meaning "don't bother" (not infinite, since you may add) */
|
|
|
|
#define FLOW_INF_COST 100000000.0
|
|
|
|
|
|
|
|
/* Cost function to send @f msat through @c in direction @dir,
|
|
|
|
* given we already have a flow of prev_flow. */
|
|
|
|
double flow_edge_cost(const struct gossmap *gossmap,
|
|
|
|
const struct gossmap_chan *c, int dir,
|
|
|
|
const struct amount_msat known_min,
|
|
|
|
const struct amount_msat known_max,
|
|
|
|
struct amount_msat prev_flow,
|
|
|
|
struct amount_msat f,
|
|
|
|
double mu,
|
|
|
|
double basefee_penalty,
|
|
|
|
double delay_riskfactor);
|
|
|
|
|
|
|
|
/* Function to fill in amounts and success_prob for flow. */
|
2023-12-18 14:18:00 +01:00
|
|
|
bool flow_complete(const tal_t *ctx, struct flow *flow,
|
2023-07-31 03:51:22 +02:00
|
|
|
const struct gossmap *gossmap,
|
|
|
|
struct chan_extra_map *chan_extra_map,
|
2023-12-18 14:18:00 +01:00
|
|
|
struct amount_msat delivered, char **fail);
|
2023-07-31 03:51:22 +02:00
|
|
|
|
|
|
|
/* Compute the prob. of success of a set of concurrent set of flows. */
|
2023-12-18 14:18:00 +01:00
|
|
|
double flowset_probability(const tal_t *ctx, struct flow **flows,
|
|
|
|
const struct gossmap *const gossmap,
|
|
|
|
struct chan_extra_map *chan_extra_map, char **fail);
|
2023-07-31 03:51:22 +02:00
|
|
|
|
|
|
|
// TODO(eduardo): we probably don't need this. Instead we should have payflow
|
|
|
|
// input.
|
|
|
|
/* Once flow is completed, this can remove it from the extra_map */
|
2023-12-18 14:18:00 +01:00
|
|
|
bool remove_completed_flow(const tal_t *ctx, const struct gossmap *gossmap,
|
2023-07-31 03:51:22 +02:00
|
|
|
struct chan_extra_map *chan_extra_map,
|
2023-12-18 14:18:00 +01:00
|
|
|
struct flow *flow, char **fail);
|
|
|
|
|
2023-07-31 03:51:22 +02:00
|
|
|
// TODO(eduardo): we probably don't need this. Instead we should have payflow
|
|
|
|
// input.
|
2023-12-18 14:18:00 +01:00
|
|
|
bool remove_completed_flowset(const tal_t *ctx, const struct gossmap *gossmap,
|
|
|
|
struct chan_extra_map *chan_extra_map,
|
|
|
|
struct flow **flows, char **fail);
|
2023-07-31 03:51:22 +02:00
|
|
|
|
2023-12-18 14:18:00 +01:00
|
|
|
bool flowset_fee(struct amount_msat *fee, struct flow **flows);
|
2023-07-31 03:51:22 +02:00
|
|
|
|
|
|
|
// TODO(eduardo): we probably don't need this. Instead we should have payflow
|
|
|
|
// input.
|
|
|
|
/* Take the flows and commit them to the chan_extra's . */
|
2023-12-18 14:18:00 +01:00
|
|
|
bool commit_flow(const tal_t *ctx, const struct gossmap *gossmap,
|
|
|
|
struct chan_extra_map *chan_extra_map, struct flow *flow,
|
|
|
|
char **fail);
|
2023-07-31 03:51:22 +02:00
|
|
|
|
|
|
|
// TODO(eduardo): we probably don't need this. Instead we should have payflow
|
|
|
|
// input.
|
2023-12-24 09:01:08 +01:00
|
|
|
/* Take the flows and commit them to the chan_extra's .
|
|
|
|
* Returns the number of flows successfully commited. */
|
|
|
|
size_t commit_flowset(const tal_t *ctx, const struct gossmap *gossmap,
|
2023-12-18 14:18:00 +01:00
|
|
|
struct chan_extra_map *chan_extra_map, struct flow **flows,
|
|
|
|
char **fail);
|
2023-07-31 03:51:22 +02:00
|
|
|
|
2024-01-25 07:13:43 +01:00
|
|
|
/* flows should be a set of optimal routes delivering an amount that is
|
|
|
|
* slighty less than amount_to_deliver. We will try to reallocate amounts in
|
|
|
|
* these flows so that it delivers the exact amount_to_deliver to the
|
|
|
|
* destination.
|
|
|
|
* Returns how much we are delivering at the end. */
|
|
|
|
bool flows_fit_amount(const tal_t *ctx, struct amount_msat *amount_allocated,
|
|
|
|
struct flow **flows, struct amount_msat amount_to_deliver,
|
|
|
|
const struct gossmap *gossmap,
|
|
|
|
struct chan_extra_map *chan_extra_map, char **fail);
|
|
|
|
|
2024-01-29 08:57:05 +01:00
|
|
|
/* Helpers to get the htlc_max and htlc_min of a channel. */
|
|
|
|
static inline struct amount_msat
|
|
|
|
channel_htlc_max(const struct gossmap_chan *chan, const int dir)
|
|
|
|
{
|
|
|
|
return amount_msat(fp16_to_u64(chan->half[dir].htlc_max));
|
|
|
|
}
|
|
|
|
static inline struct amount_msat
|
|
|
|
channel_htlc_min(const struct gossmap_chan *chan, const int dir)
|
|
|
|
{
|
|
|
|
return amount_msat(fp16_to_u64(chan->half[dir].htlc_min));
|
|
|
|
}
|
|
|
|
|
2023-07-31 03:51:22 +02:00
|
|
|
#endif /* LIGHTNING_PLUGINS_RENEPAY_FLOW_H */
|