Skip to content

Commit 0ca79af

Browse files
Support deleting legacy forward map persistence in 0.5
In 0.3+, we are taking steps to remove the requirement of regularly persisting the ChannelManager and instead rebuild the set of HTLC forwards (and the manager generally) from Channel{Monitor} data. We previously merged support for reconstructing the ChannelManager::decode_update_add_htlcs map from channel data, using a new HTLC onion field that will be present for inbound HTLCs received on 0.3+ only. The plan is that in upcoming LDK versions, the manager will reconstruct this map and the other forward/claimable/pending HTLC maps will automatically repopulate themselves on the next call to process_pending_htlc_forwards. As such, once we're in a future version that reconstructs the pending HTLC set, we can stop persisting the legacy ChannelManager maps such as forward_htlcs, pending_intercepted_htlcs since they will never be used. For 0.3 to be compatible with this future version, in this commit we detect that the manager was last written on a version of LDK that doesn't persist the legacy maps. In that case, we don't try to read the old forwards map and run the new reconstruction logic only.
1 parent 979d564 commit 0ca79af

File tree

1 file changed

+39
-19
lines changed

1 file changed

+39
-19
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16631,6 +16631,17 @@ pub fn provided_init_features(config: &UserConfig) -> InitFeatures {
1663116631
const SERIALIZATION_VERSION: u8 = 1;
1663216632
const MIN_SERIALIZATION_VERSION: u8 = 1;
1663316633

16634+
// We plan to start writing this version in 0.5.
16635+
//
16636+
// LDK 0.5+ will reconstruct the set of pending HTLCs from `Channel{Monitor}` data that started
16637+
// being written in 0.3, ignoring legacy `ChannelManager` HTLC maps on read and not writing them.
16638+
// LDK 0.5+ will automatically fail to read if the pending HTLC set cannot be reconstructed, i.e.
16639+
// if we were last written with pending HTLCs on 0.2- or if the new 0.3+ fields are missing.
16640+
//
16641+
// If 0.3 or 0.4 reads this manager version, it knows that the legacy maps were not written and
16642+
// acts accordingly.
16643+
const RECONSTRUCT_HTLCS_FROM_CHANS_VERSION: u8 = 5;
16644+
1663416645
impl_writeable_tlv_based!(PhantomRouteHints, {
1663516646
(2, channels, required_vec),
1663616647
(4, phantom_scid, required),
@@ -17382,6 +17393,8 @@ pub(super) struct ChannelManagerData<SP: SignerProvider> {
1738217393
forward_htlcs_legacy: HashMap<u64, Vec<HTLCForwardInfo>>,
1738317394
pending_intercepted_htlcs_legacy: HashMap<InterceptId, PendingAddHTLCInfo>,
1738417395
decode_update_add_htlcs_legacy: HashMap<u64, Vec<msgs::UpdateAddHTLC>>,
17396+
// The `ChannelManager` version that was written.
17397+
version: u8,
1738517398
}
1738617399

1738717400
/// Arguments for deserializing [`ChannelManagerData`].
@@ -17405,7 +17418,7 @@ impl<'a, ES: EntropySource, NS: NodeSigner, SP: SignerProvider, L: Logger>
1740517418
fn read<R: io::Read>(
1740617419
reader: &mut R, args: ChannelManagerDataReadArgs<'a, ES, NS, SP, L>,
1740717420
) -> Result<Self, DecodeError> {
17408-
let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION);
17421+
let version = read_ver_prefix!(reader, SERIALIZATION_VERSION);
1740917422

1741017423
let chain_hash: ChainHash = Readable::read(reader)?;
1741117424
let best_block_height: u32 = Readable::read(reader)?;
@@ -17427,21 +17440,26 @@ impl<'a, ES: EntropySource, NS: NodeSigner, SP: SignerProvider, L: Logger>
1742717440
channels.push(channel);
1742817441
}
1742917442

17430-
let forward_htlcs_count: u64 = Readable::read(reader)?;
17431-
let mut forward_htlcs_legacy: HashMap<u64, Vec<HTLCForwardInfo>> =
17432-
hash_map_with_capacity(cmp::min(forward_htlcs_count as usize, 128));
17433-
for _ in 0..forward_htlcs_count {
17434-
let short_channel_id = Readable::read(reader)?;
17435-
let pending_forwards_count: u64 = Readable::read(reader)?;
17436-
let mut pending_forwards = Vec::with_capacity(cmp::min(
17437-
pending_forwards_count as usize,
17438-
MAX_ALLOC_SIZE / mem::size_of::<HTLCForwardInfo>(),
17439-
));
17440-
for _ in 0..pending_forwards_count {
17441-
pending_forwards.push(Readable::read(reader)?);
17442-
}
17443-
forward_htlcs_legacy.insert(short_channel_id, pending_forwards);
17444-
}
17443+
let forward_htlcs_legacy: HashMap<u64, Vec<HTLCForwardInfo>> =
17444+
if version < RECONSTRUCT_HTLCS_FROM_CHANS_VERSION {
17445+
let forward_htlcs_count: u64 = Readable::read(reader)?;
17446+
let mut fwds = hash_map_with_capacity(cmp::min(forward_htlcs_count as usize, 128));
17447+
for _ in 0..forward_htlcs_count {
17448+
let short_channel_id = Readable::read(reader)?;
17449+
let pending_forwards_count: u64 = Readable::read(reader)?;
17450+
let mut pending_forwards = Vec::with_capacity(cmp::min(
17451+
pending_forwards_count as usize,
17452+
MAX_ALLOC_SIZE / mem::size_of::<HTLCForwardInfo>(),
17453+
));
17454+
for _ in 0..pending_forwards_count {
17455+
pending_forwards.push(Readable::read(reader)?);
17456+
}
17457+
fwds.insert(short_channel_id, pending_forwards);
17458+
}
17459+
fwds
17460+
} else {
17461+
new_hash_map()
17462+
};
1744517463

1744617464
let claimable_htlcs_count: u64 = Readable::read(reader)?;
1744717465
let mut claimable_htlcs_list =
@@ -17721,6 +17739,7 @@ impl<'a, ES: EntropySource, NS: NodeSigner, SP: SignerProvider, L: Logger>
1772117739
in_flight_monitor_updates: in_flight_monitor_updates.unwrap_or_default(),
1772217740
peer_storage_dir: peer_storage_dir.unwrap_or_default(),
1772317741
async_receive_offer_cache,
17742+
version,
1772417743
})
1772517744
}
1772617745
}
@@ -18023,6 +18042,7 @@ impl<
1802318042
mut in_flight_monitor_updates,
1802418043
peer_storage_dir,
1802518044
async_receive_offer_cache,
18045+
version: _version,
1802618046
} = data;
1802718047

1802818048
let empty_peer_state = || PeerState {
@@ -18572,10 +18592,10 @@ impl<
1857218592
// persist that state, relying on it being up-to-date on restart. Newer versions are moving
1857318593
// towards reducing this reliance on regular persistence of the `ChannelManager`, and instead
1857418594
// reconstruct HTLC/payment state based on `Channel{Monitor}` data if
18575-
// `reconstruct_manager_from_monitors` is set below. Currently it is only set in tests, randomly
18576-
// to ensure the legacy codepaths also have test coverage.
18595+
// `reconstruct_manager_from_monitors` is set below. Currently we set in tests randomly to
18596+
// ensure the legacy codepaths also have test coverage.
1857718597
#[cfg(not(test))]
18578-
let reconstruct_manager_from_monitors = false;
18598+
let reconstruct_manager_from_monitors = _version >= RECONSTRUCT_HTLCS_FROM_CHANS_VERSION;
1857918599
#[cfg(test)]
1858018600
let reconstruct_manager_from_monitors =
1858118601
args.reconstruct_manager_from_monitors.unwrap_or_else(|| {

0 commit comments

Comments
 (0)