forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 0
/
flow.h
324 lines (286 loc) · 10.4 KB
/
flow.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
#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>
#include <plugins/renepay/payment.h>
// 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];
};
bool chan_extra_is_busy(const struct chan_extra *const ce);
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);
/* 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);
/* This helper function preserves the uncertainty network invariant after the
* knowledge is updated. It assumes that the (channel,!dir) knowledge is
* correct. */
void chan_extra_adjust_half(struct chan_extra *ce,
int dir);
/* 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.*/
void chan_extra_can_send(struct chan_extra_map *chan_extra_map,
struct short_channel_id scid,
int dir,
struct amount_msat x);
/* Update the knowledge that this (channel,direction) cannot send x msat.*/
void chan_extra_cannot_send(struct payment* p,
struct chan_extra_map *chan_extra_map,
struct short_channel_id scid,
int dir,
struct amount_msat x);
/* Update the knowledge that this (channel,direction) has liquidity x.*/
void chan_extra_set_liquidity(struct chan_extra_map *chan_extra_map,
struct short_channel_id scid,
int dir,
struct amount_msat x);
/* Update the knowledge that this (channel,direction) has sent x msat.*/
void chan_extra_sent_success(struct chan_extra_map *chan_extra_map,
struct short_channel_id scid,
int dir,
struct amount_msat x);
/* Forget a bit about this (channel,direction) state. */
void chan_extra_relax(struct chan_extra_map *chan_extra_map,
struct short_channel_id scid,
int dir,
struct amount_msat down,
struct amount_msat up);
/* Forget the channel information by a fraction of the capacity. */
void chan_extra_relax_fraction(
struct chan_extra* ce,
double fraction);
/* 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,
const struct short_channel_id scid,
int dir);
/* 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 {
const struct gossmap_chan **path;
/* 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. */
void flow_complete(struct flow *flow,
const struct gossmap *gossmap,
struct chan_extra_map *chan_extra_map,
struct amount_msat delivered);
/* Compute the prob. of success of a set of concurrent set of flows. */
double flow_set_probability(
struct flow ** flows,
const struct gossmap *const gossmap,
struct chan_extra_map * chan_extra_map);
// 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 */
void remove_completed_flow(const struct gossmap *gossmap,
struct chan_extra_map *chan_extra_map,
struct flow *flow);
// TODO(eduardo): we probably don't need this. Instead we should have payflow
// input.
void remove_completed_flow_set(const struct gossmap *gossmap,
struct chan_extra_map *chan_extra_map,
struct flow **flows);
struct amount_msat flow_set_fee(struct flow **flows);
/*
* mu (μ) is used as follows in the cost function:
*
* -log((c_e + 1 - f_e) / (c_e + 1)) + μ fee
*
* This raises the question of how to set mu? The left term is a
* logrithmic failure probability, the right term is the fee in
* millisats.
*
* We want a more "usable" measure of frugality (fr), where fr = 1
* means that the two terms are roughly equal, and fr < 1 means the
* probability is more important, and fr > 1 means the fee is more
* important.
*
* For this we take the current payment amount and the median channel
* capacity and feerates:
*
* -log((median_cap + 1 - f_e) / (median_cap + 1)) = μ (1/fr) median_fee
*
* => μ = -log((median_cap + 1 - f_e) / (median_cap + 1)) * fr / median_fee
*
* But this is slightly too naive! If we're trying to make a payment larger
* than the median, this is undefined; and grows hugely when we're near the median.
* In fact, it should be "the median of all channels larger than the amount",
* which is what we calculate here.
*
* Turns out that in the real network:
* - median_cap = 1250800000
* - median_feerate = 51
*
* And the log term at the 10th percentile capacity is about 0.125 of the median,
* and at the 90th percentile capacity the log term is about 12.5 the value at the median.
*
* In other words, we expose a simple frugality knob with reasonable
* range 0.1 (don't care about fees) to 10 (fees before probability),
* and generate our μ from there.
*/
double derive_mu(const struct gossmap *gossmap,
struct amount_msat amount,
double frugality);
s64 linear_fee_cost(
const struct gossmap_chan *c,
const int dir,
double base_fee_penalty,
double delay_feefactor);
// 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 . */
void commit_flow(
const struct gossmap *gossmap,
struct chan_extra_map *chan_extra_map,
struct flow *flow);
// 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 . */
void commit_flow_set(
const struct gossmap *gossmap,
struct chan_extra_map *chan_extra_map,
struct flow **flows);
#endif /* LIGHTNING_PLUGINS_RENEPAY_FLOW_H */