Skip to content

Commit 03dafa9

Browse files
committed
Fail closed on manager read errors
Only a missing ChannelManager should create a fresh node. Propagate other storage errors so transient failures cannot replace live channel state with an empty manager. Fixes #1026 Co-Authored-By: HAL 9000
1 parent 5e7250a commit 03dafa9

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
@@ -1934,7 +1934,16 @@ fn build_with_store_internal(
19341934

19351935
// Initialize the ChannelManager
19361936
let channel_manager = {
1937-
if let Ok(reader) = channel_manager_bytes_res {
1937+
let channel_manager_bytes = match channel_manager_bytes_res {
1938+
Ok(reader) => Some(reader),
1939+
Err(e) if e.kind() == lightning::io::ErrorKind::NotFound => None,
1940+
Err(e) => {
1941+
log_error!(logger, "Failed to read channel manager from store: {}", e);
1942+
return Err(BuildError::ReadFailed);
1943+
},
1944+
};
1945+
1946+
if let Some(reader) = channel_manager_bytes {
19381947
let channel_monitor_references =
19391948
channel_monitors.iter().map(|(_, chanmon)| chanmon).collect();
19401949
let read_args = ChannelManagerReadArgs::new(
@@ -2426,7 +2435,90 @@ pub(crate) fn sanitize_alias(alias_str: &str) -> Result<NodeAlias, BuildError> {
24262435

24272436
#[cfg(test)]
24282437
mod tests {
2429-
use super::{sanitize_alias, BuildError, NodeAlias};
2438+
use std::future::Future;
2439+
use std::sync::Arc;
2440+
2441+
use lightning::io;
2442+
use lightning::util::persist::{
2443+
KVStore, PageToken, PaginatedKVStore, PaginatedListResponse,
2444+
CHANNEL_MANAGER_PERSISTENCE_KEY, CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE,
2445+
CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE,
2446+
};
2447+
2448+
use super::{sanitize_alias, BuildError, NodeAlias, NodeBuilder};
2449+
use crate::entropy::NodeEntropy;
2450+
use crate::io::test_utils::InMemoryStore;
2451+
use crate::logger::Logger;
2452+
2453+
struct ChannelManagerReadFailingStore(InMemoryStore);
2454+
2455+
impl KVStore for ChannelManagerReadFailingStore {
2456+
fn read(
2457+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str,
2458+
) -> impl Future<Output = Result<Vec<u8>, io::Error>> + 'static + Send {
2459+
let fail_read = primary_namespace == CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE
2460+
&& secondary_namespace == CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE
2461+
&& key == CHANNEL_MANAGER_PERSISTENCE_KEY;
2462+
let read = KVStore::read(&self.0, primary_namespace, secondary_namespace, key);
2463+
async move {
2464+
if fail_read {
2465+
Err(io::Error::new(io::ErrorKind::Other, "channel manager read failed"))
2466+
} else {
2467+
read.await
2468+
}
2469+
}
2470+
}
2471+
2472+
fn write(
2473+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec<u8>,
2474+
) -> impl Future<Output = Result<(), io::Error>> + 'static + Send {
2475+
KVStore::write(&self.0, primary_namespace, secondary_namespace, key, buf)
2476+
}
2477+
2478+
fn remove(
2479+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool,
2480+
) -> impl Future<Output = Result<(), io::Error>> + 'static + Send {
2481+
KVStore::remove(&self.0, primary_namespace, secondary_namespace, key, lazy)
2482+
}
2483+
2484+
fn list(
2485+
&self, primary_namespace: &str, secondary_namespace: &str,
2486+
) -> impl Future<Output = Result<Vec<String>, io::Error>> + 'static + Send {
2487+
KVStore::list(&self.0, primary_namespace, secondary_namespace)
2488+
}
2489+
}
2490+
2491+
impl PaginatedKVStore for ChannelManagerReadFailingStore {
2492+
fn list_paginated(
2493+
&self, primary_namespace: &str, secondary_namespace: &str,
2494+
page_token: Option<PageToken>,
2495+
) -> impl Future<Output = Result<PaginatedListResponse, io::Error>> + 'static + Send {
2496+
PaginatedKVStore::list_paginated(
2497+
&self.0,
2498+
primary_namespace,
2499+
secondary_namespace,
2500+
page_token,
2501+
)
2502+
}
2503+
}
2504+
2505+
#[test]
2506+
fn channel_manager_read_failure_fails_build() {
2507+
let builder = NodeBuilder::new();
2508+
let logger = Arc::new(Logger::new_log_facade());
2509+
#[cfg(not(feature = "uniffi"))]
2510+
let node_entropy = NodeEntropy::from_seed_bytes([42; 64]);
2511+
#[cfg(feature = "uniffi")]
2512+
let node_entropy = NodeEntropy::from_seed_bytes(vec![42; 64]).unwrap();
2513+
2514+
let result = builder.build_with_store_and_logger(
2515+
node_entropy,
2516+
ChannelManagerReadFailingStore(InMemoryStore::new()),
2517+
logger,
2518+
);
2519+
2520+
assert!(matches!(result, Err(BuildError::ReadFailed)));
2521+
}
24302522

24312523
#[test]
24322524
fn sanitize_empty_node_alias() {

0 commit comments

Comments
 (0)