Skip to content

Commit 13a8a3f

Browse files
joostjagerclaude
andcommitted
Document the logical steps within ChannelManager deserialization stage 2
Add step comments to from_channel_manager_data to clarify the seven logical phases of ChannelManager reconstruction: 1. Channel/monitor reconciliation 2. Initialize missing optional fields 3. Replay in-flight monitor updates 4. Reconstruct HTLC state from monitors 5. Reconstruct claimable payments 6. Construct the ChannelManager 7. Replay pending claims and fail HTLCs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 2a8fdc9 commit 13a8a3f

1 file changed

Lines changed: 26 additions & 2 deletions

File tree

lightning/src/ln/channelmanager.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17815,6 +17815,12 @@ impl<
1781517815
is_connected: false,
1781617816
};
1781717817

17818+
// Step 1: Channel/monitor reconciliation.
17819+
//
17820+
// Validate each deserialized channel against its corresponding ChannelMonitor to ensure
17821+
// consistency. Channels that are behind their monitors are force-closed. Channels without
17822+
// monitors (except those awaiting initial persistence) are rejected. Monitors without
17823+
// channels get force-close updates queued.
1781817824
const MAX_ALLOC_SIZE: usize = 1024 * 64;
1781917825
let mut failed_htlcs = Vec::new();
1782017826
let channel_count = channels.len();
@@ -18075,14 +18081,17 @@ impl<
1807518081
}
1807618082
}
1807718083

18078-
// Apply peer features from deserialized data
18084+
// Apply peer features from deserialized data.
1807918085
for (peer_pubkey, latest_features) in peer_init_features {
1808018086
if let Some(peer_state) = per_peer_state.get_mut(&peer_pubkey) {
1808118087
peer_state.get_mut().unwrap().latest_features = latest_features;
1808218088
}
1808318089
}
1808418090

18085-
// Post-deserialization processing
18091+
// Step 2: Initialize missing optional fields.
18092+
//
18093+
// Fields that were added in later versions may be None when reading older data.
18094+
// Generate fresh random values for these fields to maintain functionality.
1808618095
let mut decode_update_add_htlcs = new_hash_map();
1808718096
if fake_scid_rand_bytes.is_none() {
1808818097
fake_scid_rand_bytes = Some(args.entropy_source.get_secure_random_bytes());
@@ -18110,6 +18119,8 @@ impl<
1811018119
}
1811118120
}
1811218121

18122+
// Step 3: Replay in-flight monitor updates.
18123+
//
1811318124
// We have to replay (or skip, if they were completed after we wrote the `ChannelManager`)
1811418125
// each `ChannelMonitorUpdate` in `in_flight_monitor_updates`. After doing so, we have to
1811518126
// check that each channel we have isn't newer than the latest `ChannelMonitorUpdate`(s) we
@@ -18336,6 +18347,8 @@ impl<
1833618347
pending_background_events.push(new_event);
1833718348
}
1833818349

18350+
// Step 4: Reconstruct HTLC state from monitors.
18351+
//
1833918352
// In LDK 0.2 and below, the `ChannelManager` would track all payments and HTLCs internally and
1834018353
// persist that state, relying on it being up-to-date on restart. Newer versions are moving
1834118354
// towards reducing this reliance on regular persistence of the `ChannelManager`, and instead
@@ -18740,6 +18753,10 @@ impl<
1874018753
}
1874118754
}
1874218755

18756+
// Step 5: Reconstruct claimable payments.
18757+
//
18758+
// Combine claimable_htlcs_list with their purposes and onion fields. For very old data
18759+
// (pre-0.0.107) that lacks purposes, reconstruct them from legacy hop data.
1874318760
let expanded_inbound_key = args.node_signer.get_expanded_key();
1874418761

1874518762
let mut claimable_payments = hash_map_with_capacity(claimable_htlcs_list.len());
@@ -19065,6 +19082,9 @@ impl<
1906519082
}
1906619083
}
1906719084

19085+
// Step 6: Construct the ChannelManager.
19086+
//
19087+
// All data has been validated and reconciled. Build the final ChannelManager struct.
1906819088
let best_block = BestBlock::new(best_block_hash, best_block_height);
1906919089
let flow = OffersMessageFlow::new(
1907019090
chain_hash,
@@ -19143,6 +19163,10 @@ impl<
1914319163
testing_dnssec_proof_offer_resolution_override: Mutex::new(new_hash_map()),
1914419164
};
1914519165

19166+
// Step 7: Replay pending claims and fail HTLCs.
19167+
//
19168+
// Process any payment preimages stored in monitors that need to be claimed on the inbound
19169+
// edge. Also fail any HTLCs that were dropped during channel reconciliation.
1914619170
let mut processed_claims: HashSet<Vec<MPPClaimHTLCSource>> = new_hash_set();
1914719171
for (_, monitor) in args.channel_monitors.iter() {
1914819172
for (payment_hash, (payment_preimage, payment_claims)) in monitor.get_stored_preimages()

0 commit comments

Comments
 (0)