@ -1,6 +1,7 @@
/* This contains the code which actively seeks out gossip from peers */
/* This contains the code which actively seeks out gossip from peers */
# include <bitcoin/short_channel_id.h>
# include <bitcoin/short_channel_id.h>
# include <ccan/array_size/array_size.h>
# include <ccan/array_size/array_size.h>
# include <ccan/asort/asort.h>
# include <ccan/list/list.h>
# include <ccan/list/list.h>
# include <ccan/mem/mem.h>
# include <ccan/mem/mem.h>
# include <ccan/tal/tal.h>
# include <ccan/tal/tal.h>
@ -70,7 +71,6 @@ struct seeker {
/* Array of scids for node announcements. */
/* Array of scids for node announcements. */
struct short_channel_id * nannounce_scids ;
struct short_channel_id * nannounce_scids ;
u8 * nannounce_query_flags ;
u8 * nannounce_query_flags ;
u64 nannounce_offset ;
/* Are there any node_ids we didn't know? Implies we're
/* Are there any node_ids we didn't know? Implies we're
* missing channels . */
* missing channels . */
@ -430,62 +430,77 @@ static bool next_block_range(struct seeker *seeker,
return false ;
return false ;
}
}
static int cmp_scid ( const struct short_channel_id * a ,
const struct short_channel_id * b ,
void * unused )
{
if ( a - > u64 > b - > u64 )
return 1 ;
else if ( a - > u64 < b - > u64 )
return - 1 ;
return 0 ;
}
/* We can't ask for channels by node_id, so probe at random */
/* We can't ask for channels by node_id, so probe at random */
static bool get_unannounced_nodes ( const tal_t * ctx ,
static bool get_unannounced_nodes ( const tal_t * ctx ,
struct routing_state * rstate ,
struct routing_state * rstate ,
size_t max ,
size_t max ,
u64 * offset ,
struct short_channel_id * * scids ,
struct short_channel_id * * scids ,
u8 * * query_flags )
u8 * * query_flags )
{
{
size_t num = 0 ;
size_t num = 0 ;
u64 offset ;
u64 threshold = pseudorand_u64 ( ) ;
/* Pick an example short_channel_id at random to query. As a
/* Pick an example short_channel_id at random to query. As a
* side - effect this gets the node . */
* side - effect this gets the node . */
* scids = tal_arr ( ctx , struct short_channel_id , max ) ;
* scids = tal_arr ( ctx , struct short_channel_id , max ) ;
* query_flags = tal_arr ( ctx , u8 , max ) ;
/* We need to query short_channel_id in order, though (spec
/* FIXME: This is inefficient! Reuse next_block_range here! */
* says it ) , so we walk those rather than walking nodes . We go
for ( struct chan * c = uintmap_first ( & rstate - > chanmap , & offset ) ;
* backwards , as those are the ones we are most likely to be missing ,
* and also it changes most over time . */
for ( struct chan * c = uintmap_before ( & rstate - > chanmap , offset ) ;
c ;
c ;
c = uintmap_before ( & rstate - > chanmap , offset ) ) {
c = uintmap_after ( & rstate - > chanmap , & offset ) ) {
u8 qflags = 0 ;
/* Local-only? Don't ask. */
/* Local-only? Don't ask. */
if ( ! is_chan_public ( c ) )
if ( ! is_chan_public ( c ) )
continue ;
continue ;
if ( ! c - > nodes [ 0 ] - > bcast . index )
if ( c - > nodes [ 0 ] - > bcast . index & & c - > nodes [ 1 ] - > bcast . index )
qflags | = SCID_QF_NODE1 ;
continue ;
if ( ! c - > nodes [ 1 ] - > bcast . index )
qflags | = SCID_QF_NODE2 ;
if ( num < max ) {
if ( qflags ) {
( * scids ) [ num + + ] = c - > scid ;
/* Since we're going backwards, place end first */
} else {
( * scids ) [ max - 1 - num ] = c - > scid ;
/* Maybe replace one: approx. reservoir sampling */
( * query_flags ) [ max - 1 - num ] = qflags ;
u64 p = pseudorand_u64 ( ) ;
if ( + + num = = max )
if ( p > threshold ) {
break ;
( * scids ) [ pseudorand ( max ) ] = c - > scid ;
threshold = p ;
}
}
}
}
}
if ( num = = 0 ) {
if ( num = = 0 ) {
* scids = tal_free ( * scids ) ;
* scids = tal_free ( * scids ) ;
* query_flags = tal_free ( * query_flags ) ;
return false ;
return false ;
}
}
if ( num < max ) {
if ( num < max )
memmove ( * scids , * scids + max - num ,
num * sizeof ( * * scids ) ) ;
memmove ( * query_flags , * query_flags + max - num ,
num * sizeof ( * * query_flags ) ) ;
tal_resize ( scids , num ) ;
tal_resize ( scids , num ) ;
tal_resize ( query_flags , num ) ;
}
/* Sort them into order. */
asort ( * scids , num , cmp_scid , NULL ) ;
/* Now get flags. */
* query_flags = tal_arr ( ctx , u8 , num ) ;
for ( size_t i = 0 ; i < tal_count ( * scids ) ; i + + ) {
struct chan * c = get_channel ( rstate , & ( * scids ) [ i ] ) ;
( * query_flags ) [ i ] = 0 ;
if ( ! c - > nodes [ 0 ] - > bcast . index )
( * query_flags ) [ i ] | = SCID_QF_NODE1 ;
if ( ! c - > nodes [ 1 ] - > bcast . index )
( * query_flags ) [ i ] | = SCID_QF_NODE2 ;
}
return true ;
return true ;
}
}
@ -545,7 +560,6 @@ static void nodeannounce_query_done(struct peer *peer, bool complete)
num_scids = 7000 ;
num_scids = 7000 ;
if ( ! get_unannounced_nodes ( seeker , seeker - > daemon - > rstate , num_scids ,
if ( ! get_unannounced_nodes ( seeker , seeker - > daemon - > rstate , num_scids ,
& seeker - > nannounce_offset ,
& seeker - > nannounce_scids ,
& seeker - > nannounce_scids ,
& seeker - > nannounce_query_flags ) ) {
& seeker - > nannounce_query_flags ) ) {
/* Nothing unknown at all? Great, we're done */
/* Nothing unknown at all? Great, we're done */
@ -563,8 +577,8 @@ static void peer_gossip_probe_nannounces(struct seeker *seeker)
peer = random_seeker ( seeker , peer_can_take_scid_query ) ;
peer = random_seeker ( seeker , peer_can_take_scid_query ) ;
set_state ( seeker , PROBING_NANNOUNCES , peer ,
set_state ( seeker , PROBING_NANNOUNCES , peer ,
" Probing for %zu scids at offset %zu " ,
" Probing for %zu scids " ,
tal_count ( seeker - > nannounce_scids ) , seeker - > nannounce_offset ) ;
tal_count ( seeker - > nannounce_scids ) ) ;
if ( ! peer )
if ( ! peer )
return ;
return ;
@ -668,10 +682,8 @@ static void process_scid_probe(struct peer *peer,
return ;
return ;
}
}
/* Channel probe finished, try asking for 32 unannounced nodes. */
/* Channel probe finished, try asking for 128 unannounced nodes. */
seeker - > nannounce_offset = UINT64_MAX ;
if ( ! get_unannounced_nodes ( seeker , seeker - > daemon - > rstate , 128 ,
if ( ! get_unannounced_nodes ( seeker , seeker - > daemon - > rstate , 32 ,
& seeker - > nannounce_offset ,
& seeker - > nannounce_scids ,
& seeker - > nannounce_scids ,
& seeker - > nannounce_query_flags ) ) {
& seeker - > nannounce_query_flags ) ) {
/* No unknown nodes. Great! */
/* No unknown nodes. Great! */
@ -716,7 +728,6 @@ static void probe_random_scids(struct seeker *seeker, size_t num_blocks)
}
}
seeker - > nannounce_scids = NULL ;
seeker - > nannounce_scids = NULL ;
seeker - > nannounce_offset = UINT64_MAX ;
peer_gossip_probe_scids ( seeker ) ;
peer_gossip_probe_scids ( seeker ) ;
}
}