mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 01:43:36 +01:00
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:
parent
c589543f1c
commit
ae71a87c40
@ -1,3 +1,3 @@
|
||||
CCAN imported from http://ccodearchive.net.
|
||||
|
||||
CCAN version: init-2524-g609670cc
|
||||
CCAN version: init-2540-g8448fd28
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
31
ccan/ccan/htable/test/run-clash.c
Normal file
31
ccan/ccan/htable/test/run-clash.c
Normal 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();
|
||||
}
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
||||
|
107
ccan/ccan/htable/tools/density.c
Normal file
107
ccan/ccan/htable/tools/density.c
Normal 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;
|
||||
}
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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++) {
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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 \
|
||||
|
186
common/test/run-gossmap_canned.c
Normal file
186
common/test/run-gossmap_canned.c
Normal 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,
|
||||
×tamp,
|
||||
&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,
|
||||
×tamp,
|
||||
&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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user