Skip to content

Commit ae08821

Browse files
committed
Fix channel manager race panic
The race: - (1) If a channel manager is starting for the first time, it gets its initial block hash by calling BlockSource::get_blockchain_info() and constructing a BestBlock out of that. - (2) During the initial chain sync, if chain_tip.is_none() then the best chain_tip is retrieved using lightning_block_sync::init::validate_best_block_header() which similarly uses BlockSource::get_best_block() - If blocks were mined between (1) and (2), the channel manager’s block hash will be at a lower height than that of the block hash contained inside the chain_tip fed to the SpvClient. Suppose that this results in the channel manager being at block 1 and the SpvClient being at block 2. Once block 3 comes in and the SpvClient detects it via poll_best_tip(), the SpvClient computes the ChainDifference between its saved chain_tip value and block 3, concluding that it just needs to connect block 3. However, when Listen::filtered_block_connected is called using the data in block 3, the channel manager panics with “Blocks must be connected in chain-order - the connected header must build on the last connected header” - because block 3’s prev block hash is block 2’s block hash, rather than block 1’s block hash which the channel manager expects This commit fixes it by removing the fresh channel manager's query to the block source, instead deriving its best block from the validated block header using a new `.to_best_block()` method.
1 parent 523ca2d commit ae08821

File tree

1 file changed

+25
-24
lines changed

1 file changed

+25
-24
lines changed

src/main.rs

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use lightning::chain;
1717
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
1818
use lightning::chain::chainmonitor;
1919
use lightning::chain::keysinterface::{InMemorySigner, KeysInterface, KeysManager, Recipient};
20-
use lightning::chain::{BestBlock, Filter, Watch};
20+
use lightning::chain::{Filter, Watch};
2121
use lightning::ln::channelmanager;
2222
use lightning::ln::channelmanager::{
2323
ChainParameters, ChannelManagerReadArgs, SimpleArcChannelManager,
@@ -458,7 +458,12 @@ async fn start_ldk() {
458458
// Step 7: Read ChannelMonitor state from disk
459459
let mut channelmonitors = persister.read_channelmonitors(keys_manager.clone()).unwrap();
460460

461-
// Step 8: Initialize the ChannelManager
461+
// Step 8: Poll for the best chain tip, which may be used by the channel manager & spv client
462+
let polled_chain_tip = init::validate_best_block_header(bitcoind_client.as_ref())
463+
.await
464+
.expect("Failed to fetch best block header and best block");
465+
466+
// Step 9: Initialize the ChannelManager
462467
let mut user_config = UserConfig::default();
463468
user_config.channel_handshake_limits.force_announced_channel_preference = false;
464469
let mut restarting_node = true;
@@ -481,15 +486,11 @@ async fn start_ldk() {
481486
} else {
482487
// We're starting a fresh node.
483488
restarting_node = false;
484-
let getinfo_resp = bitcoind_client.get_blockchain_info().await;
485-
486-
let chain_params = ChainParameters {
487-
network: args.network,
488-
best_block: BestBlock::new(
489-
getinfo_resp.latest_blockhash,
490-
getinfo_resp.latest_height as u32,
491-
),
492-
};
489+
490+
let polled_best_block = polled_chain_tip.to_best_block();
491+
let polled_best_block_hash = polled_best_block.block_hash();
492+
let chain_params =
493+
ChainParameters { network: args.network, best_block: polled_best_block };
493494
let fresh_channel_manager = channelmanager::ChannelManager::new(
494495
fee_estimator.clone(),
495496
chain_monitor.clone(),
@@ -499,11 +500,11 @@ async fn start_ldk() {
499500
user_config,
500501
chain_params,
501502
);
502-
(getinfo_resp.latest_blockhash, fresh_channel_manager)
503+
(polled_best_block_hash, fresh_channel_manager)
503504
}
504505
};
505506

506-
// Step 9: Sync ChannelMonitors and ChannelManager to chain tip
507+
// Step 10: Sync ChannelMonitors and ChannelManager to chain tip
507508
let mut chain_listener_channel_monitors = Vec::new();
508509
let mut cache = UnboundedCache::new();
509510
let mut chain_tip: Option<poll::ValidatedBlockHeader> = None;
@@ -540,14 +541,14 @@ async fn start_ldk() {
540541
);
541542
}
542543

543-
// Step 10: Give ChannelMonitors to ChainMonitor
544+
// Step 11: Give ChannelMonitors to ChainMonitor
544545
for item in chain_listener_channel_monitors.drain(..) {
545546
let channel_monitor = item.1 .0;
546547
let funding_outpoint = item.2;
547548
chain_monitor.watch_channel(funding_outpoint, channel_monitor).unwrap();
548549
}
549550

550-
// Step 11: Optional: Initialize the P2PGossipSync
551+
// Step 12: Optional: Initialize the P2PGossipSync
551552
let genesis = genesis_block(args.network).header.block_hash();
552553
let network_graph_path = format!("{}/network_graph", ldk_data_dir.clone());
553554
let network_graph =
@@ -558,7 +559,7 @@ async fn start_ldk() {
558559
logger.clone(),
559560
));
560561

