mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-26 20:30:59 +01:00
renepay: test channel capacity unavailable
Add a test that checks `get_route` and `uncertainty_update` behaviour's handling of missing channel capacities. Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
This commit is contained in:
parent
d30b1c8dc2
commit
4b8d9116de
4 changed files with 305 additions and 112 deletions
|
@ -10,9 +10,14 @@ $(PLUGIN_RENEPAY_TEST_OBJS): $(PLUGIN_RENEPAY_SRC)
|
|||
|
||||
PLUGIN_RENEPAY_TEST_COMMON_OBJS := \
|
||||
plugins/renepay/dijkstra.o \
|
||||
plugins/renepay/chan_extra.o
|
||||
plugins/renepay/chan_extra.o \
|
||||
bitcoin/chainparams.o \
|
||||
common/gossmap.o \
|
||||
common/fp16.o \
|
||||
common/dijkstra.o \
|
||||
gossipd/gossip_store_wiregen.o
|
||||
|
||||
$(PLUGIN_RENEPAY_TEST_PROGRAMS): $(PLUGIN_RENEPAY_TEST_COMMON_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) bitcoin/chainparams.o common/gossmap.o common/fp16.o common/dijkstra.o gossipd/gossip_store_wiregen.o
|
||||
$(PLUGIN_RENEPAY_TEST_PROGRAMS): $(PLUGIN_RENEPAY_TEST_COMMON_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS)
|
||||
|
||||
check-renepay: $(PLUGIN_RENEPAY_TEST_PROGRAMS:%=unittest/%)
|
||||
|
||||
|
|
110
plugins/renepay/test/common.h
Normal file
110
plugins/renepay/test/common.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
#ifndef LIGHTNING_PLUGINS_RENEPAY_TEST_COMMON_H
|
||||
#define LIGHTNING_PLUGINS_RENEPAY_TEST_COMMON_H
|
||||
#include "config.h"
|
||||
#include <common/gossip_store.h>
|
||||
#include <gossipd/gossip_store_wiregen.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <wire/peer_wiregen.h>
|
||||
|
||||
static const char *print_routes(const tal_t *ctx,
|
||||
struct route **routes)
|
||||
{
|
||||
tal_t *this_ctx = tal(ctx, tal_t);
|
||||
char *buff = tal_fmt(ctx, "%zu routes\n", tal_count(routes));
|
||||
for (size_t i = 0; i < tal_count(routes); i++) {
|
||||
struct amount_msat fee, delivered;
|
||||
|
||||
delivered = route_delivers(routes[i]);
|
||||
fee = route_fees(routes[i]);
|
||||
tal_append_fmt(&buff, " %s", fmt_route_path(this_ctx, routes[i]));
|
||||
tal_append_fmt(&buff, " %s delivered with fee %s\n",
|
||||
fmt_amount_msat(this_ctx, delivered),
|
||||
fmt_amount_msat(this_ctx, fee));
|
||||
}
|
||||
|
||||
tal_free(this_ctx);
|
||||
return buff;
|
||||
}
|
||||
|
||||
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 add_connection(int store_fd,
|
||||
const struct node_id *from,
|
||||
const struct node_id *to,
|
||||
struct short_channel_id scid,
|
||||
struct amount_msat min,
|
||||
struct amount_msat max,
|
||||
u32 base_fee, s32 proportional_fee,
|
||||
u32 delay,
|
||||
struct amount_sat capacity,
|
||||
bool add_capacity)
|
||||
{
|
||||
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 (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);
|
||||
|
||||
if (add_capacity) {
|
||||
msg = towire_gossip_store_channel_amount(tmpctx, capacity);
|
||||
write_to_store(store_fd, msg);
|
||||
}
|
||||
|
||||
u8 flags = node_id_idx(from, to);
|
||||
|
||||
msg = towire_channel_update(tmpctx,
|
||||
&dummy_sig,
|
||||
&chainparams->genesis_blockhash,
|
||||
scid, 0,
|
||||
ROUTING_OPT_HTLC_MAX_MSAT,
|
||||
flags,
|
||||
delay,
|
||||
min,
|
||||
base_fee,
|
||||
proportional_fee,
|
||||
max);
|
||||
write_to_store(store_fd, msg);
|
||||
}
|
||||
|
||||
static void node_id_from_privkey(const struct privkey *p, struct node_id *id)
|
||||
{
|
||||
struct pubkey k;
|
||||
pubkey_from_privkey(p, &k);
|
||||
node_id_from_pubkey(id, &k);
|
||||
}
|
||||
|
||||
|
||||
#endif /* LIGHTNING_PLUGINS_RENEPAY_TEST_COMMON_H */
|
|
@ -1,3 +1,5 @@
|
|||
/* Checks that get_route can handle bottleneck situations assigning values to
|
||||
* routes that do not exceed the liquidity constraints. */
|
||||
#include "config.h"
|
||||
|
||||
#include "../errorcodes.c"
|
||||
|
@ -7,18 +9,14 @@
|
|||
#include "../disabledmap.c"
|
||||
#include "../route.c"
|
||||
#include "../routebuilder.c"
|
||||
#include "common.h"
|
||||
|
||||
#include <bitcoin/chainparams.h>
|
||||
#include <bitcoin/preimage.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <common/gossip_store.h>
|
||||
#include <common/setup.h>
|
||||
#include <common/utils.h>
|
||||
#include <gossipd/gossip_store_wiregen.h>
|
||||
#include <sodium/randombytes.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <wire/peer_wiregen.h>
|
||||
|
||||
static u8 empty_map[] = {10};
|
||||
|
||||
|
@ -56,102 +54,6 @@ static const char *print_flows(const tal_t *ctx, const char *desc,
|
|||
return buff;
|
||||
}
|
||||
|
||||
static const char *print_routes(const tal_t *ctx,
|
||||
struct route **routes)
|
||||
{
|
||||
tal_t *this_ctx = tal(ctx, tal_t);
|
||||
char *buff = tal_fmt(ctx, "%zu routes\n", tal_count(routes));
|
||||
for (size_t i = 0; i < tal_count(routes); i++) {
|
||||
struct amount_msat fee, delivered;
|
||||
|
||||
delivered = route_delivers(routes[i]);
|
||||
fee = route_fees(routes[i]);
|
||||
tal_append_fmt(&buff, " %s", fmt_route_path(this_ctx, routes[i]));
|
||||
tal_append_fmt(&buff, " %s delivered with fee %s\n",
|
||||
fmt_amount_msat(this_ctx, delivered),
|
||||
fmt_amount_msat(this_ctx, fee));
|
||||
}
|
||||
|
||||
tal_free(this_ctx);
|
||||
return buff;
|
||||
}
|
||||
|
||||
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 add_connection(int store_fd,
|
||||
const struct node_id *from,
|
||||
const struct node_id *to,
|
||||
struct short_channel_id scid,
|
||||
struct amount_msat min,
|
||||
struct amount_msat max,
|
||||
u32 base_fee, s32 proportional_fee,
|
||||
u32 delay,
|
||||
struct amount_sat capacity)
|
||||
{
|
||||
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 (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);
|
||||
|
||||
msg = towire_gossip_store_channel_amount(tmpctx, capacity);
|
||||
write_to_store(store_fd, msg);
|
||||
|
||||
u8 flags = node_id_idx(from, to);
|
||||
|
||||
msg = towire_channel_update(tmpctx,
|
||||
&dummy_sig,
|
||||
&chainparams->genesis_blockhash,
|
||||
scid, 0,
|
||||
ROUTING_OPT_HTLC_MAX_MSAT,
|
||||
flags,
|
||||
delay,
|
||||
min,
|
||||
base_fee,
|
||||
proportional_fee,
|
||||
max);
|
||||
write_to_store(store_fd, msg);
|
||||
}
|
||||
|
||||
static void node_id_from_privkey(const struct privkey *p, struct node_id *id)
|
||||
{
|
||||
struct pubkey k;
|
||||
pubkey_from_privkey(p, &k);
|
||||
node_id_from_pubkey(id, &k);
|
||||
}
|
||||
|
||||
#define NUM_NODES 8
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -201,28 +103,32 @@ int main(int argc, char *argv[])
|
|||
AMOUNT_MSAT(0),
|
||||
AMOUNT_MSAT(60 * 1000 * 1000),
|
||||
0, 0, 5,
|
||||
AMOUNT_SAT(60 * 1000));
|
||||
AMOUNT_SAT(60 * 1000),
|
||||
true);
|
||||
|
||||
assert(mk_short_channel_id(&scid, 1, 3, 0));
|
||||
add_connection(fd, &nodes[0], &nodes[2], scid,
|
||||
AMOUNT_MSAT(0),
|
||||
AMOUNT_MSAT(60 * 1000 * 1000),
|
||||
0, 0, 5,
|
||||
AMOUNT_SAT(60 * 1000));
|
||||
AMOUNT_SAT(60 * 1000),
|
||||
true);
|
||||
|
||||
assert(mk_short_channel_id(&scid, 2, 4, 0));
|
||||
add_connection(fd, &nodes[1], &nodes[3], scid,
|
||||
AMOUNT_MSAT(0),
|
||||
AMOUNT_MSAT(1000 * 1000 * 1000),
|
||||
0, 0, 5,
|
||||
AMOUNT_SAT(1000 * 1000));
|
||||
AMOUNT_SAT(1000 * 1000),
|
||||
true);
|
||||
|
||||
assert(mk_short_channel_id(&scid, 3, 4, 0));
|
||||
add_connection(fd, &nodes[2], &nodes[3], scid,
|
||||
AMOUNT_MSAT(0),
|
||||
AMOUNT_MSAT(1000 * 1000 * 1000),
|
||||
0, 0, 5,
|
||||
AMOUNT_SAT(1000 * 1000));
|
||||
AMOUNT_SAT(1000 * 1000),
|
||||
true);
|
||||
|
||||
assert(mk_short_channel_id(&scid, 4, 5, 0));
|
||||
add_connection(fd, &nodes[3], &nodes[4], scid,
|
||||
|
@ -232,35 +138,40 @@ int main(int argc, char *argv[])
|
|||
* through this channel. */
|
||||
AMOUNT_MSAT(106 * 1000 * 1000),
|
||||
0, 0, 5,
|
||||
AMOUNT_SAT(110 * 1000));
|
||||
AMOUNT_SAT(110 * 1000),
|
||||
true);
|
||||
|
||||
assert(mk_short_channel_id(&scid, 5, 6, 0));
|
||||
add_connection(fd, &nodes[4], &nodes[5], scid,
|
||||
AMOUNT_MSAT(0),
|
||||
AMOUNT_MSAT(1000 * 1000 * 1000),
|
||||
0, 100 * 1000 /* 10% */, 5,
|
||||
AMOUNT_SAT(1000 * 1000));
|
||||
AMOUNT_SAT(1000 * 1000),
|
||||
true);
|
||||
|
||||
assert(mk_short_channel_id(&scid, 5, 7, 0));
|
||||
add_connection(fd, &nodes[4], &nodes[6], scid,
|
||||
AMOUNT_MSAT(0),
|
||||
AMOUNT_MSAT(1000 * 1000 * 1000),
|
||||
0, 100 * 1000 /* 10% */, 5,
|
||||
AMOUNT_SAT(1000 * 1000));
|
||||
AMOUNT_SAT(1000 * 1000),
|
||||
true);
|
||||
|
||||
assert(mk_short_channel_id(&scid, 6, 8, 0));
|
||||
add_connection(fd, &nodes[5], &nodes[7], scid,
|
||||
AMOUNT_MSAT(0),
|
||||
AMOUNT_MSAT(1000 * 1000 * 1000),
|
||||
0, 0, 5,
|
||||
AMOUNT_SAT(1000 * 1000));
|
||||
AMOUNT_SAT(1000 * 1000),
|
||||
true);
|
||||
|
||||
assert(mk_short_channel_id(&scid, 7, 8, 0));
|
||||
add_connection(fd, &nodes[6], &nodes[7], scid,
|
||||
AMOUNT_MSAT(0),
|
||||
AMOUNT_MSAT(1000 * 1000 * 1000),
|
||||
0, 0, 5,
|
||||
AMOUNT_SAT(1000 * 1000));
|
||||
AMOUNT_SAT(1000 * 1000),
|
||||
true);
|
||||
|
||||
assert(gossmap_refresh(gossmap, NULL));
|
||||
struct uncertainty *uncertainty = uncertainty_new(tmpctx);
|
||||
|
|
167
plugins/renepay/test/run-missingcapacity.c
Normal file
167
plugins/renepay/test/run-missingcapacity.c
Normal file
|
@ -0,0 +1,167 @@
|
|||
/* Checks that uncertainty_update and get_routes can handle a gossmap where the
|
||||
* capacity of some channels are missing.
|
||||
*
|
||||
* */
|
||||
#include "config.h"
|
||||
|
||||
#include "../disabledmap.c"
|
||||
#include "../errorcodes.c"
|
||||
#include "../flow.c"
|
||||
#include "../mcf.c"
|
||||
#include "../route.c"
|
||||
#include "../routebuilder.c"
|
||||
#include "../uncertainty.c"
|
||||
#include "common.h"
|
||||
|
||||
#include <bitcoin/chainparams.h>
|
||||
#include <bitcoin/preimage.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <common/setup.h>
|
||||
#include <common/utils.h>
|
||||
#include <sodium/randombytes.h>
|
||||
|
||||
static u8 empty_map[] = {10};
|
||||
|
||||
#define NUM_NODES 4
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd;
|
||||
char *gossfile;
|
||||
struct gossmap *gossmap;
|
||||
struct node_id nodes[NUM_NODES];
|
||||
|
||||
common_setup(argv[0]);
|
||||
chainparams = chainparams_for_network("regtest");
|
||||
|
||||
fd = tmpdir_mkstemp(tmpctx, "run-missingcapacity.XXXXXX", &gossfile);
|
||||
assert(write(fd, empty_map, sizeof(empty_map)) == sizeof(empty_map));
|
||||
|
||||
gossmap = gossmap_load(tmpctx, gossfile, NULL);
|
||||
assert(gossmap);
|
||||
|
||||
for (size_t i = 0; i < NUM_NODES; i++) {
|
||||
struct privkey tmp;
|
||||
memset(&tmp, i+1, sizeof(tmp));
|
||||
node_id_from_privkey(&tmp, &nodes[i]);
|
||||
}
|
||||
|
||||
/* We will try a payment from 1 to 4.
|
||||
* There are two possible routes 1->2->4 or 1->3->4.
|
||||
* However, we will simulate that we don't have channel 3->4's capacity
|
||||
* in the gossmap (see #7194). We expect that 3->4 it's simply ignored
|
||||
* and only route through 1->2->4 is used.
|
||||
*
|
||||
* +--2--+
|
||||
* | |
|
||||
* 1 4
|
||||
* | |
|
||||
* +--3--+
|
||||
*
|
||||
* */
|
||||
struct short_channel_id scid;
|
||||
|
||||
assert(mk_short_channel_id(&scid, 1, 2, 0));
|
||||
add_connection(fd, &nodes[0], &nodes[1], scid,
|
||||
AMOUNT_MSAT(0),
|
||||
AMOUNT_MSAT(1000 * 1000 * 1000),
|
||||
0, 0, 5,
|
||||
AMOUNT_SAT(1000 * 1000),
|
||||
/* add capacity? = */ true);
|
||||
|
||||
assert(mk_short_channel_id(&scid, 2, 4, 0));
|
||||
add_connection(fd, &nodes[1], &nodes[3], scid,
|
||||
AMOUNT_MSAT(0),
|
||||
AMOUNT_MSAT(1000 * 1000 * 1000),
|
||||
0, 0, 5,
|
||||
AMOUNT_SAT(1000 * 1000),
|
||||
/* add capacity? = */ true);
|
||||
|
||||
assert(mk_short_channel_id(&scid, 1, 3, 0));
|
||||
add_connection(fd, &nodes[0], &nodes[2], scid,
|
||||
AMOUNT_MSAT(0),
|
||||
AMOUNT_MSAT(1000 * 1000 * 1000),
|
||||
0, 0, 5,
|
||||
AMOUNT_SAT(1000 * 1000),
|
||||
/* add capacity? = */ true);
|
||||
|
||||
assert(mk_short_channel_id(&scid, 3, 4, 0));
|
||||
add_connection(fd, &nodes[2], &nodes[3], scid,
|
||||
AMOUNT_MSAT(0),
|
||||
AMOUNT_MSAT(1000 * 1000 * 1000),
|
||||
0, 0, 5,
|
||||
AMOUNT_SAT(1000 * 1000),
|
||||
/* add capacity? = */ false);
|
||||
|
||||
assert(gossmap_refresh(gossmap, NULL));
|
||||
struct uncertainty *uncertainty = uncertainty_new(tmpctx);
|
||||
int skipped_count =
|
||||
uncertainty_update(uncertainty, gossmap);
|
||||
assert(skipped_count==1);
|
||||
|
||||
struct preimage preimage;
|
||||
|
||||
struct amount_msat maxfee = AMOUNT_MSAT(20*1000);
|
||||
struct payment_info pinfo;
|
||||
pinfo.invstr = NULL;
|
||||
pinfo.label = NULL;
|
||||
pinfo.description = NULL;
|
||||
pinfo.payment_secret = NULL;
|
||||
pinfo.payment_metadata = NULL;
|
||||
pinfo.routehints = NULL;
|
||||
pinfo.destination = nodes[3];
|
||||
pinfo.amount = AMOUNT_MSAT(100 * 1000 * 1000);
|
||||
|
||||
assert(amount_msat_add(&pinfo.maxspend, maxfee, pinfo.amount));
|
||||
pinfo.maxdelay = 100;
|
||||
pinfo.final_cltv = 5;
|
||||
|
||||
pinfo.start_time = time_now();
|
||||
pinfo.stop_time = timeabs_add(pinfo.start_time, time_from_sec(10000));
|
||||
|
||||
pinfo.base_fee_penalty = 1e-5;
|
||||
pinfo.prob_cost_factor = 1e-5;
|
||||
pinfo.delay_feefactor = 1e-6;
|
||||
pinfo.min_prob_success = 0.9;
|
||||
pinfo.use_shadow = false;
|
||||
|
||||
randombytes_buf(&preimage, sizeof(preimage));
|
||||
sha256(&pinfo.payment_hash, &preimage, sizeof(preimage));
|
||||
|
||||
struct disabledmap *disabledmap = disabledmap_new(tmpctx);
|
||||
|
||||
enum jsonrpc_errcode errcode;
|
||||
const char *err_msg;
|
||||
|
||||
u64 groupid = 1;
|
||||
u64 next_partid=1;
|
||||
|
||||
struct route **routes = get_routes(
|
||||
/* ctx */tmpctx,
|
||||
/* payment */&pinfo,
|
||||
/* source */&nodes[0],
|
||||
/* destination */&nodes[3],
|
||||
/* gossmap */gossmap,
|
||||
/* uncertainty */uncertainty,
|
||||
disabledmap,
|
||||
/* amount */ pinfo.amount,
|
||||
/* feebudget */maxfee,
|
||||
&next_partid,
|
||||
groupid,
|
||||
&errcode,
|
||||
&err_msg);
|
||||
|
||||
assert(routes);
|
||||
|
||||
if (!routes) {
|
||||
printf("get_route failed with error %d: %s", errcode, err_msg);
|
||||
} else {
|
||||
printf("get_routes: %s\n", print_routes(tmpctx, routes));
|
||||
assert(tal_count(routes) == 1);
|
||||
assert(tal_count(routes[0]->hops) == 2);
|
||||
assert(node_id_eq(&routes[0]->hops[0].node_id, &nodes[1]));
|
||||
assert(node_id_eq(&routes[0]->hops[1].node_id, &nodes[3]));
|
||||
}
|
||||
common_shutdown();
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue