Skip to content

Commit 5e4197b

Browse files
authored
Merge pull request #1032 from tnull/2026-08-fail-channel-manager-read
Fail closed on manager read errors
2 parents 516f8cb + 03dafa9 commit 5e4197b

1 file changed

Lines changed: 94 additions & 2 deletions

File tree

src/builder.rs

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,7 +1967,16 @@ fn build_with_store_internal(
19671967

19681968
// Initialize the ChannelManager
19691969
let channel_manager = {
1970-
if let Ok(reader) = channel_manager_bytes_res {
1970+
let channel_manager_bytes = match channel_manager_bytes_res {
1971+
Ok(reader) => Some(reader),
1972+
Err(e) if e.kind() == lightning::io::ErrorKind::NotFound => None,
1973+
Err(e) => {
1974+
log_error!(logger, "Failed to read channel manager from store: {}", e);
1975+
return Err(BuildError::ReadFailed);
1976+
},
1977+
};
1978+
1979+
if let Some(reader) = channel_manager_bytes {
19711980
let channel_monitor_references =
19721981
channel_monitors.iter().map(|(_, chanmon)| chanmon).collect();
19731982
let read_args = ChannelManagerReadArgs::new(
@@ -2459,7 +2468,90 @@ pub(crate) fn sanitize_alias(alias_str: &str) -> Result<NodeAlias, BuildError> {
24592468

24602469
#[cfg(test)]
24612470
mod tests {
2462-
use super::{sanitize_alias, BuildError, NodeAlias};
2471+
use std::future::Future;
2472+
use std::sync::Arc;
2473+
2474+
use lightning::io;
2475+
use lightning::util::persist::{
2476+
KVStore, PageToken, PaginatedKVStore, PaginatedListResponse,
2477+
CHANNEL_MANAGER_PERSISTENCE_KEY, CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE,
2478+
CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE,
2479+
};
2480+
2481+
use super::{sanitize_alias, BuildError, NodeAlias, NodeBuilder};
2482+
use crate::entropy::NodeEntropy;
2483+
use crate::io::test_utils::InMemoryStore;
2484+
use crate::logger::Logger;
2485+
2486+
struct ChannelManagerReadFailingStore(InMemoryStore);
2487+
2488+
impl KVStore for ChannelManagerReadFailingStore {
2489+
fn read(
2490+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str,
2491+
) -> impl Future<Output = Result<Vec<u8>, io::Error>> + 'static + Send {
2492+
let fail_read = primary_namespace == CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE
2493+
&& secondary_namespace == CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE
2494+
&& key == CHANNEL_MANAGER_PERSISTENCE_KEY;
2495+
let read = KVStore::read(&self.0, primary_namespace, secondary_namespace, key);
2496+
async move {
2497+
if fail_read {
2498+
Err(io::Error::new(io::ErrorKind::Other, "channel manager read failed"))
2499+
} else {
2500+
read.await
2501+
}
2502+
}
2503+
}
2504+
2505+
fn write(
2506+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec<u8>,
2507+
) -> impl Future<Output = Result<(), io::Error>> + 'static + Send {
2508+
KVStore::write(&self.0, primary_namespace, secondary_namespace, key, buf)
2509+
}
2510+
2511+
fn remove(
2512+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool,
2513+
) -> impl Future<Output = Result<(), io::Error>> + 'static + Send {
2514+
KVStore::remove(&self.0, primary_namespace, secondary_namespace, key, lazy)
2515+
}
2516+
2517+
fn list(
2518+
&self, primary_namespace: &str, secondary_namespace: &str,
2519+
) -> impl Future<Output = Result<Vec<String>, io::Error>> + 'static + Send {
2520+
KVStore::list(&self.0, primary_namespace, secondary_namespace)
2521+
}
2522+
}
2523+
2524+
impl PaginatedKVStore for ChannelManagerReadFailingStore {
2525+
fn list_paginated(
2526+
&self, primary_namespace: &str, secondary_namespace: &str,
2527+
page_token: Option<PageToken>,
2528+
) -> impl Future<Output = Result<PaginatedListResponse, io::Error>> + 'static + Send {
2529+
PaginatedKVStore::list_paginated(
2530+
&self.0,
2531+
primary_namespace,
2532+
secondary_namespace,
2533+
page_token,
2534+
)
2535+
}
2536+
}
2537+
2538+
#[test]
2539+
fn channel_manager_read_failure_fails_build() {
2540+
let builder = NodeBuilder::new();
2541+
let logger = Arc::new(Logger::new_log_facade());
2542+
#[cfg(not(feature = "uniffi"))]
2543+
let node_entropy = NodeEntropy::from_seed_bytes([42; 64]);
2544+
#[cfg(feature = "uniffi")]
2545+
let node_entropy = NodeEntropy::from_seed_bytes(vec![42; 64]).unwrap();
2546+
2547+
let result = builder.build_with_store_and_logger(
2548+
node_entropy,
2549+
ChannelManagerReadFailingStore(InMemoryStore::new()),
2550+
logger,
2551+
);
2552+
2553+
assert!(matches!(result, Err(BuildError::ReadFailed)));
2554+
}
24632555

24642556
#[test]
24652557
fn sanitize_empty_node_alias() {

0 commit comments

Comments
 (0)