Skip to content

Commit fce5071

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 159b210 commit fce5071

File tree

1 file changed

+32
-15
lines changed

1 file changed

+32
-15
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16643,6 +16643,17 @@ pub fn provided_init_features(config: &UserConfig) -> InitFeatures {
1664316643
const SERIALIZATION_VERSION: u8 = 1;
1664416644
const MIN_SERIALIZATION_VERSION: u8 = 1;
1664516645

16646+
// We plan to start writing this version in 0.5.
16647+
//
16648+
// LDK 0.5+ will reconstruct the set of pending HTLCs from `Channel{Monitor}` data that started
16649+
// being written in 0.3, ignoring legacy `ChannelManager` HTLC maps on read and not writing them.
16650+
// LDK 0.5+ will automatically fail to read if the pending HTLC set cannot be reconstructed, i.e.
16651+
// if we were last written with pending HTLCs on 0.2- or if the new 0.3+ fields are missing.
16652+
//
16653+
// If 0.3 or 0.4 reads this manager version, it knows that the legacy maps were not written and
16654+
// acts accordingly.
16655+
const RECONSTRUCT_HTLCS_FROM_CHANS_VERSION: u8 = 2;
16656+
1664616657
impl_writeable_tlv_based!(PhantomRouteHints, {
1664716658
(2, channels, required_vec),
1664816659
(4, phantom_scid, required),
@@ -17644,7 +17655,7 @@ where
1764417655
fn read<Reader: io::Read>(
1764517656
reader: &mut Reader, mut args: ChannelManagerReadArgs<'a, M, T, ES, NS, SP, F, R, MR, L>,
1764617657
) -> Result<Self, DecodeError> {
17647-
let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION);
17658+
let ver = read_ver_prefix!(reader, SERIALIZATION_VERSION);
1764817659

1764917660
let chain_hash: ChainHash = Readable::read(reader)?;
1765017661
let best_block_height: u32 = Readable::read(reader)?;
@@ -17931,23 +17942,24 @@ where
1793117942
}
1793217943

1793317944
const MAX_ALLOC_SIZE: usize = 1024 * 64;
17934-
let forward_htlcs_count: u64 = Readable::read(reader)?;
1793517945
// Marked `_legacy` because in versions > 0.2 we are taking steps to remove the requirement of
1793617946
// regularly persisting the `ChannelManager` and instead rebuild the set of HTLC forwards from
1793717947
// `Channel{Monitor}` data. See `reconstruct_manager_from_monitors` usage below.
17938-
let mut forward_htlcs_legacy: HashMap<u64, Vec<HTLCForwardInfo>> =
17939-
hash_map_with_capacity(cmp::min(forward_htlcs_count as usize, 128));
17940-
for _ in 0..forward_htlcs_count {
17941-
let short_channel_id = Readable::read(reader)?;
17942-
let pending_forwards_count: u64 = Readable::read(reader)?;
17943-
let mut pending_forwards = Vec::with_capacity(cmp::min(
17944-
pending_forwards_count as usize,
17945-
MAX_ALLOC_SIZE / mem::size_of::<HTLCForwardInfo>(),
17946-
));
17947-
for _ in 0..pending_forwards_count {
17948-
pending_forwards.push(Readable::read(reader)?);
17948+
let mut forward_htlcs_legacy: HashMap<u64, Vec<HTLCForwardInfo>> = new_hash_map();
17949+
if ver < RECONSTRUCT_HTLCS_FROM_CHANS_VERSION {
17950+
let forward_htlcs_count: u64 = Readable::read(reader)?;
17951+
for _ in 0..forward_htlcs_count {
17952+
let short_channel_id = Readable::read(reader)?;
17953+
let pending_forwards_count: u64 = Readable::read(reader)?;
17954+
let mut pending_forwards = Vec::with_capacity(cmp::min(
17955+
pending_forwards_count as usize,
17956+
MAX_ALLOC_SIZE / mem::size_of::<HTLCForwardInfo>(),
17957+
));
17958+
for _ in 0..pending_forwards_count {
17959+
pending_forwards.push(Readable::read(reader)?);
17960+
}
17961+
forward_htlcs_legacy.insert(short_channel_id, pending_forwards);
1794917962
}
17950-
forward_htlcs_legacy.insert(short_channel_id, pending_forwards);
1795117963
}
1795217964

1795317965
let claimable_htlcs_count: u64 = Readable::read(reader)?;
@@ -18086,6 +18098,11 @@ where
1808618098
(19, peer_storage_dir, optional_vec),
1808718099
(21, async_receive_offer_cache, (default_value, async_receive_offer_cache)),
1808818100
});
18101+
if (decode_update_add_htlcs_legacy.is_some() || pending_intercepted_htlcs_legacy.is_some())
18102+
&& ver >= RECONSTRUCT_HTLCS_FROM_CHANS_VERSION
18103+
{
18104+
return Err(DecodeError::InvalidValue);
18105+
}
1808918106
let mut decode_update_add_htlcs_legacy =
1809018107
decode_update_add_htlcs_legacy.unwrap_or_else(|| new_hash_map());
1809118108
let mut pending_intercepted_htlcs_legacy =
@@ -18385,7 +18402,7 @@ where
1838518402
// `reconstruct_manager_from_monitors` is set below. Currently it is only set in tests, randomly
1838618403
// to ensure the legacy codepaths also have test coverage.
1838718404
#[cfg(not(test))]
18388-
let reconstruct_manager_from_monitors = false;
18405+
let reconstruct_manager_from_monitors = ver >= RECONSTRUCT_HTLCS_FROM_CHANS_VERSION;
1838918406
#[cfg(test)]
1839018407
let reconstruct_manager_from_monitors = {
1839118408
use core::hash::{BuildHasher, Hasher};

0 commit comments

Comments
 (0)