forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun-route-specific.c
300 lines (263 loc) · 12.5 KB
/
run-route-specific.c
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
/* We can't seem to route the following:
*
* Expect route 03c173897878996287a8100469f954dd820fcd8941daed91c327f168f3329be0bf -> 0230ad0e74ea03976b28fda587bb75bdd357a1938af4424156a18265167f5e40ae -> 02ea622d5c8d6143f15ed3ce1d501dd0d3d09d3b1c83a44d0034949f8a9ab60f06
*
* getchannels:
* {'channels': [{'active': True, 'short_id': '6990x2x1/1', 'fee_per_kw': 10, 'delay': 5, 'message_flags': 0, 'channel_flags': 1, 'destination': '0230ad0e74ea03976b28fda587bb75bdd357a1938af4424156a18265167f5e40ae', 'source': '02ea622d5c8d6143f15ed3ce1d501dd0d3d09d3b1c83a44d0034949f8a9ab60f06', 'last_update': 1504064344}, {'active': True, 'short_id': '6989x2x1/0', 'fee_per_kw': 10, 'delay': 5, 'message_flags': 0, 'channel_flags': 0, 'destination': '03c173897878996287a8100469f954dd820fcd8941daed91c327f168f3329be0bf', 'source': '0230ad0e74ea03976b28fda587bb75bdd357a1938af4424156a18265167f5e40ae', 'last_update': 1504064344}, {'active': True, 'short_id': '6990x2x1/0', 'fee_per_kw': 10, 'delay': 5, 'message_flags': 0, 'channel_flags': 0, 'destination': '02ea622d5c8d6143f15ed3ce1d501dd0d3d09d3b1c83a44d0034949f8a9ab60f06', 'source': '0230ad0e74ea03976b28fda587bb75bdd357a1938af4424156a18265167f5e40ae', 'last_update': 1504064344}, {'active': True, 'short_id': '6989x2x1/1', 'fee_per_kw': 10, 'delay': 5, 'message_flags': 0, 'channel_flags': 1, 'destination': '0230ad0e74ea03976b28fda587bb75bdd357a1938af4424156a18265167f5e40ae', 'source': '03c173897878996287a8100469f954dd820fcd8941daed91c327f168f3329be0bf', 'last_update': 1504064344}]}
*/
#include "config.h"
#include <assert.h>
#include <common/channel_type.h>
#include <common/dijkstra.h>
#include <common/gossmap.h>
#include <common/gossip_store.h>
#include <common/route.h>
#include <common/setup.h>
#include <common/type_to_string.h>
#include <common/utils.h>
#include <bitcoin/chainparams.h>
#include <stdio.h>
#include <wire/peer_wiregen.h>
#include <unistd.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for fromwire_bigsize */
bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_bigsize called!\n"); abort(); }
/* Generated stub for fromwire_channel_id */
bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
struct channel_id *channel_id UNNEEDED)
{ fprintf(stderr, "fromwire_channel_id called!\n"); abort(); }
/* Generated stub for fromwire_tlv */
bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
const struct tlv_record_type *types UNNEEDED, size_t num_types UNNEEDED,
void *record UNNEEDED, struct tlv_field **fields UNNEEDED,
const u64 *extra_types UNNEEDED, size_t *err_off UNNEEDED, u64 *err_type UNNEEDED)
{ fprintf(stderr, "fromwire_tlv called!\n"); abort(); }
/* Generated stub for towire_bigsize */
void towire_bigsize(u8 **pptr UNNEEDED, const bigsize_t val UNNEEDED)
{ fprintf(stderr, "towire_bigsize called!\n"); abort(); }
/* Generated stub for towire_channel_id */
void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id UNNEEDED)
{ fprintf(stderr, "towire_channel_id called!\n"); abort(); }
/* Generated stub for towire_tlv */
void towire_tlv(u8 **pptr UNNEEDED,
const struct tlv_record_type *types UNNEEDED, size_t num_types UNNEEDED,
const void *record UNNEEDED)
{ fprintf(stderr, "towire_tlv called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
static void write_to_store(int store_fd, const u8 *msg)
{
struct gossip_hdr hdr;
hdr.flags = cpu_to_be16(0);
hdr.len = cpu_to_be16(tal_count(msg));
/* We don't actually check these! */
hdr.crc = 0;
hdr.timestamp = 0;
assert(write(store_fd, &hdr, sizeof(hdr)) == sizeof(hdr));
assert(write(store_fd, msg, tal_count(msg)) == tal_count(msg));
}
static void update_connection(int store_fd,
const struct node_id *from,
const struct node_id *to,
const char *shortid,
struct amount_msat min,
struct amount_msat max,
u32 base_fee, s32 proportional_fee,
u32 delay,
bool disable)
{
struct short_channel_id scid;
secp256k1_ecdsa_signature dummy_sig;
u8 *msg;
/* So valgrind doesn't complain */
memset(&dummy_sig, 0, sizeof(dummy_sig));
if (!short_channel_id_from_str(shortid, strlen(shortid), &scid))
abort();
msg = towire_channel_update(tmpctx,
&dummy_sig,
&chainparams->genesis_blockhash,
&scid, 0,
ROUTING_OPT_HTLC_MAX_MSAT,
node_id_idx(from, to)
+ (disable ? ROUTING_FLAGS_DISABLED : 0),
delay,
min,
base_fee,
proportional_fee,
max);
write_to_store(store_fd, msg);
}
static void add_connection(int store_fd,
const struct node_id *from,
const struct node_id *to,
const char *shortid,
struct amount_msat min,
struct amount_msat max,
u32 base_fee, s32 proportional_fee,
u32 delay)
{
struct short_channel_id scid;
secp256k1_ecdsa_signature dummy_sig;
struct secret not_a_secret;
struct pubkey dummy_key;
u8 *msg;
const struct node_id *ids[2];
/* So valgrind doesn't complain */
memset(&dummy_sig, 0, sizeof(dummy_sig));
memset(¬_a_secret, 1, sizeof(not_a_secret));
pubkey_from_secret(¬_a_secret, &dummy_key);
if (!short_channel_id_from_str(shortid, strlen(shortid), &scid))
abort();
if (node_id_cmp(from, to) > 0) {
ids[0] = to;
ids[1] = from;
} else {
ids[0] = from;
ids[1] = to;
}
msg = towire_channel_announcement(tmpctx, &dummy_sig, &dummy_sig,
&dummy_sig, &dummy_sig,
/* features */ NULL,
&chainparams->genesis_blockhash,
&scid,
ids[0], ids[1],
&dummy_key, &dummy_key);
write_to_store(store_fd, msg);
update_connection(store_fd, from, to, shortid, min, max,
base_fee, proportional_fee,
delay, false);
}
static bool channel_is_between(const struct gossmap *gossmap,
const struct route_hop *route,
const struct gossmap_node *a,
const struct gossmap_node *b)
{
const struct gossmap_chan *c = gossmap_find_chan(gossmap, &route->scid);
if (c->half[route->direction].nodeidx
!= gossmap_node_idx(gossmap, a))
return false;
if (c->half[!route->direction].nodeidx
!= gossmap_node_idx(gossmap, b))
return false;
return true;
}
/* route_can_carry disregards unless *both* dirs are enabled, so we use
* a simpler variant here */
static bool route_can_carry_unless_disabled(const struct gossmap *map,
const struct gossmap_chan *c,
int dir,
struct amount_msat amount,
void *arg)
{
if (!c->half[dir].enabled)
return false;
return route_can_carry_even_disabled(map, c, dir, amount, arg);
}
int main(int argc, char *argv[])
{
struct node_id a, b, c, d;
struct gossmap_node *a_node, *b_node, *c_node, *d_node;
const struct dijkstra *dij;
struct route_hop *route;
int store_fd;
struct gossmap *gossmap;
const double riskfactor = 1.0;
char gossip_version = 10;
char *gossipfilename;
common_setup(argv[0]);
node_id_from_hexstr("03c173897878996287a8100469f954dd820fcd8941daed91c327f168f3329be0bf",
strlen("03c173897878996287a8100469f954dd820fcd8941daed91c327f168f3329be0bf"),
&a);
node_id_from_hexstr("0230ad0e74ea03976b28fda587bb75bdd357a1938af4424156a18265167f5e40ae",
strlen("0230ad0e74ea03976b28fda587bb75bdd357a1938af4424156a18265167f5e40ae"),
&b);
node_id_from_hexstr("02ea622d5c8d6143f15ed3ce1d501dd0d3d09d3b1c83a44d0034949f8a9ab60f06",
strlen("02ea622d5c8d6143f15ed3ce1d501dd0d3d09d3b1c83a44d0034949f8a9ab60f06"),
&c);
node_id_from_hexstr("02cca6c5c966fcf61d121e3a70e03a1cd9eeeea024b26ea666ce974d43b242e636",
strlen("02cca6c5c966fcf61d121e3a70e03a1cd9eeeea024b26ea666ce974d43b242e636"),
&d);
chainparams = chainparams_for_network("regtest");
store_fd = tmpdir_mkstemp(tmpctx, "run-route-specific-gossipstore.XXXXXX", &gossipfilename);
assert(write(store_fd, &gossip_version, sizeof(gossip_version))
== sizeof(gossip_version));
gossmap = gossmap_load(tmpctx, gossipfilename, NULL);
/* [{'active': True, 'short_id': '6990:2:1/1', 'fee_per_kw': 10, 'delay': 5, 'message_flags': 0, 'channel_flags': 1, 'destination': '0230ad0e74ea03976b28fda587bb75bdd357a1938af4424156a18265167f5e40ae', 'source': '02ea622d5c8d6143f15ed3ce1d501dd0d3d09d3b1c83a44d0034949f8a9ab60f06', 'last_update': 1504064344}, */
add_connection(store_fd, &c, &b, "6990x2x1",
AMOUNT_MSAT(0), AMOUNT_MSAT(1000),
0, 10, 5);
/* {'active': True, 'short_id': '6989:2:1/0', 'fee_per_kw': 10, 'delay': 5, 'message_flags': 0, 'channel_flags': 0, 'destination': '03c173897878996287a8100469f954dd820fcd8941daed91c327f168f3329be0bf', 'source': '0230ad0e74ea03976b28fda587bb75bdd357a1938af4424156a18265167f5e40ae', 'last_update': 1504064344}, */
add_connection(store_fd, &b, &a, "6989x2x1",
AMOUNT_MSAT(0), AMOUNT_MSAT(1000),
0, 10, 5);
/* {'active': True, 'short_id': '6990:2:1/0', 'fee_per_kw': 10, 'delay': 5, 'message_flags': 0, 'channel_flags': 0, 'destination': '02ea622d5c8d6143f15ed3ce1d501dd0d3d09d3b1c83a44d0034949f8a9ab60f06', 'source': '0230ad0e74ea03976b28fda587bb75bdd357a1938af4424156a18265167f5e40ae', 'last_update': 1504064344}, */
update_connection(store_fd, &b, &c, "6990x2x1",
AMOUNT_MSAT(100), AMOUNT_MSAT(1000),
0, 10, 5, false);
/* {'active': True, 'short_id': '6989:2:1/1', 'fee_per_kw': 10, 'delay': 5, 'message_flags': 0, 'channel_flags': 1, 'destination': '0230ad0e74ea03976b28fda587bb75bdd357a1938af4424156a18265167f5e40ae', 'source': '03c173897878996287a8100469f954dd820fcd8941daed91c327f168f3329be0bf', 'last_update': 1504064344}]} */
update_connection(store_fd, &a, &b, "6989x2x1",
AMOUNT_MSAT(0), AMOUNT_MSAT(1000),
0, 10, 5, false);
assert(gossmap_refresh(gossmap, NULL));
a_node = gossmap_find_node(gossmap, &a);
b_node = gossmap_find_node(gossmap, &b);
c_node = gossmap_find_node(gossmap, &c);
dij = dijkstra(tmpctx, gossmap, c_node, AMOUNT_MSAT(1000), riskfactor,
route_can_carry_unless_disabled,
route_score_cheaper, NULL);
route = route_from_dijkstra(tmpctx, gossmap, dij, a_node,
AMOUNT_MSAT(1000), 0);
assert(route);
assert(tal_count(route) == 2);
assert(channel_is_between(gossmap, &route[0], a_node, b_node));
assert(channel_is_between(gossmap, &route[1], b_node, c_node));
/* We should not be able to find a route that exceeds our own capacity */
dij = dijkstra(tmpctx, gossmap, c_node, AMOUNT_MSAT(1000001), riskfactor,
route_can_carry_unless_disabled,
route_score_cheaper, NULL);
route = route_from_dijkstra(tmpctx, gossmap, dij, a_node,
AMOUNT_MSAT(1000), 0);
assert(!route);
/* Now test with a query that exceeds the channel capacity after adding
* some fees */
dij = dijkstra(tmpctx, gossmap, c_node, AMOUNT_MSAT(999999), riskfactor,
route_can_carry_unless_disabled,
route_score_cheaper, NULL);
route = route_from_dijkstra(tmpctx, gossmap, dij, a_node,
AMOUNT_MSAT(999999), 0);
assert(!route);
/* This should fail to return a route because it is smaller than these
* htlc_minimum_msat on the last channel. */
dij = dijkstra(tmpctx, gossmap, c_node, AMOUNT_MSAT(1), riskfactor,
route_can_carry_unless_disabled,
route_score_cheaper, NULL);
route = route_from_dijkstra(tmpctx, gossmap, dij, a_node,
AMOUNT_MSAT(1), 0);
assert(!route);
/* {'active': True, 'short_id': '6990:2:1/0', 'fee_per_kw': 10, 'delay': 5, 'message_flags': 1, 'htlc_maximum_msat': 500000, 'htlc_minimum_msat': 100, 'channel_flags': 0, 'destination': '02cca6c5c966fcf61d121e3a70e03a1cd9eeeea024b26ea666ce974d43b242e636', 'source': '03c173897878996287a8100469f954dd820fcd8941daed91c327f168f3329be0bf', 'last_update': 1504064344}, */
add_connection(store_fd, &a, &d, "6991x2x1",
AMOUNT_MSAT(100), AMOUNT_MSAT(499968), /* exact repr in fp16! */
0, 0, 5);
assert(gossmap_refresh(gossmap, NULL));
a_node = gossmap_find_node(gossmap, &a);
b_node = gossmap_find_node(gossmap, &b);
c_node = gossmap_find_node(gossmap, &c);
d_node = gossmap_find_node(gossmap, &d);
/* This should route correctly at the max_msat level */
dij = dijkstra(tmpctx, gossmap, d_node, AMOUNT_MSAT(499968), riskfactor,
route_can_carry_unless_disabled,
route_score_cheaper, NULL);
route = route_from_dijkstra(tmpctx, gossmap, dij, a_node,
AMOUNT_MSAT(499968), 0);
assert(route);
/* This should fail to return a route because it's larger than the
* htlc_maximum_msat on the last channel. */
dij = dijkstra(tmpctx, gossmap, d_node, AMOUNT_MSAT(499968+1), riskfactor,
route_can_carry_unless_disabled,
route_score_cheaper, NULL);
route = route_from_dijkstra(tmpctx, gossmap, dij, a_node,
AMOUNT_MSAT(499968+1), 0);
assert(!route);
common_shutdown();
return 0;
}