Skip to content

Commit 9f08ea3

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 a359216 commit 9f08ea3

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::keysinterface::{InMemorySigner, KeysInterface, KeysManager, Recipient};
1919
use lightning::chain::{chainmonitor, ChannelMonitorUpdateStatus};
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,7 +541,7 @@ 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;
@@ -550,7 +551,7 @@ async fn start_ldk() {
550551
);
551552
}
552553

553-
// Step 11: Optional: Initialize the P2PGossipSync
554+
// Step 12: Optional: Initialize the P2PGossipSync
554555
let genesis = genesis_block(args.network).header.block_hash();
555556
let network_graph_path = format!("{}/network_graph", ldk_data_dir.clone());
556557
let network_graph =
@@ -561,7 +562,7 @@ async fn start_ldk() {
561562
logger.clone(),
562563
));
563564

564-
// Step 12: Initialize the PeerManager
565+
// Step 13: Initialize the PeerManager
565566
let channel_manager: Arc<ChannelManager> = Arc::new(channel_manager);
566567
let onion_messenger: Arc<OnionMessenger> = Arc::new(OnionMessenger::new(
567568
Arc::clone(&keys_manager),
@@ -586,7 +587,7 @@ async fn start_ldk() {
586587
));
587588

588589
// ## Running LDK
589-
// Step 13: Initialize networking
590+
// Step 14: Initialize networking
590591

591592
let peer_manager_connection_handler = peer_manager.clone();
592593
let listening_port = args.ldk_peer_listening_port;
@@ -612,9 +613,9 @@ async fn start_ldk() {
612613
}
613614
});
614615

615-
// Step 14: Connect and Disconnect Blocks
616+
// Step 15: Connect and Disconnect Blocks
616617
if chain_tip.is_none() {
617-
chain_tip = Some(init::validate_best_block_header(bitcoind_client.as_ref()).await.unwrap());
618+
chain_tip = Some(polled_chain_tip);
618619
}
619620
let channel_manager_listener = channel_manager.clone();
620621
let chain_monitor_listener = chain_monitor.clone();
@@ -631,7 +632,7 @@ async fn start_ldk() {
631632
}
632633
});
633634

634-
// Step 15: Handle LDK Events
635+
// Step 16: Handle LDK Events
635636
let channel_manager_event_listener = channel_manager.clone();
636637
let keys_manager_listener = keys_manager.clone();
637638
// TODO: persist payment info to disk
@@ -656,15 +657,15 @@ async fn start_ldk() {
656657
));
657658
};
658659

659-
// Step 16: Initialize routing ProbabilisticScorer
660+
// Step 17: Initialize routing ProbabilisticScorer
660661
let scorer_path = format!("{}/scorer", ldk_data_dir.clone());
661662
let scorer = Arc::new(Mutex::new(disk::read_scorer(
662663
Path::new(&scorer_path),
663664
Arc::clone(&network_graph),
664665
Arc::clone(&logger),
665666
)));
666667

667-
// Step 17: Create InvoicePayer
668+
// Step 18: Create InvoicePayer
668669
let router = DefaultRouter::new(
669670
network_graph.clone(),
670671
logger.clone(),
@@ -679,10 +680,10 @@ async fn start_ldk() {
679680
payment::Retry::Timeout(Duration::from_secs(10)),
680681
));
681682

682-
// Step 18: Persist ChannelManager and NetworkGraph
683+
// Step 19: Persist ChannelManager and NetworkGraph
683684
let persister = Arc::new(FilesystemPersister::new(ldk_data_dir.clone()));
684685

685-
// Step 19: Background Processing
686+
// Step 20: Background Processing
686687
let background_processor = BackgroundProcessor::start(
687688
persister,
688689
invoice_payer.clone(),

0 commit comments

Comments
 (0)