@@ -102,7 +102,21 @@ struct NetworkMap {
102
102
our_node_id : PublicKey ,
103
103
nodes : HashMap < PublicKey , NodeInfo > ,
104
104
}
105
-
105
+ struct MutNetworkMap < ' a > {
106
+ #[ cfg( feature = "non_bitcoin_chain_hash_routing" ) ]
107
+ channels : & ' a mut HashMap < ( u64 , Sha256dHash ) , ChannelInfo > ,
108
+ #[ cfg( not( feature = "non_bitcoin_chain_hash_routing" ) ) ]
109
+ channels : & ' a mut HashMap < u64 , ChannelInfo > ,
110
+ nodes : & ' a mut HashMap < PublicKey , NodeInfo > ,
111
+ }
112
+ impl NetworkMap {
113
+ fn borrow_parts ( & mut self ) -> MutNetworkMap {
114
+ MutNetworkMap {
115
+ channels : & mut self . channels ,
116
+ nodes : & mut self . nodes ,
117
+ }
118
+ }
119
+ }
106
120
impl std:: fmt:: Display for NetworkMap {
107
121
fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> Result < ( ) , std:: fmt:: Error > {
108
122
write ! ( f, "Node id {} network map\n [Channels]\n " , log_pubkey!( self . our_node_id) ) ?;
@@ -199,6 +213,10 @@ impl RoutingMessageHandler for Router {
199
213
}
200
214
201
215
fn handle_channel_announcement ( & self , msg : & msgs:: ChannelAnnouncement ) -> Result < bool , HandleError > {
216
+ if msg. contents . node_id_1 == msg. contents . node_id_2 || msg. contents . bitcoin_key_1 == msg. contents . bitcoin_key_2 {
217
+ return Err ( HandleError { err : "Channel announcement node had a channel with itself" , action : Some ( ErrorAction :: IgnoreError ) } ) ;
218
+ }
219
+
202
220
let msg_hash = Message :: from_slice ( & Sha256dHash :: from_data ( & msg. contents . encode ( ) [ ..] ) [ ..] ) . unwrap ( ) ;
203
221
secp_verify_sig ! ( self . secp_ctx, & msg_hash, & msg. node_signature_1, & msg. contents. node_id_1) ;
204
222
secp_verify_sig ! ( self . secp_ctx, & msg_hash, & msg. node_signature_2, & msg. contents. node_id_2) ;
@@ -209,7 +227,7 @@ impl RoutingMessageHandler for Router {
209
227
panic ! ( "Unknown-required-features ChannelAnnouncements should never deserialize!" ) ;
210
228
}
211
229
212
- match self . chain_monitor . get_chain_utxo ( msg. contents . chain_hash , msg. contents . short_channel_id ) {
230
+ let checked_utxo = match self . chain_monitor . get_chain_utxo ( msg. contents . chain_hash , msg. contents . short_channel_id ) {
213
231
Ok ( ( script_pubkey, _value) ) => {
214
232
let expected_script = Builder :: new ( ) . push_opcode ( opcodes:: All :: OP_PUSHNUM_2 )
215
233
. push_slice ( & msg. contents . bitcoin_key_1 . serialize ( ) )
@@ -220,49 +238,67 @@ impl RoutingMessageHandler for Router {
220
238
}
221
239
//TODO: Check if value is worth storing, use it to inform routing, and compare it
222
240
//to the new HTLC max field in channel_update
241
+ true
223
242
} ,
224
243
Err ( ChainError :: NotSupported ) => {
225
244
// Tentatively accept, potentially exposing us to DoS attacks
245
+ false
226
246
} ,
227
247
Err ( ChainError :: NotWatched ) => {
228
248
return Err ( HandleError { err : "Channel announced on an unknown chain" , action : Some ( ErrorAction :: IgnoreError ) } ) ;
229
249
} ,
230
250
Err ( ChainError :: UnknownTx ) => {
231
251
return Err ( HandleError { err : "Channel announced without corresponding UTXO entry" , action : Some ( ErrorAction :: IgnoreError ) } ) ;
232
252
} ,
233
- }
253
+ } ;
234
254
235
- let mut network = self . network_map . write ( ) . unwrap ( ) ;
255
+ let mut network_lock = self . network_map . write ( ) . unwrap ( ) ;
256
+ let network = network_lock. borrow_parts ( ) ;
257
+
258
+ let chan_info = ChannelInfo {
259
+ features : msg. contents . features . clone ( ) ,
260
+ one_to_two : DirectionalChannelInfo {
261
+ src_node_id : msg. contents . node_id_1 . clone ( ) ,
262
+ last_update : 0 ,
263
+ enabled : false ,
264
+ cltv_expiry_delta : u16:: max_value ( ) ,
265
+ htlc_minimum_msat : u64:: max_value ( ) ,
266
+ fee_base_msat : u32:: max_value ( ) ,
267
+ fee_proportional_millionths : u32:: max_value ( ) ,
268
+ } ,
269
+ two_to_one : DirectionalChannelInfo {
270
+ src_node_id : msg. contents . node_id_2 . clone ( ) ,
271
+ last_update : 0 ,
272
+ enabled : false ,
273
+ cltv_expiry_delta : u16:: max_value ( ) ,
274
+ htlc_minimum_msat : u64:: max_value ( ) ,
275
+ fee_base_msat : u32:: max_value ( ) ,
276
+ fee_proportional_millionths : u32:: max_value ( ) ,
277
+ }
278
+ } ;
236
279
237
280
match network. channels . entry ( NetworkMap :: get_key ( msg. contents . short_channel_id , msg. contents . chain_hash ) ) {
238
- Entry :: Occupied ( _ ) => {
281
+ Entry :: Occupied ( mut entry ) => {
239
282
//TODO: because asking the blockchain if short_channel_id is valid is only optional
240
283
//in the blockchain API, we need to handle it smartly here, though its unclear
241
284
//exactly how...
242
- return Err ( HandleError { err : "Already have knowledge of channel" , action : Some ( ErrorAction :: IgnoreError ) } )
285
+ if checked_utxo {
286
+ // Either our UTXO provider is busted, there was a reorg, or the UTXO provider
287
+ // only sometimes returns results. In any case remove the previous entry. Note
288
+ // that the spec expects us to "blacklist" the node_ids involved, but we can't
289
+ // do that because
290
+ // a) we don't *require* a UTXO provider that always returns results.
291
+ // b) we don't track UTXOs of channels we know about and remove them if they
292
+ // get reorg'd out.
293
+ // c) it's unclear how to do so without exposing ourselves to massive DoS risk.
294
+ Self :: remove_channel_in_nodes ( network. nodes , & entry. get ( ) , msg. contents . short_channel_id ) ;
295
+ * entry. get_mut ( ) = chan_info;
296
+ } else {
297
+ return Err ( HandleError { err : "Already have knowledge of channel" , action : Some ( ErrorAction :: IgnoreError ) } )
298
+ }
243
299
} ,
244
300
Entry :: Vacant ( entry) => {
245
- entry. insert ( ChannelInfo {
246
- features : msg. contents . features . clone ( ) ,
247
- one_to_two : DirectionalChannelInfo {
248
- src_node_id : msg. contents . node_id_1 . clone ( ) ,
249
- last_update : 0 ,
250
- enabled : false ,
251
- cltv_expiry_delta : u16:: max_value ( ) ,
252
- htlc_minimum_msat : u64:: max_value ( ) ,
253
- fee_base_msat : u32:: max_value ( ) ,
254
- fee_proportional_millionths : u32:: max_value ( ) ,
255
- } ,
256
- two_to_one : DirectionalChannelInfo {
257
- src_node_id : msg. contents . node_id_2 . clone ( ) ,
258
- last_update : 0 ,
259
- enabled : false ,
260
- cltv_expiry_delta : u16:: max_value ( ) ,
261
- htlc_minimum_msat : u64:: max_value ( ) ,
262
- fee_base_msat : u32:: max_value ( ) ,
263
- fee_proportional_millionths : u32:: max_value ( ) ,
264
- }
265
- } ) ;
301
+ entry. insert ( chan_info) ;
266
302
}
267
303
} ;
268
304
@@ -302,12 +338,7 @@ impl RoutingMessageHandler for Router {
302
338
& msgs:: HTLCFailChannelUpdate :: ChannelClosed { ref short_channel_id } => {
303
339
let mut network = self . network_map . write ( ) . unwrap ( ) ;
304
340
if let Some ( chan) = network. channels . remove ( short_channel_id) {
305
- network. nodes . get_mut ( & chan. one_to_two . src_node_id ) . unwrap ( ) . channels . retain ( |chan_id| {
306
- chan_id != NetworkMap :: get_short_id ( chan_id)
307
- } ) ;
308
- network. nodes . get_mut ( & chan. two_to_one . src_node_id ) . unwrap ( ) . channels . retain ( |chan_id| {
309
- chan_id != NetworkMap :: get_short_id ( chan_id)
310
- } ) ;
341
+ Self :: remove_channel_in_nodes ( & mut network. nodes , & chan, * short_channel_id) ;
311
342
}
312
343
} ,
313
344
}
@@ -458,6 +489,25 @@ impl Router {
458
489
unimplemented ! ( ) ;
459
490
}
460
491
492
+ fn remove_channel_in_nodes ( nodes : & mut HashMap < PublicKey , NodeInfo > , chan : & ChannelInfo , short_channel_id : u64 ) {
493
+ macro_rules! remove_from_node {
494
+ ( $node_id: expr) => {
495
+ if let Entry :: Occupied ( mut entry) = nodes. entry( $node_id) {
496
+ entry. get_mut( ) . channels. retain( |chan_id| {
497
+ short_channel_id != * NetworkMap :: get_short_id( chan_id)
498
+ } ) ;
499
+ if entry. get( ) . channels. is_empty( ) {
500
+ entry. remove_entry( ) ;
501
+ }
502
+ } else {
503
+ panic!( "Had channel that pointed to unknown node (ie inconsistent network map)!" ) ;
504
+ }
505
+ }
506
+ }
507
+ remove_from_node ! ( chan. one_to_two. src_node_id) ;
508
+ remove_from_node ! ( chan. two_to_one. src_node_id) ;
509
+ }
510
+
461
511
/// Gets a route from us to the given target node.
462
512
/// Extra routing hops between known nodes and the target will be used if they are included in
463
513
/// last_hops.
0 commit comments