@ -131,10 +131,8 @@ static void destroy_node(struct node *node, struct routing_state *rstate)
node_map_del ( rstate - > nodes , node ) ;
node_map_del ( rstate - > nodes , node ) ;
/* These remove themselves from the array. */
/* These remove themselves from the array. */
while ( tal_count ( node - > in ) )
while ( tal_count ( node - > channels ) )
tal_free ( node - > in [ 0 ] ) ;
tal_free ( node - > channels [ 0 ] ) ;
while ( tal_count ( node - > out ) )
tal_free ( node - > out [ 0 ] ) ;
}
}
struct node * get_node ( struct routing_state * rstate , const struct pubkey * id )
struct node * get_node ( struct routing_state * rstate , const struct pubkey * id )
@ -151,8 +149,7 @@ static struct node *new_node(struct routing_state *rstate,
n = tal ( rstate , struct node ) ;
n = tal ( rstate , struct node ) ;
n - > id = * id ;
n - > id = * id ;
n - > in = tal_arr ( n , struct node_connection * , 0 ) ;
n - > channels = tal_arr ( n , struct routing_channel * , 0 ) ;
n - > out = tal_arr ( n , struct node_connection * , 0 ) ;
n - > alias = NULL ;
n - > alias = NULL ;
n - > node_announcement = NULL ;
n - > node_announcement = NULL ;
n - > announcement_idx = 0 ;
n - > announcement_idx = 0 ;
@ -164,50 +161,78 @@ static struct node *new_node(struct routing_state *rstate,
return n ;
return n ;
}
}
static bool remove_conn_from_array ( struct node_connection * * * con ns ,
static bool remove_channel_from_array ( struct routing_channel * * * cha ns ,
struct node_connection * n c)
struct routing_channel * c )
{
{
size_t i , n ;
size_t i , n ;
n = tal_count ( * con ns ) ;
n = tal_count ( * cha ns ) ;
for ( i = 0 ; i < n ; i + + ) {
for ( i = 0 ; i < n ; i + + ) {
if ( ( * con ns ) [ i ] ! = n c)
if ( ( * cha ns ) [ i ] ! = c )
continue ;
continue ;
n - - ;
n - - ;
memmove ( * con ns + i , * con ns + i + 1 , sizeof ( * * con ns ) * ( n - i ) ) ;
memmove ( * cha ns + i , * cha ns + i + 1 , sizeof ( * * cha ns ) * ( n - i ) ) ;
tal_resize ( con ns , n ) ;
tal_resize ( cha ns , n ) ;
return true ;
return true ;
}
}
return false ;
return false ;
}
}
static void destroy_connection ( struct node_connection * nc )
static void destroy_routing_channel ( struct routing_channel * chan ,
struct routing_state * rstate )
{
{
if ( ! remove_conn _from_array ( & nc - > dst - > in , nc )
if ( ! remove_channel _from_array ( & cha n- > nodes [ 0 ] - > channels , chan )
| | ! remove_conn _from_array ( & nc - > src - > out , nc ) )
| | ! remove_channel _from_array ( & cha n- > nodes [ 1 ] - > channels , chan ) )
/* FIXME! */
/* FIXME! */
abort ( ) ;
abort ( ) ;
uintmap_del ( & rstate - > channels , chan - > scid . u64 ) ;
if ( tal_count ( chan - > nodes [ 0 ] - > channels ) = = 0 )
tal_free ( chan - > nodes [ 0 ] ) ;
if ( tal_count ( chan - > nodes [ 1 ] - > channels ) = = 0 )
tal_free ( chan - > nodes [ 1 ] ) ;
}
}
static struct node_connection * get_connection ( struct routing_state * rstate ,
/* Returns routing_channel connecting from and to: *idx set to refer
* to connection with src = from , dst = to */
static struct routing_channel * 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 - > channels ) ;
for ( i = 0 ; i < n ; i + + ) {
if ( to - > channels [ i ] - > nodes [ * idx ] = = from )
return to - > channels [ i ] ;
}
return NULL ;
}
static struct node_connection * get_connection ( struct routing_state * rstate ,
const struct pubkey * from_id ,
const struct pubkey * from_id ,
const struct pubkey * to_id )
const struct pubkey * to_id )
{
{
int i , n ;
int idx ;
struct node * from , * to ;
struct node * from , * to ;
struct routing_channel * c ;
from = get_node ( rstate , from_id ) ;
from = get_node ( rstate , from_id ) ;
to = get_node ( rstate , to_id ) ;
to = get_node ( rstate , to_id ) ;
if ( ! from | | ! to )
if ( ! from | | ! to )
return NULL ;
return NULL ;
n = tal_count ( to - > in ) ;
c = find_channel ( rstate , from , to , & idx ) ;
for ( i = 0 ; i < n ; i + + ) {
if ( ! c )
if ( to - > in [ i ] - > src = = from )
return NULL ;
return to - > in [ i ] ;
return c - > connections [ idx ] ;
}
return NULL ;
}
}
/* FIXME: All users of this are confused. */
struct node_connection * get_connection_by_scid ( const struct routing_state * rstate ,
struct node_connection * get_connection_by_scid ( const struct routing_state * rstate ,
const struct short_channel_id * scid ,
const struct short_channel_id * scid ,
const u8 direction )
const u8 direction )
@ -220,80 +245,121 @@ struct node_connection *get_connection_by_scid(const struct routing_state *rstat
return chan - > connections [ direction ] ;
return chan - > connections [ direction ] ;
}
}
static struct node_connection *
static struct routing_channel * new_routing_channel ( struct routing_state * rstate ,
get_or_make_connection ( struct routing_state * rstate ,
const struct short_channel_id * scid ,
const struct pubkey * from_id ,
struct node * n1 ,
const struct pubkey * to_id )
struct node * n2 )
{
{
size_t i , n ;
struct routing_channel * chan = tal ( rstate , struct routing_channel ) ;
struct node * from , * to ;
int n1idx = pubkey_idx ( & n1 - > id , & n2 - > id ) ;
struct node_connection * nc ;
size_t n ;
from = get_node ( rstate , from_id ) ;
chan - > scid = * scid ;
if ( ! from )
chan - > connections [ 0 ] = chan - > connections [ 1 ] = NULL ;
from = new_node ( rstate , from_id ) ;
chan - > nodes [ n1idx ] = n1 ;
to = get_node ( rstate , to_id ) ;
chan - > nodes [ ! n1idx ] = n2 ;
if ( ! to )
chan - > txout_script = NULL ;
to = new_node ( rstate , to_id ) ;
chan - > public = false ;
memset ( & chan - > msg_indexes , 0 , sizeof ( chan - > msg_indexes ) ) ;
n = tal_count ( to - > in ) ;
for ( i = 0 ; i < n ; i + + ) {
if ( to - > in [ i ] - > src = = from ) {
status_trace ( " Updating existing route from %s to %s " ,
type_to_string ( trc , struct pubkey ,
& from - > id ) ,
type_to_string ( trc , struct pubkey ,
& to - > id ) ) ;
return to - > in [ i ] ;
}
}
SUPERVERBOSE ( " Creating new route from %s to %s " ,
n = tal_count ( n2 - > channels ) ;
type_to_string ( trc , struct pubkey , & from - > id ) ,
tal_resize ( & n2 - > channels , n + 1 ) ;
type_to_string ( trc , struct pubkey , & to - > id ) ) ;
n2 - > channels [ n ] = chan ;
n = tal_count ( n1 - > channels ) ;
tal_resize ( & n1 - > channels , n + 1 ) ;
n1 - > channels [ n ] = chan ;
nc = tal ( rstate , struct node_connection ) ;
uintmap_add ( & rstate - > channels , scid - > u64 , chan ) ;
nc - > src = from ;
nc - > dst = to ;
nc - > channel_announcement = NULL ;
nc - > channel_update = NULL ;
nc - > unroutable_until = 0 ;
/* Hook it into in/out arrays. */
tal_add_destructor2 ( chan , destroy_routing_channel , rstate ) ;
i = tal_count ( to - > in ) ;
return chan ;
tal_resize ( & to - > in , i + 1 ) ;
to - > in [ i ] = nc ;
i = tal_count ( from - > out ) ;
tal_resize ( & from - > out , i + 1 ) ;
from - > out [ i ] = nc ;
tal_add_destructor ( nc , destroy_connection ) ;
return nc ;
}
}
static void delete_connection ( const struct node_connection * connection )
static void destroy_node_connection ( struct node_connection * nc ,
struct routing_channel * chan )
{
{
tal_free ( connection ) ;
int dir = nc - > flags & 0x1 ;
struct node_connection * c = chan - > connections [ dir ] ;
assert ( nc = = c ) ;
chan - > connections [ dir ] = NULL ;
/* Both sides deleted? Free channel */
if ( ! chan - > connections [ ! dir ] )
tal_free ( chan ) ;
}
}
struct node_connection * half_add_connection (
static struct node_connection * new_node_connection ( struct routing_state * rstate ,
struct routing_state * rstate ,
struct routing_channel * chan ,
const struct pubkey * from ,
struct node * from ,
const struct pubkey * to ,
struct node * to ,
const struct short_channel_id * schanid ,
int idx )
const u16 flags
)
{
{
struct node_connection * nc ;
struct node_connection * c ;
nc = get_or_make_connection ( rstate , from , to ) ;
nc - > short_channel_id = * schanid ;
/* We are going to put this in the right way? */
nc - > active = false ;
assert ( idx = = pubkey_idx ( & from - > id , & to - > id ) ) ;
nc - > flags = flags ;
assert ( from = = chan - > nodes [ idx ] ) ;
nc - > last_timestamp = - 1 ;
assert ( to = = chan - > nodes [ ! idx ] ) ;
return nc ;
c = tal ( rstate , struct node_connection ) ;
c - > src = from ;
c - > dst = to ;
c - > short_channel_id = chan - > scid ;
c - > channel_announcement = NULL ;
c - > channel_update = NULL ;
c - > unroutable_until = 0 ;
c - > active = false ;
c - > flags = idx ;
c - > last_timestamp = - 1 ;
/* Hook it into in/out arrays. */
assert ( ! chan - > connections [ idx ] ) ;
chan - > connections [ idx ] = c ;
tal_add_destructor2 ( c , destroy_node_connection , chan ) ;
return c ;
}
}
struct node_connection * half_add_connection ( struct routing_state * rstate ,
const struct pubkey * from_id ,
const struct pubkey * to_id ,
const struct short_channel_id * scid )
{
int idx ;
struct node * from , * to ;
struct routing_channel * chan ;
struct node_connection * c ;
from = get_node ( rstate , from_id ) ;
if ( ! from )
from = new_node ( rstate , from_id ) ;
to = get_node ( rstate , to_id ) ;
if ( ! to )
to = new_node ( rstate , to_id ) ;
/* FIXME: callers all have no channel? */
chan = find_channel ( rstate , from , to , & idx ) ;
if ( ! chan )
chan = new_routing_channel ( rstate , scid , from , to ) ;
c = chan - > connections [ idx ] ;
if ( ! c ) {
SUPERVERBOSE ( " Creating new route from %s to %s " ,
type_to_string ( trc , struct pubkey , & from - > id ) ,
type_to_string ( trc , struct pubkey , & to - > id ) ) ;
c = chan - > connections [ idx ]
= new_node_connection ( rstate , chan , from , to , idx ) ;
} else {
status_trace ( " Updating existing route from %s to %s " ,
type_to_string ( trc , struct pubkey , & from - > id ) ,
type_to_string ( trc , struct pubkey , & to - > id ) ) ;
}
assert ( c - > src = = from ) ;
assert ( c - > dst = = to ) ;
return c ;
}
/* Too big to reach, but don't overflow if added. */
/* Too big to reach, but don't overflow if added. */
# define INFINITE 0x3FFFFFFFFFFFFFFFULL
# define INFINITE 0x3FFFFFFFFFFFFFFFULL
@ -333,10 +399,10 @@ static u64 risk_fee(u64 amount, u32 delay, double riskfactor)
/* We track totals, rather than costs. That's because the fee depends
/* We track totals, rather than costs. That's because the fee depends
* on the current amount passing through . */
* on the current amount passing through . */
static void bfg_one_edge ( struct node * node , size_t edgenum , double riskfactor ,
static void bfg_one_edge ( struct node * node ,
struct node_connection * c , double riskfactor ,
double fuzz , const struct siphash_seed * base_seed )
double fuzz , const struct siphash_seed * base_seed )
{
{
struct node_connection * c = node - > in [ edgenum ] ;
size_t h ;
size_t h ;
double fee_scale = 1.0 ;
double fee_scale = 1.0 ;
@ -390,7 +456,7 @@ static void bfg_one_edge(struct node *node, size_t edgenum, double riskfactor,
/* Determine if the given node_connection is routable */
/* Determine if the given node_connection is routable */
static bool nc_is_routable ( const struct node_connection * nc , time_t now )
static bool nc_is_routable ( const struct node_connection * nc , time_t now )
{
{
return nc - > active & & nc - > unroutable_until < now ;
return nc & & nc - > active & & nc - > unroutable_until < now ;
}
}
/* riskfactor is already scaled to per-block amount */
/* riskfactor is already scaled to per-block amount */
@ -449,18 +515,21 @@ find_route(const tal_t *ctx, struct routing_state *rstate,
for ( n = node_map_first ( rstate - > nodes , & it ) ;
for ( n = node_map_first ( rstate - > nodes , & it ) ;
n ;
n ;
n = node_map_next ( rstate - > nodes , & it ) ) {
n = node_map_next ( rstate - > nodes , & it ) ) {
size_t num_edges = tal_count ( n - > in ) ;
size_t num_edges = tal_count ( n - > channels ) ;
for ( i = 0 ; i < num_edges ; i + + ) {
for ( i = 0 ; i < num_edges ; i + + ) {
struct node_connection * c ;
SUPERVERBOSE ( " Node %s edge %i/%zu " ,
SUPERVERBOSE ( " Node %s edge %i/%zu " ,
type_to_string ( trc , struct pubkey ,
type_to_string ( trc , struct pubkey ,
& n - > id ) ,
& n - > id ) ,
i , num_edges ) ;
i , num_edges ) ;
if ( ! nc_is_routable ( n - > in [ i ] , now ) ) {
c = connection_to ( n , n - > channels [ i ] ) ;
if ( ! nc_is_routable ( c , now ) ) {
SUPERVERBOSE ( " ...unroutable " ) ;
SUPERVERBOSE ( " ...unroutable " ) ;
continue ;
continue ;
}
}
bfg_one_edge ( n , i , riskfactor ,
bfg_one_edge ( n , c ,
fuzz , base_seed ) ;
riskfactor , fuzz , base_seed ) ;
SUPERVERBOSE ( " ...done " ) ;
SUPERVERBOSE ( " ...done " ) ;
}
}
}
}
@ -539,7 +608,7 @@ add_channel_direction(struct routing_state *rstate, const struct pubkey *from,
c = c1 ;
c = c1 ;
} else {
} else {
/* We don't know this channel at all, create it */
/* We don't know this channel at all, create it */
c = half_add_connection ( rstate , from , to , short_channel_id , direction ) ;
c = half_add_connection ( rstate , from , to , short_channel_id ) ;
}
}
/* Remember the announcement so we can forward it to new peers */
/* Remember the announcement so we can forward it to new peers */
@ -585,41 +654,6 @@ static bool check_channel_announcement(
check_signed_hash ( & hash , bitcoin2_sig , bitcoin2_key ) ;
check_signed_hash ( & hash , bitcoin2_sig , bitcoin2_key ) ;
}
}
struct routing_channel * routing_channel_new ( const tal_t * ctx ,
struct short_channel_id * scid )
{
struct routing_channel * chan = tal ( ctx , struct routing_channel ) ;
chan - > scid = * scid ;
chan - > connections [ 0 ] = chan - > connections [ 1 ] = NULL ;
chan - > nodes [ 0 ] = chan - > nodes [ 1 ] = NULL ;
chan - > txout_script = NULL ;
chan - > public = false ;
memset ( & chan - > msg_indexes , 0 , sizeof ( chan - > msg_indexes ) ) ;
return chan ;
}
static void destroy_node_connection ( struct node_connection * nc ,
struct routing_state * rstate )
{
struct routing_channel * chan = get_channel ( rstate , & nc - > short_channel_id ) ;
struct node_connection * c = chan - > connections [ nc - > flags & 0x1 ] ;
if ( c = = NULL )
return ;
/* If we found a channel it should be the same */
assert ( nc = = c ) ;
chan - > connections [ nc - > flags & 0x1 ] = NULL ;
}
void channel_add_connection ( struct routing_state * rstate ,
struct routing_channel * chan ,
struct node_connection * nc )
{
int direction = get_channel_direction ( & nc - > src - > id , & nc - > dst - > id ) ;
assert ( chan ! = NULL ) ;
chan - > connections [ direction ] = nc ;
tal_add_destructor2 ( nc , destroy_node_connection , rstate ) ;
}
static void add_pending_node_announcement ( struct routing_state * rstate , struct pubkey * nodeid )
static void add_pending_node_announcement ( struct routing_state * rstate , struct pubkey * nodeid )
{
{
struct pending_node_announce * pna = tal ( rstate , struct pending_node_announce ) ;
struct pending_node_announce * pna = tal ( rstate , struct pending_node_announce ) ;
@ -834,20 +868,6 @@ bool handle_pending_cannouncement(struct routing_state *rstate,
return false ;
return false ;
}
}
chan = get_channel ( rstate , & pending - > short_channel_id ) ;
/* So you're new in town, ey? Let's find you a room in the Inn. */
if ( ! chan ) {
chan = routing_channel_new ( rstate , & pending - > short_channel_id ) ;
uintmap_add ( & rstate - > channels , pending - > short_channel_id . u64 , chan ) ;
} else {
/* See handle_channel_announcement */
assert ( ! chan - > public ) ;
}
/* Channel is now public. */
chan - > public = true ;
/* Is this a new connection? It is if we don't know the
/* Is this a new connection? It is if we don't know the
* channel yet , or do not have a matching announcement in the
* channel yet , or do not have a matching announcement in the
* case of side - loaded channels */
* case of side - loaded channels */
@ -867,8 +887,9 @@ bool handle_pending_cannouncement(struct routing_state *rstate,
c1 = add_channel_direction ( rstate , & pending - > node_id_2 , & pending - > node_id_1 ,
c1 = add_channel_direction ( rstate , & pending - > node_id_2 , & pending - > node_id_1 ,
& pending - > short_channel_id , pending - > announce ) ;
& pending - > short_channel_id , pending - > announce ) ;
channel_add_connection ( rstate , chan , c0 ) ;
/* Channel is now public. */
channel_add_connection ( rstate , chan , c1 ) ;
chan = get_channel ( rstate , scid ) ;
chan - > public = true ;
if ( forward ) {
if ( forward ) {
if ( replace_broadcast ( rstate - > broadcasts ,
if ( replace_broadcast ( rstate - > broadcasts ,
@ -1234,30 +1255,20 @@ struct route_hop *get_route(tal_t *ctx, struct routing_state *rstate,
return hops ;
return hops ;
}
}
/* Get the struct node_connection matching the short_channel_id,
* which must be an out connection of the given node . */
static struct node_connection *
get_out_node_connection_of ( const struct node * node ,
const struct short_channel_id * short_channel_id )
{
int i ;
for ( i = 0 ; i < tal_count ( node - > out ) ; + + i ) {
if ( structeq ( & node - > out [ i ] - > short_channel_id , short_channel_id ) )
return node - > out [ i ] ;
}
return NULL ;
}
/**
/**
* routing_failure_on_nc - Handle routing failure on a specific
* routing_failure_channel_out - Handle routing failure on a specific channel
* node_connection .
*/
*/
static void routing_failure_on_nc ( enum onion_type failcode ,
static void routing_failure_channel_out ( struct node * node ,
struct node_connection * nc ,
enum onion_type failcode ,
time_t now )
struct routing_channel * chan ,
time_t now )
{
{
struct node_connection * nc ;
nc = connection_from ( node , chan ) ;
if ( ! nc )
return ;
/* BOLT #4:
/* BOLT #4:
*
*
* - if the PERM bit is NOT set :
* - if the PERM bit is NOT set :
@ -1267,7 +1278,7 @@ static void routing_failure_on_nc(enum onion_type failcode,
/* Prevent it for 20 seconds. */
/* Prevent it for 20 seconds. */
nc - > unroutable_until = now + 20 ;
nc - > unroutable_until = now + 20 ;
else
else
delete_connection ( nc ) ;
tal_free ( nc ) ;
}
}
void routing_failure ( struct routing_state * rstate ,
void routing_failure ( struct routing_state * rstate ,
@ -1278,7 +1289,6 @@ void routing_failure(struct routing_state *rstate,
{
{
const tal_t * tmpctx = tal_tmpctx ( rstate ) ;
const tal_t * tmpctx = tal_tmpctx ( rstate ) ;
struct node * node ;
struct node * node ;
struct node_connection * nc ;
int i ;
int i ;
enum wire_type t ;
enum wire_type t ;
time_t now = time_now ( ) . ts . tv_sec ;
time_t now = time_now ( ) . ts . tv_sec ;
@ -1308,23 +1318,35 @@ void routing_failure(struct routing_state *rstate,
*
*
*/
*/
if ( failcode & NODE ) {
if ( failcode & NODE ) {
for ( i = 0 ; i < tal_count ( node - > in ) ; + + i )
/* If permanent, we forget entire node and all its channels.
routing_failure_on_nc ( failcode , node - > in [ i ] , now ) ;
* If we did this in a loop , we might use - after - free . */
for ( i = 0 ; i < tal_count ( node - > out ) ; + + i )
if ( failcode & PERM ) {
routing_failure_on_nc ( failcode , node - > out [ i ] , now ) ;
tal_free ( node ) ;
} else {
for ( i = 0 ; i < tal_count ( node - > channels ) ; + + i )
routing_failure_channel_out ( node , failcode ,
node - > channels [ i ] ,
now ) ;
}
} else {
} else {
nc = get_out_node_connection_of ( node , scid ) ;
struct routing_channel * chan = get_channel ( rstate , scid ) ;
if ( nc )
routing_failure_on_nc ( failcode , nc , now ) ;
if ( ! chan )
status_unusual ( " routing_failure: "
" Channel %s unknown " ,
type_to_string ( tmpctx ,
struct short_channel_id ,
scid ) ) ;
else if ( chan - > nodes [ 0 ] ! = node & & chan - > nodes [ 1 ] ! = node )
status_unusual ( " routing_failure: "
" Channel %s does not connect to %s " ,
type_to_string ( tmpctx ,
struct short_channel_id ,
scid ) ,
type_to_string ( tmpctx , struct pubkey ,
erring_node_pubkey ) ) ;
else
else
status_trace ( " UNUSUAL routing_failure: "
routing_failure_channel_out ( node , failcode , chan , now ) ;
" Channel %s not an out channel "
" of node %s " ,
type_to_string ( tmpctx ,
struct short_channel_id ,
scid ) ,
type_to_string ( tmpctx , struct pubkey ,
erring_node_pubkey ) ) ;
}
}
/* Update the channel if UPDATE failcode. Do
/* Update the channel if UPDATE failcode. Do