core-lightning/gossipd/test/run-find_route.c
Rusty Russell a92ead48bf gossipd: ignore redundant channel_update and node_announcement.
If you send a message which simply changes timestamp and signature, we
drop it.  You shouldn't be doing that, and the door to ignoring them
was opened by by option_gossip_query_ex, which would allow clients to
ignore updates with the same checksum.

This is more aggressive at reducing spam messages, but we allow refreshes
(to be conservative, we allow them even when 1/2 of the way through the
refresh period).

I dropped the now-unnecessary sleep from test_gossip_pruning, too.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2019-09-20 06:55:00 +00:00

258 lines
8.9 KiB
C

#include "../routing.c"
#include "../gossip_store.c"
#include <stdio.h>
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 cupdate_different */
bool cupdate_different(struct gossip_store *gs UNNEEDED,
const struct half_chan *hc UNNEEDED,
const u8 *cupdate UNNEEDED)
{ fprintf(stderr, "cupdate_different called!\n"); abort(); }
/* Generated stub for fromwire_gossipd_local_add_channel */
bool fromwire_gossipd_local_add_channel(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, struct node_id *remote_node_id UNNEEDED, struct amount_sat *satoshis UNNEEDED)
{ fprintf(stderr, "fromwire_gossipd_local_add_channel called!\n"); abort(); }
/* Generated stub for fromwire_gossip_store_channel_amount */
bool fromwire_gossip_store_channel_amount(const void *p UNNEEDED, struct amount_sat *satoshis UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_channel_amount called!\n"); abort(); }
/* Generated stub for fromwire_gossip_store_private_update */
bool fromwire_gossip_store_private_update(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **update UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_private_update 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 memleak_add_helper_ */
void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED,
const tal_t *)){ }
/* Generated stub for nannounce_different */
bool nannounce_different(struct gossip_store *gs UNNEEDED,
const struct node *node UNNEEDED,
const u8 *nannounce UNNEEDED)
{ fprintf(stderr, "nannounce_different 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 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(); }
/* Generated stub for towire_gossip_store_channel_amount */
u8 *towire_gossip_store_channel_amount(const tal_t *ctx UNNEEDED, struct amount_sat satoshis UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_channel_amount called!\n"); abort(); }
/* Generated stub for towire_gossip_store_private_update */
u8 *towire_gossip_store_private_update(const tal_t *ctx UNNEEDED, const u8 *update UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_private_update called!\n"); abort(); }
/* Generated stub for update_peers_broadcast_index */
void update_peers_broadcast_index(struct list_head *peers UNNEEDED, u32 offset UNNEEDED)
{ fprintf(stderr, "update_peers_broadcast_index called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
#if DEVELOPER
/* Generated stub for memleak_remove_htable */
void memleak_remove_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED)
{ fprintf(stderr, "memleak_remove_htable called!\n"); abort(); }
/* Generated stub for memleak_remove_intmap_ */
void memleak_remove_intmap_(struct htable *memtable UNNEEDED, const struct intmap *m UNNEEDED)
{ fprintf(stderr, "memleak_remove_intmap_ called!\n"); abort(); }
#endif
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);
}
/* Updates existing route if required. */
static void add_connection(struct routing_state *rstate,
const struct node_id *from,
const struct node_id *to,
u32 base_fee, s32 proportional_fee,
u32 delay)
{
struct short_channel_id scid;
struct half_chan *c;
struct chan *chan;
struct amount_sat satoshis = AMOUNT_SAT(100000);
/* 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, satoshis);
c = &chan->half[node_id_idx(from, to)];
/* Make sure it's seen as initialized (index non-zero). */
c->bcast.index = 1;
c->base_fee = base_fee;
c->proportional_fee = proportional_fee;
c->delay = delay;
c->channel_flags = node_id_idx(from, to);
c->htlc_minimum = AMOUNT_MSAT(0);
c->htlc_maximum = AMOUNT_MSAT(100000 * 1000);
}
/* 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 UNUSED,
const struct node *from,
const struct node *to,
int *idx)
{
struct chan_map_iter i;
struct chan *c;
*idx = node_id_idx(&from->id, &to->id);
for (c = first_chan(to, &i); c; c = next_chan(to, &i)) {
if (c->nodes[*idx] == from)
return c;
}
return NULL;
}
static struct half_chan *get_connection(struct routing_state *rstate,
const struct node_id *from_id,
const struct node_id *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 node_id *a, const struct node_id *b)
{
if (node_id_eq(&chan->nodes[0]->id, a)
&& node_id_eq(&chan->nodes[1]->id, b))
return true;
if (node_id_eq(&chan->nodes[0]->id, b)
&& node_id_eq(&chan->nodes[1]->id, a))
return true;
return false;
}
int main(void)
{
setup_locale();
struct routing_state *rstate;
struct node_id a, b, c, d;
struct privkey tmp;
struct amount_msat fee;
struct chan **route;
const double riskfactor = 1.0 / BLOCKS_PER_YEAR / 10000;
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
| SECP256K1_CONTEXT_SIGN);
setup_tmpctx();
memset(&tmp, 'a', sizeof(tmp));
node_id_from_privkey(&tmp, &a);
rstate = new_routing_state(tmpctx, NULL, &a, 0, NULL, NULL);
new_node(rstate, &a);
memset(&tmp, 'b', sizeof(tmp));
node_id_from_privkey(&tmp, &b);
new_node(rstate, &b);
/* A<->B */
add_connection(rstate, &a, &b, 1, 1, 1);
route = find_route(tmpctx, rstate, &a, &b, AMOUNT_MSAT(1000), riskfactor, 0.0, NULL,
ROUTING_MAX_HOPS, &fee);
assert(route);
assert(tal_count(route) == 1);
assert(amount_msat_eq(fee, AMOUNT_MSAT(0)));
/* A<->B<->C */
memset(&tmp, 'c', sizeof(tmp));
node_id_from_privkey(&tmp, &c);
new_node(rstate, &c);
status_debug("A = %s", type_to_string(tmpctx, struct node_id, &a));
status_debug("B = %s", type_to_string(tmpctx, struct node_id, &b));
status_debug("C = %s", type_to_string(tmpctx, struct node_id, &c));
add_connection(rstate, &b, &c, 1, 1, 1);
route = find_route(tmpctx, rstate, &a, &c, AMOUNT_MSAT(1000), riskfactor, 0.0, NULL,
ROUTING_MAX_HOPS, &fee);
assert(route);
assert(tal_count(route) == 2);
assert(amount_msat_eq(fee, AMOUNT_MSAT(1)));
/* A<->D<->C: Lower base, higher percentage. */
memset(&tmp, 'd', sizeof(tmp));
node_id_from_privkey(&tmp, &d);
new_node(rstate, &d);
status_debug("D = %s", type_to_string(tmpctx, struct node_id, &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(tmpctx, rstate, &a, &c, AMOUNT_MSAT(1000), riskfactor, 0.0, NULL,
ROUTING_MAX_HOPS, &fee);
assert(route);
assert(tal_count(route) == 2);
assert(channel_is_between(route[0], &a, &d));
assert(channel_is_between(route[1], &d, &c));
assert(amount_msat_eq(fee, AMOUNT_MSAT(0)));
/* Will go via B for large amounts. */
route = find_route(tmpctx, rstate, &a, &c, AMOUNT_MSAT(3000000), riskfactor, 0.0, NULL,
ROUTING_MAX_HOPS, &fee);
assert(route);
assert(tal_count(route) == 2);
assert(channel_is_between(route[0], &a, &b));
assert(channel_is_between(route[1], &b, &c));
assert(amount_msat_eq(fee, AMOUNT_MSAT(1 + 3)));
/* Make B->C inactive, force it back via D */
get_connection(rstate, &b, &c)->channel_flags |= ROUTING_FLAGS_DISABLED;
route = find_route(tmpctx, rstate, &a, &c, AMOUNT_MSAT(3000000), riskfactor, 0.0, NULL,
ROUTING_MAX_HOPS, &fee);
assert(route);
assert(tal_count(route) == 2);
assert(channel_is_between(route[0], &a, &d));
assert(channel_is_between(route[1], &d, &c));
assert(amount_msat_eq(fee, AMOUNT_MSAT(0 + 6)));
tal_free(tmpctx);
secp256k1_context_destroy(secp256k1_ctx);
return 0;
}