Skip to content

Commit 3f4ad01

Browse files
committed
Stop the chain source upon any startup failure
This is particularly relevant for the electrum chain source; if we fail startup, and we do not stop the electrum chain source before returning an error, then the user will hit a debug assertion on the next restart. We also move code so as to complete all the fallible startup calls before spawning the other background tasks. We do not yet have a way to clean the tasks up if a startup error is returned after the tasks have been spawned.
1 parent 0e76fe8 commit 3f4ad01

1 file changed

Lines changed: 97 additions & 84 deletions

File tree

src/lib.rs

Lines changed: 97 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,16 @@ impl Node {
292292
return Err(Error::AlreadyRunning);
293293
}
294294

295+
match self.start_inner(&mut is_running_lock) {
296+
Ok(()) => Ok(()),
297+
Err(e) => {
298+
self.chain_source.stop();
299+
Err(e)
300+
},
301+
}
302+
}
303+
304+
fn start_inner(&self, is_running_lock: &mut bool) -> Result<(), Error> {
295305
log_info!(
296306
self.logger,
297307
"Starting up LDK Node with node ID {} on network: {}",
@@ -345,6 +355,55 @@ impl Node {
345355
)
346356
})?;
347357

358+
// Bind listeners before spawning background tasks so startup errors cannot leave loops
359+
// running while the node is still marked stopped.
360+
let listeners = if let Some(listening_addresses) = &self.config.listening_addresses {
361+
let logger = Arc::clone(&self.logger);
362+
let listening_addrs = listening_addresses.clone();
363+
self.runtime.block_on(async move {
364+
let mut bind_addrs = Vec::with_capacity(listening_addrs.len());
365+
366+
for listening_addr in &listening_addrs {
367+
let resolved =
368+
tokio::net::lookup_host(listening_addr.to_string()).await.map_err(|e| {
369+
log_error!(
370+
logger,
371+
"Unable to resolve listening address: {:?}. Error details: {}",
372+
listening_addr,
373+
e,
374+
);
375+
Error::InvalidSocketAddress
376+
})?;
377+
bind_addrs.extend(resolved);
378+
}
379+
380+
let mut listeners = Vec::new();
381+
382+
// Try to bind to all addresses
383+
for addr in &bind_addrs {
384+
match tokio::net::TcpListener::bind(addr).await {
385+
Ok(listener) => {
386+
log_trace!(logger, "Listener bound to {}", addr);
387+
listeners.push(listener);
388+
},
389+
Err(e) => {
390+
log_error!(
391+
logger,
392+
"Failed to bind to {}: {} - is something else already listening?",
393+
addr,
394+
e
395+
);
396+
return Err(Error::InvalidSocketAddress);
397+
},
398+
}
399+
}
400+
401+
Ok(listeners)
402+
})?
403+
} else {
404+
Vec::new()
405+
};
406+
348407
// Spawn background task continuously syncing onchain, lightning, and fee rate cache.
349408
let stop_sync_receiver = self.stop_sender.subscribe();
350409
let chain_source = Arc::clone(&self.chain_source);
@@ -415,98 +474,52 @@ impl Node {
415474
);
416475
}
417476

