ccan: update to latest htable fixes, and update gossmap to meet new assertions.

Updating ccan to stricter htable revealed we were trying to put
(void *)1 in the htable, which is forbidden:

```
topology: ccan/ccan/htable/htable.c:382: htable_add_: Assertion `entry_is_valid((uintptr_t)p)' failed.
topology: FATAL SIGNAL 6 (version 1358d7f)
0x55f30c689c34 send_backtrace
	common/daemon.c:33
0x55f30c689ce0 crashdump
	common/daemon.c:46
0x7f5d150fe51f ???
	./signal/../sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c:0
0x7f5d15152828 __pthread_kill_implementation
	./nptl/pthread_kill.c:44
0x7f5d15152828 __pthread_kill_internal
	./nptl/pthread_kill.c:80
0x7f5d15152828 __GI___pthread_kill
	./nptl/pthread_kill.c:91
0x7f5d150fe475 __GI_raise
	../sysdeps/posix/raise.c:26
0x7f5d150e47b6 __GI_abort
	./stdlib/abort.c:79
0x7f5d150e46da __assert_fail_base
	./assert/assert.c:92
0x7f5d150f5e25 __GI___assert_fail
	./assert/assert.c:101
0x55f30c6adbe4 htable_add_
	ccan/ccan/htable/htable.c:382
0x55f30c65f303 chanidx_htable_add
	common/gossmap.c:35
0x55f30c6605ed new_channel
	common/gossmap.c:337
0x55f30c6609cf add_channel
	common/gossmap.c:425
0x55f30c661101 map_catchup
	common/gossmap.c:607
0x55f30c66221e gossmap_refresh
	common/gossmap.c:927
0x55f30c66e3e9 get_gossmap
	plugins/topology.c:27
0x55f30c66f939 listpeers_done
	plugins/topology.c:369
0x55f30c671f46 handle_rpc_reply
	plugins/libplugin.c:558
0x55f30c672a19 rpc_read_response_one
	plugins/libplugin.c:726
0x55f30c672b4f rpc_conn_read_response
	plugins/libplugin.c:746
0x55f30c6ae35e next_plan
	ccan/ccan/io/io.c:59
0x55f30c6aef93 do_plan
	ccan/ccan/io/io.c:407
0x55f30c6aefd5 io_ready
	ccan/ccan/io/io.c:417
0x55f30c6b1371 io_loop
	ccan/ccan/io/poll.c:453
0x55f30c67587c plugin_main
	plugins/libplugin.c:1559
0x55f30c6708eb main
	plugins/topology.c:701
0x7f5d150e5fcf __libc_start_call_main
	../sysdeps/nptl/libc_start_call_main.h:58
0x7f5d150e607c __libc_start_main_impl
	../csu/libc-start.c:409
0x55f30c65d894 ???
	???:0
0xffffffffffffffff ???
	???:0