561-
// Step 12: Initialize the PeerManager
562+
// Step 13: Initialize the PeerManager
562563
let channel_manager: Arc<ChannelManager> = Arc::new(channel_manager);
563564
let onion_messenger: Arc<OnionMessenger> =
564565
Arc::new(OnionMessenger::new(keys_manager.clone(), logger.clone()));
@@ -580,7 +581,7 @@ async fn start_ldk() {
580581
));
581582

582583
// ## Running LDK
583-
// Step 13: Initialize networking
584+
// Step 14: Initialize networking
584585

585586
let peer_manager_connection_handler = peer_manager.clone();
586587
let listening_port = args.ldk_peer_listening_port;
@@ -606,9 +607,9 @@ async fn start_ldk() {
606607
}
607608
});
608609

609-
// Step 14: Connect and Disconnect Blocks
610+
// Step 15: Connect and Disconnect Blocks
610611
if chain_tip.is_none() {
611-
chain_tip = Some(init::validate_best_block_header(bitcoind_client.as_ref()).await.unwrap());
612+
chain_tip = Some(polled_chain_tip);
612613
}
613614
let channel_manager_listener = channel_manager.clone();
614615
let chain_monitor_listener = chain_monitor.clone();
@@ -625,7 +626,7 @@ async fn start_ldk() {
625626
}
626627
});
627628

628-
// Step 15: Handle LDK Events
629+
// Step 16: Handle LDK Events
629630
let channel_manager_event_listener = channel_manager.clone();
630631
let keys_manager_listener = keys_manager.clone();
631632
// TODO: persist payment info to disk
@@ -650,15 +651,15 @@ async fn start_ldk() {
650651
));
651652
};
652653

653-
// Step 16: Initialize routing ProbabilisticScorer
654+
// Step 17: Initialize routing ProbabilisticScorer
654655
let scorer_path = format!("{}/scorer", ldk_data_dir.clone());
655656
let scorer = Arc::new(Mutex::new(disk::read_scorer(
656657
Path::new(&scorer_path),
657658
Arc::clone(&network_graph),
658659
Arc::clone(&logger),
659660
)));
660661

661-
// Step 17: Create InvoicePayer
662+
// Step 18: Create InvoicePayer
662663
let router = DefaultRouter::new(
663664
network_graph.clone(),
664665
logger.clone(),
@@ -673,10 +674,10 @@ async fn start_ldk() {
673674
payment::Retry::Timeout(Duration::from_secs(10)),
674675
));
675676

676-
// Step 18: Persist ChannelManager and NetworkGraph
677+
// Step 19: Persist ChannelManager and NetworkGraph
677678
let persister = Arc::new(FilesystemPersister::new(ldk_data_dir.clone()));
678679

679-
// Step 19: Background Processing
680+
// Step 20: Background Processing
680681
let background_processor = BackgroundProcessor::start(
681682
persister,
682683
invoice_payer.clone(),

0 commit comments

Comments
 (0)