418-
if let Some(listening_addresses) = &self.config.listening_addresses {
419-
// Setup networking
420-
let peer_manager_connection_handler = Arc::clone(&self.peer_manager);
421-
let listening_logger = Arc::clone(&self.logger);
422-
477+
// Setup networking
478+
let peer_manager_connection_handler = Arc::clone(&self.peer_manager);
479+
let listening_logger = Arc::clone(&self.logger);
480+
for listener in listeners {
423481
let logger = Arc::clone(&listening_logger);
424-
let listening_addrs = listening_addresses.clone();
425-
let listeners = self.runtime.block_on(async move {
426-
let mut bind_addrs = Vec::with_capacity(listening_addrs.len());
427-
428-
for listening_addr in &listening_addrs {
429-
let resolved =
430-
tokio::net::lookup_host(listening_addr.to_string()).await.map_err(|e| {
431-
log_error!(
432-
logger,
433-
"Unable to resolve listening address: {:?}. Error details: {}",
434-
listening_addr,
435-
e,
436-
);
437-
Error::InvalidSocketAddress
438-
})?;
439-
bind_addrs.extend(resolved);
440-
}
441-
442-
let mut listeners = Vec::new();
443-
444-
// Try to bind to all addresses
445-
for addr in &bind_addrs {
446-
match tokio::net::TcpListener::bind(addr).await {
447-
Ok(listener) => {
448-
log_trace!(logger, "Listener bound to {}", addr);
449-
listeners.push(listener);
450-
},
451-
Err(e) => {
452-
log_error!(
482+
let peer_mgr = Arc::clone(&peer_manager_connection_handler);
483+
let mut stop_listen = self.stop_sender.subscribe();
484+
let runtime = Arc::clone(&self.runtime);
485+
self.runtime.spawn_cancellable_background_task(async move {
486+
loop {
487+
tokio::select! {
488+
_ = stop_listen.changed() => {
489+
log_debug!(
453490
logger,
454-
"Failed to bind to {}: {} - is something else already listening?",
455-
addr,
456-
e
491+
"Stopping listening to inbound connections."
457492
);
458-
return Err(Error::InvalidSocketAddress);
459-
},
460-
}
461-
}
462-
463-
Ok(listeners)
464-
})?;
465-
466-
for listener in listeners {
467-
let logger = Arc::clone(&listening_logger);
468-
let peer_mgr = Arc::clone(&peer_manager_connection_handler);
469-
let mut stop_listen = self.stop_sender.subscribe();
470-
let runtime = Arc::clone(&self.runtime);
471-
self.runtime.spawn_cancellable_background_task(async move {
472-
loop {
473-
tokio::select! {
474-
_ = stop_listen.changed() => {
475-
log_debug!(
476-
logger,
477-
"Stopping listening to inbound connections."
478-
);
479-
break;
480-
}
481-
res = listener.accept() => {
482-
let tcp_stream = match res {
483-
Ok((tcp_stream, _)) => tcp_stream,
493+
break;
494+
}
495+
res = listener.accept() => {
496+
let tcp_stream = match res {
497+
Ok((tcp_stream, _)) => tcp_stream,
498+
Err(e) => {
499+
log_error!(logger, "Failed to accept inbound connection: {}", e);
500+
continue;
501+
},
502+
};
503+
let peer_mgr = Arc::clone(&peer_mgr);
504+
let logger = Arc::clone(&logger);
505+
runtime.spawn_cancellable_background_task(async move {
506+
let tcp_stream = match tcp_stream.into_std() {
507+
Ok(tcp_stream) => tcp_stream,
484508
Err(e) => {
485-
log_error!(logger, "Failed to accept inbound connection: {}", e);
486-
continue;
509+
log_error!(logger, "Failed to convert inbound connection: {}", e);
510+
return;
487511
},
488512
};
489-
let peer_mgr = Arc::clone(&peer_mgr);
490-
let logger = Arc::clone(&logger);
491-
runtime.spawn_cancellable_background_task(async move {
492-
let tcp_stream = match tcp_stream.into_std() {
493-
Ok(tcp_stream) => tcp_stream,
494-
Err(e) => {
495-
log_error!(logger, "Failed to convert inbound connection: {}", e);
496-
return;
497-
},
498-
};
499-
lightning_net_tokio::setup_inbound(
500-
Arc::clone(&peer_mgr),
501-
tcp_stream,
502-
)
503-
.await;
504-
});
505-
}
513+
lightning_net_tokio::setup_inbound(
514+
Arc::clone(&peer_mgr),
515+
tcp_stream,
516+
)
517+
.await;
518+
});
506519
}
507520
}
508-
});
509-
}
521+
}
522+
});
510523
}
511524

512525
// Regularly reconnect to persisted peers.

0 commit comments

Comments
 (0)