Skip to content

Commit dc087fb

Browse files
ovitrifclaude
andcommitted
fix: clarify channel manager migration guard rationale and add corrupt-data test
Correct the comment explaining why the channel manager guard uses existence-only checks: the real blocker is that ChannelManagerReadArgs requires already-deserialized channel monitors (loaded later in build), not that infrastructure is unavailable. Add test documenting intentional behavior when corrupt data exists in the store: migration is skipped (existence-only), preserving corrupt data. This is the correct trade-off — overwriting a potentially valid channel manager with stale FS data risks fund loss. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 4f91c8c commit dc087fb

1 file changed

Lines changed: 48 additions & 0 deletions

File tree

src/builder.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,6 +1347,13 @@ where
13471347
K: EntropySource + SignerProvider<EcdsaSigner = InMemorySigner>,
13481348
{
13491349
if let Some(manager_bytes) = &migration.channel_manager {
1350+
// Existence-only check (no deserialization). Unlike monitors, we cannot
1351+
// deserialize the channel manager here because ChannelManagerReadArgs
1352+
// requires already-deserialized channel_monitor_references, which are
1353+
// loaded later in build(). This means corrupt existing data will block
1354+
// migration — that is intentional: overwriting a potentially valid
1355+
// channel manager with stale FS data risks fund loss, while a node that
1356+
// refuses to start can be recovered by clearing the KV store.
13501357
let should_write = match runtime.block_on(KVStore::read(
13511358
&**kv_store,
13521359
CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE,
@@ -2803,6 +2810,47 @@ mod tests {
28032810
assert_eq!(stored, existing_data);
28042811
}
28052812

2813+
#[test]
2814+
fn test_channel_manager_migration_skips_even_when_existing_data_is_corrupt() {
2815+
let (store, keys_manager, logger, runtime) = make_test_deps(&[42u8; 32]);
2816+
2817+
// Pre-populate the store with corrupt/garbage data.
2818+
let corrupt_data = vec![0xDE, 0xAD, 0xBE, 0xEF];
2819+
runtime
2820+
.block_on(KVStore::write(
2821+
&*store,
2822+
CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE,
2823+
CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE,
2824+
CHANNEL_MANAGER_PERSISTENCE_KEY,
2825+
corrupt_data.clone(),
2826+
))
2827+
.unwrap();
2828+
2829+
// Migration should skip (existence-only check, no deserialization).
2830+
// This is intentional: overwriting potentially valid data with stale
2831+
// FS bytes risks fund loss; a node that fails to start on corrupt
2832+
// data can be recovered by clearing the KV store.
2833+
let migration = ChannelDataMigration {
2834+
channel_manager: Some(vec![0x01, 0x02, 0x03]),
2835+
channel_monitors: Vec::new(),
2836+
};
2837+
2838+
let result =
2839+
apply_channel_data_migration(&migration, &store, &keys_manager, &logger, &runtime);
2840+
assert!(result.is_ok());
2841+
2842+
// Verify the corrupt data is preserved (migration was skipped).
2843+
let stored = runtime
2844+
.block_on(KVStore::read(
2845+
&*store,
2846+
CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE,
2847+
CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE,
2848+
CHANNEL_MANAGER_PERSISTENCE_KEY,
2849+
))
2850+
.unwrap();
2851+
assert_eq!(stored, corrupt_data);
2852+
}
2853+
28062854
#[test]
28072855
fn test_channel_manager_migration_fails_on_store_read_error() {
28082856
let store: Arc<DynStore> = Arc::new(FailingReadStore);

0 commit comments

Comments
 (0)