```

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2022-07-04 14:14:06 +09:30 committed by neil saitug
parent c589543f1c
commit ae71a87c40
15 changed files with 496 additions and 74 deletions

View File

@ -1,3 +1,3 @@
CCAN imported from http://ccodearchive.net.
CCAN version: init-2524-g609670cc
CCAN version: init-2540-g8448fd28

View File

@ -86,14 +86,16 @@ void htable_init(struct htable *ht,
ht->table = &ht->common_bits;
}
/* Fill to 87.5% */
static inline size_t ht_max(const struct htable *ht)
{
return ((size_t)3 << ht->bits) / 4;
return ((size_t)7 << ht->bits) / 8;
}
static inline size_t ht_max_with_deleted(const struct htable *ht)
/* Clean deleted if we're full, and more than 12.5% deleted */
static inline size_t ht_max_deleted(const struct htable *ht)
{
return ((size_t)9 << ht->bits) / 10;
return ((size_t)1 << ht->bits) / 8;
}
bool htable_init_sized(struct htable *ht,
@ -103,7 +105,7 @@ bool htable_init_sized(struct htable *ht,
htable_init(ht, rehash, priv);
/* Don't go insane with sizing. */
for (ht->bits = 1; ((size_t)3 << ht->bits) / 4 < expect; ht->bits++) {
for (ht->bits = 1; ht_max(ht) < expect; ht->bits++) {
if (ht->bits == 30)
break;
}
@ -195,12 +197,83 @@ void *htable_prev_(const struct htable *ht, struct htable_iter *i)
for (;;) {
if (!i->off)
return NULL;
i->off --;
i->off--;
if (entry_is_valid(ht->table[i->off]))
return get_raw_ptr(ht, ht->table[i->off]);
}
}
/* Another bit currently in mask needs to be exposed, so that a bucket with p in
* it won't appear invalid */
static COLD void unset_another_common_bit(struct htable *ht,
uintptr_t *maskdiff,
const void *p)
{
size_t i;
for (i = sizeof(uintptr_t) * CHAR_BIT - 1; i > 0; i--) {
if (((uintptr_t)p & ((uintptr_t)1 << i))
&& ht->common_mask & ~*maskdiff & ((uintptr_t)1 << i))
break;
}
/* There must have been one, right? */
assert(i > 0);
*maskdiff |= ((uintptr_t)1 << i);
}
/* We want to change the common mask: this fixes up the table */
static COLD void fixup_table_common(struct htable *ht, uintptr_t maskdiff)
{
size_t i;
uintptr_t bitsdiff;
again:
bitsdiff = ht->common_bits & maskdiff;
for (i = 0; i < (size_t)1 << ht->bits; i++) {
uintptr_t e;
if (!entry_is_valid(e = ht->table[i]))
continue;
/* Clear the bits no longer in the mask, set them as
* expected. */
e &= ~maskdiff;
e |= bitsdiff;
/* If this made it invalid, restart with more exposed */
if (!entry_is_valid(e)) {
unset_another_common_bit(ht, &maskdiff, get_raw_ptr(ht, e));
goto again;
}
ht->table[i] = e;
}
/* Take away those bits from our mask, bits and perfect bit. */
ht->common_mask &= ~maskdiff;
ht->common_bits &= ~maskdiff;
if (ht_perfect_mask(ht) & maskdiff)
ht->perfect_bitnum = NO_PERFECT_BIT;
}
/* Limited recursion */
static void ht_add(struct htable *ht, const void *new, size_t h);
/* We tried to add this entry, but it looked invalid! We need to
* let another pointer bit through mask */
static COLD void update_common_fix_invalid(struct htable *ht, const void *p, size_t h)
{
uintptr_t maskdiff;
assert(ht->elems != 0);
maskdiff = 0;
unset_another_common_bit(ht, &maskdiff, p);
fixup_table_common(ht, maskdiff);
/* Now won't recurse */
ht_add(ht, p, h);
}
/* This does not expand the hash table, that's up to caller. */
static void ht_add(struct htable *ht, const void *new, size_t h)
{
@ -214,6 +287,8 @@ static void ht_add(struct htable *ht, const void *new, size_t h)
i = (i + 1) & ((1 << ht->bits)-1);
}
ht->table[i] = make_hval(ht, new, get_hash_ptr_bits(ht, h)|perfect);
if (!entry_is_valid(ht->table[i]))
update_common_fix_invalid(ht, new, h);
}
static COLD bool double_table(struct htable *ht)
@ -283,20 +358,10 @@ static COLD void rehash_table(struct htable *ht)
/* We stole some bits, now we need to put them back... */
static COLD void update_common(struct htable *ht, const void *p)
{
unsigned int i;
uintptr_t maskdiff, bitsdiff;
uintptr_t maskdiff;
if (ht->elems == 0) {
/* Always reveal one bit of the pointer in the bucket,
* so it's not zero or HTABLE_DELETED (1), even if
* hash happens to be 0. Assumes (void *)1 is not a
* valid pointer. */
for (i = sizeof(uintptr_t)*CHAR_BIT - 1; i > 0; i--) {
if ((uintptr_t)p & ((uintptr_t)1 << i))
break;
}
ht->common_mask = ~((uintptr_t)1 << i);
ht->common_mask = -1;
ht->common_bits = ((uintptr_t)p & ht->common_mask);
ht->perfect_bitnum = 0;
(void)htable_debug(ht, HTABLE_LOC);
@ -306,33 +371,25 @@ static COLD void update_common(struct htable *ht, const void *p)
/* Find bits which are unequal to old common set. */
maskdiff = ht->common_bits ^ ((uintptr_t)p & ht->common_mask);
/* These are the bits which go there in existing entries. */
bitsdiff = ht->common_bits & maskdiff;
for (i = 0; i < (size_t)1 << ht->bits; i++) {
if (!entry_is_valid(ht->table[i]))
continue;
/* Clear the bits no longer in the mask, set them as
* expected. */
ht->table[i] &= ~maskdiff;
ht->table[i] |= bitsdiff;
}
/* Take away those bits from our mask, bits and perfect bit. */
ht->common_mask &= ~maskdiff;
ht->common_bits &= ~maskdiff;
if (ht_perfect_mask(ht) & maskdiff)
ht->perfect_bitnum = NO_PERFECT_BIT;
fixup_table_common(ht, maskdiff);
(void)htable_debug(ht, HTABLE_LOC);
}
bool htable_add_(struct htable *ht, size_t hash, const void *p)
{
if (ht->elems+1 > ht_max(ht) && !double_table(ht))
return false;
if (ht->elems+1 + ht->deleted > ht_max_with_deleted(ht))
rehash_table(ht);
/* Cannot insert NULL, or (void *)1. */
assert(p);
assert(entry_is_valid((uintptr_t)p));
/* Getting too full? */
if (ht->elems+1 + ht->deleted > ht_max(ht)) {
/* If we're more than 1/8 deleted, clean those,
* otherwise double table size. */
if (ht->deleted > ht_max_deleted(ht))
rehash_table(ht);
else if (!double_table(ht))
return false;
}
if (((uintptr_t)p & ht->common_mask) != ht->common_bits)
update_common(ht, p);
@ -361,8 +418,12 @@ void htable_delval_(struct htable *ht, struct htable_iter *i)
assert(entry_is_valid(ht->table[i->off]));
ht->elems--;
ht->table[i->off] = HTABLE_DELETED;
ht->deleted++;
/* Cheap test: if the next bucket is empty, don't need delete marker */
if (ht->table[hash_bucket(ht, i->off+1)] != 0) {
ht->table[i->off] = HTABLE_DELETED;
ht->deleted++;
} else
ht->table[i->off] = 0;
}
void *htable_pick_(const struct htable *ht, size_t seed, struct htable_iter *i)

View File

@ -132,7 +132,7 @@ bool htable_copy_(struct htable *dst, const struct htable *src);
* htable_add - add a pointer into a hash table.
* @ht: the htable
* @hash: the hash value of the object
* @p: the non-NULL pointer
* @p: the non-NULL pointer (also cannot be (void *)1).
*
* Also note that this can only fail due to allocation failure. Otherwise, it
* returns true.

View File

@ -0,0 +1,31 @@
#include <ccan/htable/htable.h>
#include <ccan/htable/htable.c>
#include <ccan/tap/tap.h>
#include <stdbool.h>
#include <string.h>
/* Clashy hash */
static size_t hash(const void *elem, void *unused UNNEEDED)
{
return 0;
}
int main(void)
{
struct htable ht;
plan_tests(254 * 253);
/* We try to get two elements which clash */
for (size_t i = 2; i < 256; i++) {
for (size_t j = 2; j < 256; j++) {
if (i == j)
continue;
htable_init(&ht, hash, NULL);
htable_add(&ht, hash((void *)i, NULL), (void *)i);
htable_add(&ht, hash((void *)j, NULL), (void *)j);
ok1(htable_check(&ht, "test"));
htable_clear(&ht);
}
}
return exit_status();
}

View File

@ -107,7 +107,7 @@ static bool check_mask(struct htable *ht, uint64_t val[], unsigned num)
int main(void)
{
unsigned int i, weight;
unsigned int i;
uintptr_t perfect_bit;
struct htable ht;
uint64_t val[NUM_VALS];
@ -131,14 +131,7 @@ int main(void)
add_vals(&ht, val, 0, 1);
ok1(ht.bits == 1);
ok1(ht_max(&ht) == 1);
weight = 0;
for (i = 0; i < sizeof(ht.common_mask) * CHAR_BIT; i++) {
if (ht.common_mask & ((uintptr_t)1 << i)) {
weight++;
}
}
/* Only one bit should be clear. */
ok1(weight == i-1);
ok1(ht.common_mask == -1);
/* Mask should be set. */
ok1(check_mask(&ht, val, 1));

View File

@ -97,7 +97,7 @@ static bool check_mask(struct htable *ht, uint64_t val[], unsigned num)
int main(void)
{
unsigned int i, weight;
unsigned int i;
uintptr_t perfect_bit;
struct htable ht;
uint64_t val[NUM_VALS];
@ -122,14 +122,7 @@ int main(void)
add_vals(&ht, val, 0, 1);
ok1(ht.bits == 1);
ok1(ht_max(&ht) == 1);
weight = 0;
for (i = 0; i < sizeof(ht.common_mask) * CHAR_BIT; i++) {
if (ht.common_mask & ((uintptr_t)1 << i)) {
weight++;
}
}
/* Only one bit should be clear. */
ok1(weight == i-1);
ok1(ht.common_mask == -1);
/* Mask should be set. */
ok1(check_mask(&ht, val, 1));

View File

@ -4,9 +4,10 @@ CFLAGS=-Wall -Werror -O3 -I$(CCANDIR)
CCAN_OBJS:=ccan-tal.o ccan-tal-str.o ccan-tal-grab_file.o ccan-take.o ccan-time.o ccan-str.o ccan-noerr.o ccan-list.o
all: speed stringspeed hsearchspeed
all: speed stringspeed hsearchspeed density
speed: speed.o hash.o $(CCAN_OBJS)
density: density.o hash.o $(CCAN_OBJS)
speed.o: speed.c ../htable.h ../htable.c

View File

@ -0,0 +1,107 @@
/* Density measurements for hashtables. */
#include <ccan/err/err.h>
#include <ccan/htable/htable_type.h>
#include <ccan/htable/htable.c>
#include <ccan/hash/hash.h>
#include <ccan/ptrint/ptrint.h>
#include <ccan/time/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* We don't actually hash objects: we put values in as if they were ptrs */
static uintptr_t key(const ptrint_t *obj)
{
return ptr2int(obj);
}
static size_t hash_uintptr(uintptr_t key)
{
return hashl(&key, 1, 0);
}
static bool cmp(const ptrint_t *p, uintptr_t k)
{
return key(p) == k;
}
HTABLE_DEFINE_TYPE(ptrint_t, key, hash_uintptr, cmp, htable_ptrint);
/* Nanoseconds per operation */
static size_t normalize(const struct timeabs *start,
const struct timeabs *stop,
unsigned int num)
{
return time_to_nsec(time_divide(time_between(*stop, *start), num));
}
static size_t average_run(const struct htable_ptrint *ht, size_t count, size_t *longest)
{
size_t i, total = 0;
*longest = 0;
for (i = 0; i < count; i++) {
size_t h = hash_uintptr(i + 2);
size_t run = 1;
while (get_raw_ptr(&ht->raw, ht->raw.table[h % ((size_t)1 << ht->raw.bits)]) != int2ptr(i + 2)) {
h++;
run++;
}
total += run;
if (run > *longest)
*longest = run;
}
return total / count;
}
int main(int argc, char *argv[])
{
unsigned int i;
size_t num;
struct timeabs start, stop;
struct htable_ptrint ht;
if (argc != 2)
errx(1, "Usage: density <power-of-2-tablesize>");
num = atoi(argv[1]);
printf("Total buckets, buckets used, nanoseconds search time per element, avg run, longest run\n");
for (i = 1; i <= 99; i++) {
uintptr_t j;
struct htable_ptrint_iter it;
size_t count, avg_run, longest_run;
ptrint_t *p;
htable_ptrint_init_sized(&ht, num * 3 / 4);
assert((1 << ht.raw.bits) == num);
/* Can't put 0 or 1 in the hash table: multiply by a prime. */
for (j = 0; j < num * i / 100; j++) {
htable_ptrint_add(&ht, int2ptr(j + 2));
/* stop it from doubling! */
ht.raw.elems = num / 2;
}
/* Must not have changed! */
assert((1 << ht.raw.bits) == num);
/* Clean cache */
count = 0;
for (p = htable_ptrint_first(&ht, &it); p; p = htable_ptrint_next(&ht, &it))
count++;
assert(count == num * i / 100);
start = time_now();
for (j = 0; j < count; j++)
assert(htable_ptrint_get(&ht, j + 2));
stop = time_now();
avg_run = average_run(&ht, count, &longest_run);
printf("%zu,%zu,%zu,%zu,%zu\n",
num, count, normalize(&start, &stop, count), avg_run, longest_run);
fflush(stdout);
htable_ptrint_clear(&ht);
}
return 0;
}

View File

@ -416,7 +416,6 @@ struct io_plan *io_out_always_(struct io_conn *conn,
* // Freed if conn closes normally.
* timeout = tal(conn, struct timeout_timer);
* timeout->conn = conn;
* timeout->t = conn;
* timer_addrel(&timers, &timeout->t, time_from_sec(5));
* return io_sock_shutdown(conn);
* }
@ -815,4 +814,13 @@ struct timemono (*io_time_override(struct timemono (*now)(void)))(void);
*/
int (*io_poll_override(int (*poll)(struct pollfd *fds, nfds_t nfds, int timeout)))(struct pollfd *, nfds_t, int);
/**
* io_have_fd - do we own this file descriptor?
* @fd: the file descriptor.
* @listener: if non-NULL, set to true if it's a listening socket (io_listener).
*
* Returns NULL if we don't own it, otherwise a struct io_conn * or struct io_listener *.
*/
const void *io_have_fd(int fd, bool *listener);
#endif /* CCAN_IO_H */

View File

@ -464,3 +464,15 @@ void *io_loop(struct timers *timers, struct timer **expired)
return ret;
}
const void *io_have_fd(int fd, bool *listener)
{
for (size_t i = 0; i < num_fds; i++) {
if (fds[i]->fd != fd)
continue;
if (listener)
*listener = fds[i]->listener;
return fds[i];
}
return NULL;
}

View File

@ -17,9 +17,8 @@ struct node {
};
/* Closest member to this in a non-empty map. */
static struct strmap *closest(struct strmap *n, const char *member)
static struct strmap *closest(struct strmap *n, const char *member, size_t len)
{
size_t len = strlen(member);
const u8 *bytes = (const u8 *)member;
/* Anything with NULL value is a node. */
@ -35,20 +34,26 @@ static struct strmap *closest(struct strmap *n, const char *member)
return n;
}
void *strmap_get_(const struct strmap *map, const char *member)
void *strmap_getn_(const struct strmap *map,
const char *member, size_t memberlen)
{
struct strmap *n;
/* Not empty map? */
if (map->u.n) {
n = closest((struct strmap *)map, member);
if (streq(member, n->u.s))
n = closest((struct strmap *)map, member, memberlen);
if (!strncmp(member, n->u.s, memberlen) && !n->u.s[memberlen])
return n->v;
}
errno = ENOENT;
return NULL;
}
void *strmap_get_(const struct strmap *map, const char *member)
{
return strmap_getn_(map, member, strlen(member));
}
bool strmap_add_(struct strmap *map, const char *member, const void *value)
{
size_t len = strlen(member);
@ -68,7 +73,7 @@ bool strmap_add_(struct strmap *map, const char *member, const void *value)
}
/* Find closest existing member. */
n = closest(map, member);
n = closest(map, member, len);
/* Find where they differ. */
for (byte_num = 0; n->u.s[byte_num] == member[byte_num]; byte_num++) {

View File

@ -72,7 +72,7 @@ static inline bool strmap_empty_(const struct strmap *map)
/**
* strmap_get - get a value from a string map
* @map: the typed strmap to search.
* @member: the string to search for.
* @member: the string to search for (nul terminated)
*
* Returns the value, or NULL if it isn't in the map (and sets errno = ENOENT).
*
@ -85,6 +85,23 @@ static inline bool strmap_empty_(const struct strmap *map)
tcon_cast((map), canary, strmap_get_(tcon_unwrap(map), (member)))
void *strmap_get_(const struct strmap *map, const char *member);
/**
* strmap_getn - get a value from a string map
* @map: the typed strmap to search.
* @member: the string to search for.
* @memberlen: the length of @member.
*
* Returns the value, or NULL if it isn't in the map (and sets errno = ENOENT).
*
* Example:
* val = strmap_getn(&map, "hello", 5);
* if (val)
* printf("hello => %i\n", *val);
*/
#define strmap_getn(map, member, n) \
tcon_cast((map), canary, strmap_getn_(tcon_unwrap(map), (member), (n)))
void *strmap_getn_(const struct strmap *map, const char *member, size_t n);
/**
* strmap_add - place a member in the string map.
* @map: the typed strmap to add to.

View File

@ -176,25 +176,25 @@ u32 gossmap_chan_idx(const struct gossmap *map, const struct gossmap_chan *chan)
return chan - map->chan_arr;
}
/* htable can't handle NULL values, so we add 1 */
/* htable can't handle NULL or 1 values, so we add 2 */
static struct gossmap_chan *ptrint2chan(const ptrint_t *pidx)
{
return map->chan_arr + ptr2int(pidx) - 1;
return map->chan_arr + ptr2int(pidx) - 2;
}
static ptrint_t *chan2ptrint(const struct gossmap_chan *chan)
{
return int2ptr(chan - map->chan_arr + 1);
return int2ptr(chan - map->chan_arr + 2);
}
static struct gossmap_node *ptrint2node(const ptrint_t *pidx)
{
return map->node_arr + ptr2int(pidx) - 1;
return map->node_arr + ptr2int(pidx) - 2;
}
static ptrint_t *node2ptrint(const struct gossmap_node *node)
{
return int2ptr(node - map->node_arr + 1);
return int2ptr(node - map->node_arr + 2);
}
static struct short_channel_id chanidx_id(const ptrint_t *pidx)

View File

@ -63,6 +63,14 @@ common/test/run-gossmap_local: \
wire/tlvstream.o \
wire/towire.o
common/test/run-gossmap_canned: \
common/base32.o \
common/wireaddr.o \
wire/fromwire.o \
wire/peer$(EXP)_wiregen.o \
wire/tlvstream.o \
wire/towire.o
common/test/run-bolt12_merkle: \
common/amount.o \
common/bigsize.o \

View File

@ -0,0 +1,186 @@
/* Test a canned gossmap we had troubl with */
#include "config.h"
#include "../amount.c"
#include "../fp16.c"
#include "../gossmap.c"
#include "../node_id.c"
#include "../pseudorand.c"
#include <ccan/read_write_all/read_write_all.h>
#include <common/channel_type.h>
#include <common/setup.h>
#include <common/utils.h>
#include <stdio.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 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(); }
/* AUTOGENERATED MOCKS END */
/* Canned gossmap, taken from od -tx1 -Anone -v < /tmp/ltests-rtchpzh1/test_peers_1/lightning-2/regtest/gossip_store | sed 's/ / 0x/g'| cut -c2- | sed -e 's/ /, /' -e 's/$/,/' */
static u8 canned_map[] = {
0x09,0x00,0x00,0x01,0xbc,0x4a,0xe8,0x33,0xa0,0x00,0x00,0x00,0x00,0x10,0x08,0x00,
0x00,0x00,0x00,0x00,0x0f,0x42,0x40,0x01,0xb0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x22,0x6e,
0x46,0x11,0x1a,0x0b,0x59,0xca,0xaf,0x12,0x60,0x43,0xeb,0x5b,0xbf,0x28,0xc3,0x4f,
0x3a,0x5e,0x33,0x2a,0x1f,0xc7,0xb2,0xb7,0x3c,0xf1,0x88,0x91,0x0f,0x00,0x00,0x67,
0x00,0x00,0x01,0x00,0x01,0x02,0x2d,0x22,0x36,0x20,0xa3,0x59,0xa4,0x7f,0xf7,0xf7,
0xac,0x44,0x7c,0x85,0xc4,0x6c,0x92,0x3d,0xa5,0x33,0x89,0x22,0x1a,0x00,0x54,0xc1,
0x1c,0x1e,0x3c,0xa3,0x1d,0x59,0x02,0x66,0xe4,0x59,0x8d,0x1d,0x3c,0x41,0x5f,0x57,
0x2a,0x84,0x88,0x83,0x0b,0x60,0xf7,0xe7,0x44,0xed,0x92,0x35,0xeb,0x0b,0x1b,0xa9,
0x32,0x83,0xb3,0x15,0xc0,0x35,0x18,0x03,0x1b,0x84,0xc5,0x56,0x7b,0x12,0x64,0x40,
0x99,0x5d,0x3e,0xd5,0xaa,0xba,0x05,0x65,0xd7,0x1e,0x18,0x34,0x60,0x48,0x19,0xff,
0x9c,0x17,0xf5,0xe9,0xd5,0xdd,0x07,0x8f,0x03,0x1b,0x84,0xc5,0x56,0x7b,0x12,0x64,
0x40,0x99,0x5d,0x3e,0xd5,0xaa,0xba,0x05,0x65,0xd7,0x1e,0x18,0x34,0x60,0x48,0x19,
0xff,0x9c,0x17,0xf5,0xe9,0xd5,0xdd,0x07,0x8f,0x00,0x00,0x00,0x8e,0xf7,0xf5,0x09,
0x1e,0x00,0x00,0x00,0x00,0x10,0x06,0x00,0x8a,0x01,0x02,0x53,0x0b,0x21,0x64,0xa7,
0xd8,0x03,0x4f,0x50,0xb8,0x16,0x9e,0xaa,0x73,0x6b,0xe0,0x70,0x36,0x16,0xc5,0xb1,
0x04,0xd7,0xfd,0xc0,0x8f,0x68,0x72,0xd7,0x3e,0x38,0x72,0x05,0x7c,0x00,0x81,0x44,
0x96,0xa2,0x22,0x08,0x15,0xdd,0x88,0x86,0xe7,0xb5,0x97,0x45,0x73,0x46,0x35,0xde,
0xf0,0x62,0x11,0x22,0x1f,0xea,0x62,0xd0,0x40,0x6f,0x60,0x06,0x22,0x6e,0x46,0x11,
0x1a,0x0b,0x59,0xca,0xaf,0x12,0x60,0x43,0xeb,0x5b,0xbf,0x28,0xc3,0x4f,0x3a,0x5e,
0x33,0x2a,0x1f,0xc7,0xb2,0xb7,0x3c,0xf1,0x88,0x91,0x0f,0x00,0x00,0x67,0x00,0x00,
0x01,0x00,0x01,0x62,0xc4,0xdb,0x93,0x01,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x3b,
0x02,0x33,0x80,0x00,0x00,0x00,0x8e,0x6f,0xbe,0x57,0x16,0x00,0x00,0x00,0x00,0x10,
0x06,0x00,0x8a,0x01,0x02,0x0c,0x6c,0x84,0xfe,0xfd,0x31,0xe5,0x56,0x63,0xce,0xea,
0x62,0x3c,0x82,0x3c,0xf8,0xb8,0xae,0x6d,0x8a,0xc7,0x60,0x44,0xe5,0x0d,0xaf,0xdd,
0x76,0xae,0x54,0x08,0xec,0x13,0x45,0xa0,0x69,0x60,0x89,0x74,0x88,0xe1,0xe8,0xcb,
0xcc,0x03,0xe3,0x1b,0x4a,0x77,0x17,0xfe,0xa1,0xe1,0xa3,0x42,0x39,0x2d,0xda,0x7b,
0x68,0xf3,0xd5,0x97,0x88,0x06,0x22,0x6e,0x46,0x11,0x1a,0x0b,0x59,0xca,0xaf,0x12,
0x60,0x43,0xeb,0x5b,0xbf,0x28,0xc3,0x4f,0x3a,0x5e,0x33,0x2a,0x1f,0xc7,0xb2,0xb7,
0x3c,0xf1,0x88,0x91,0x0f,0x00,0x00,0x67,0x00,0x00,0x01,0x00,0x01,0x62,0xc4,0xdb,
0x93,0x01,0x01,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x3b,0x02,0x33,0x80,
};
static void check_cannounce(const u8 *cannounce,
const struct short_channel_id *scid,
const struct node_id *n1,
const struct node_id *n2)
{
secp256k1_ecdsa_signature sig;
u8 *features;
struct bitcoin_blkid chain_hash;
struct short_channel_id actual_scid;
struct node_id actual_n1, actual_n2;
struct pubkey k;
assert(fromwire_channel_announcement(cannounce, cannounce,
&sig, &sig, &sig, &sig,
&features, &chain_hash,
&actual_scid,
&actual_n1,
&actual_n2,
&k, &k));
assert(short_channel_id_eq(&actual_scid, scid));
if (node_id_cmp(n1, n2) < 0) {
assert(node_id_eq(&actual_n1, n1));
assert(node_id_eq(&actual_n2, n2));
} else {
assert(node_id_eq(&actual_n1, n2));
assert(node_id_eq(&actual_n2, n1));
}
}
int main(int argc, char *argv[])
{
int fd;
char *gossfile;
struct gossmap *map;
struct node_id l1, l2;
struct short_channel_id scid12;
struct amount_sat capacity;
u32 timestamp, fee_base_msat, fee_proportional_millionths;
u8 message_flags, channel_flags;
struct amount_msat htlc_minimum_msat, htlc_maximum_msat;
u8 *cann;
common_setup(argv[0]);
fd = tmpdir_mkstemp(tmpctx, "run-gossip_canned.XXXXXX", &gossfile);
assert(write_all(fd, canned_map, sizeof(canned_map)));
map = gossmap_load(tmpctx, gossfile, NULL);
assert(map);
/* There is an unannounced channel 1<->2 (103x1x1) */
assert(node_id_from_hexstr("0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518", 66, &l1));
assert(node_id_from_hexstr("022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59", 66, &l2));
assert(gossmap_find_node(map, &l1));
assert(gossmap_find_node(map, &l2));
assert(short_channel_id_from_str("103x1x1", 7, &scid12));
assert(gossmap_find_chan(map, &scid12));
assert(gossmap_find_chan(map, &scid12)->private);
assert(gossmap_chan_get_capacity(map, gossmap_find_chan(map, &scid12),
&capacity));
assert(amount_sat_eq(capacity, AMOUNT_SAT(1000000)));
gossmap_chan_get_update_details(map, gossmap_find_chan(map, &scid12),
0,
&timestamp,
&message_flags,
&channel_flags,
&fee_base_msat,
&fee_proportional_millionths,
&htlc_minimum_msat,
&htlc_maximum_msat);
assert(timestamp == 1657068435);
assert(message_flags == 1);
assert(channel_flags == 0);
assert(fee_base_msat == 1);
assert(fee_proportional_millionths == 10);
assert(amount_msat_eq(htlc_minimum_msat, AMOUNT_MSAT(0)));
assert(amount_msat_eq(htlc_maximum_msat, AMOUNT_MSAT(990000000)));
gossmap_chan_get_update_details(map, gossmap_find_chan(map, &scid12),
1,
&timestamp,
&message_flags,
&channel_flags,
&fee_base_msat,
&fee_proportional_millionths,
&htlc_minimum_msat,
&htlc_maximum_msat);
assert(timestamp == 1657068435);
assert(message_flags == 1);
assert(channel_flags == 1);
assert(fee_base_msat == 1);
assert(fee_proportional_millionths == 10);
assert(amount_msat_eq(htlc_minimum_msat, AMOUNT_MSAT(0)));
assert(amount_msat_eq(htlc_maximum_msat, AMOUNT_MSAT(990000000)));
assert(tal_bytelen(gossmap_chan_get_features(tmpctx, map,
gossmap_find_chan(map, &scid12))) == 0);
cann = gossmap_chan_get_announce(tmpctx, map,
gossmap_find_chan(map, &scid12));
check_cannounce(cann, &scid12, &l1, &l2);
common_shutdown();
}