core-lightning/gossipd/test/run-find_route.c
Rusty Russell 46cc7c281e features: more general accessor functions.
As we add more features, the current code is insufficient.

1. Keep an array of single feature bits, for easy switching on and off.
2. Create feature_offered() which checks for both compulsory and optional
   variants.
3. Invert requires_unsupported_features() and unsupported_features()
   which tend to be double-negative, all_supported_features() and
   features_supported().
4. Move single feature definition from wire/peer_wire.h to common/features.h.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-03-14 02:19:37 +00:00

221 lines
7.6 KiB
C

#include "../routing.c"
#include <stdio.h>
struct broadcast_state *new_broadcast_state(tal_t *ctx UNNEEDED)
{
return NULL;
}
void status_fmt(enum log_level level UNUSED, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
printf("\n");
va_end(ap);
}
/* AUTOGENERATED MOCKS START */
/* Generated stub for fromwire_channel_announcement */
bool fromwire_channel_announcement(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, secp256k1_ecdsa_signature *node_signature_1 UNNEEDED, secp256k1_ecdsa_signature *node_signature_2 UNNEEDED, secp256k1_ecdsa_signature *bitcoin_signature_1 UNNEEDED, secp256k1_ecdsa_signature *bitcoin_signature_2 UNNEEDED, u8 **features UNNEEDED, struct bitcoin_blkid *chain_hash UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, struct pubkey *node_id_1 UNNEEDED, struct pubkey *node_id_2 UNNEEDED, struct pubkey *bitcoin_key_1 UNNEEDED, struct pubkey *bitcoin_key_2 UNNEEDED)
{ fprintf(stderr, "fromwire_channel_announcement called!\n"); abort(); }
/* Generated stub for fromwire_channel_update */
bool fromwire_channel_update(const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, struct bitcoin_blkid *chain_hash UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, u32 *timestamp UNNEEDED, u16 *flags UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, u64 *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED)
{ fprintf(stderr, "fromwire_channel_update called!\n"); abort(); }
/* Generated stub for fromwire_node_announcement */
bool fromwire_node_announcement(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, u8 **features UNNEEDED, u32 *timestamp UNNEEDED, struct pubkey *node_id UNNEEDED, u8 rgb_color[3] UNNEEDED, u8 alias[32] UNNEEDED, u8 **addresses UNNEEDED)
{ fprintf(stderr, "fromwire_node_announcement called!\n"); abort(); }
/* Generated stub for fromwire_u8 */
u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); }
/* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); }
/* Generated stub for onion_type_name */
const char *onion_type_name(int e UNNEEDED)
{ fprintf(stderr, "onion_type_name called!\n"); abort(); }
/* Generated stub for replace_broadcast */
bool replace_broadcast(const tal_t *ctx UNNEEDED,
struct broadcast_state *bstate UNNEEDED,
u64 *index UNNEEDED,
const u8 *payload TAKES UNNEEDED)
{ fprintf(stderr, "replace_broadcast called!\n"); abort(); }
/* Generated stub for sanitize_error */
char *sanitize_error(const tal_t *ctx UNNEEDED, const u8 *errmsg UNNEEDED,
struct channel_id *channel_id UNNEEDED)
{ fprintf(stderr, "sanitize_error called!\n"); abort(); }
/* Generated stub for status_failed */
void status_failed(enum status_failreason code UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "status_failed called!\n"); abort(); }
/* Generated stub for towire_errorfmt */
u8 *towire_errorfmt(const tal_t *ctx UNNEEDED,
const struct channel_id *channel UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "towire_errorfmt called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
const void *trc;
/* Updates existing route if required. */
static struct half_chan *add_connection(struct routing_state *rstate,
const struct pubkey *from,
const struct pubkey *to,
u32 base_fee, s32 proportional_fee,
u32 delay)
{
struct short_channel_id scid;
struct half_chan *c;
struct chan *chan;
/* Make a unique scid. */
memcpy(&scid, from, sizeof(scid) / 2);
memcpy((char *)&scid + sizeof(scid) / 2, to, sizeof(scid) / 2);
chan = get_channel(rstate, &scid);
if (!chan)
chan = new_chan(rstate, &scid, from, to);
c = &chan->half[pubkey_idx(from, to)];
c->base_fee = base_fee;
c->proportional_fee = proportional_fee;
c->delay = delay;
c->active = true;
c->flags = get_channel_direction(from, to);
return c;
}
/* Returns chan connecting from and to: *idx set to refer
* to connection with src=from, dst=to */
static struct chan *find_channel(struct routing_state *rstate,
const struct node *from,
const struct node *to,
int *idx)
{
int i, n;
*idx = pubkey_idx(&from->id, &to->id);
n = tal_count(to->chans);
for (i = 0; i < n; i++) {
if (to->chans[i]->nodes[*idx] == from)
return to->chans[i];
}
return NULL;
}
static struct half_chan *get_connection(struct routing_state *rstate,
const struct pubkey *from_id,
const struct pubkey *to_id)
{
int idx;
struct node *from, *to;
struct chan *c;
from = get_node(rstate, from_id);
to = get_node(rstate, to_id);
if (!from || ! to)
return NULL;
c = find_channel(rstate, from, to, &idx);
if (!c)
return NULL;
return &c->half[idx];
}
static bool channel_is_between(const struct chan *chan,
const struct pubkey *a, const struct pubkey *b)
{
if (pubkey_eq(&chan->nodes[0]->id, a)
&& pubkey_eq(&chan->nodes[1]->id, b))
return true;
if (pubkey_eq(&chan->nodes[0]->id, b)
&& pubkey_eq(&chan->nodes[1]->id, a))
return true;
return false;
}
int main(void)
{
static const struct bitcoin_blkid zerohash;
const tal_t *ctx = trc = tal_tmpctx(NULL);
struct routing_state *rstate;
struct pubkey a, b, c, d;
struct privkey tmp;
u64 fee;
struct chan **route;
const double riskfactor = 1.0 / BLOCKS_PER_YEAR / 10000;
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
| SECP256K1_CONTEXT_SIGN);
memset(&tmp, 'a', sizeof(tmp));
rstate = new_routing_state(ctx, &zerohash, &a, 0);
pubkey_from_privkey(&tmp, &a);
new_node(rstate, &a);
memset(&tmp, 'b', sizeof(tmp));
pubkey_from_privkey(&tmp, &b);
new_node(rstate, &b);
/* A<->B */
add_connection(rstate, &a, &b, 1, 1, 1);
route = find_route(ctx, rstate, &a, &b, 1000, riskfactor, 0.0, NULL, &fee);
assert(tal_count(route) == 1);
assert(fee == 0);
/* A<->B<->C */
memset(&tmp, 'c', sizeof(tmp));
pubkey_from_privkey(&tmp, &c);
new_node(rstate, &c);
status_trace("A = %s", type_to_string(trc, struct pubkey, &a));
status_trace("B = %s", type_to_string(trc, struct pubkey, &b));
status_trace("C = %s", type_to_string(trc, struct pubkey, &c));
add_connection(rstate, &b, &c, 1, 1, 1);
route = find_route(ctx, rstate, &a, &c, 1000, riskfactor, 0.0, NULL, &fee);
assert(tal_count(route) == 2);
assert(fee == 1);
/* A<->D<->C: Lower base, higher percentage. */
memset(&tmp, 'd', sizeof(tmp));
pubkey_from_privkey(&tmp, &d);
new_node(rstate, &d);
status_trace("D = %s", type_to_string(trc, struct pubkey, &d));
add_connection(rstate, &a, &d, 0, 2, 1);
add_connection(rstate, &d, &c, 0, 2, 1);
/* Will go via D for small amounts. */
route = find_route(ctx, rstate, &a, &c, 1000, riskfactor, 0.0, NULL, &fee);
assert(tal_count(route) == 2);
assert(channel_is_between(route[0], &a, &d));
assert(channel_is_between(route[1], &d, &c));
assert(fee == 0);
/* Will go via B for large amounts. */
route = find_route(ctx, rstate, &a, &c, 3000000, riskfactor, 0.0, NULL, &fee);
assert(tal_count(route) == 2);
assert(channel_is_between(route[0], &a, &b));
assert(channel_is_between(route[1], &b, &c));
assert(fee == 1 + 3);
/* Make B->C inactive, force it back via D */
get_connection(rstate, &b, &c)->active = false;
route = find_route(ctx, rstate, &a, &c, 3000000, riskfactor, 0.0, NULL, &fee);
assert(tal_count(route) == 2);
assert(channel_is_between(route[0], &a, &d));
assert(channel_is_between(route[1], &d, &c));
assert(fee == 0 + 6);
tal_free(ctx);
secp256k1_context_destroy(secp256k1_ctx);
return 0;
}