Deterministic reconstruct_manager option in tests
What changed, and why it matters
This commit is a test-only change. It adds a new option that lets tests explicitly choose whether Lightning Dev Kit's ChannelManager rebuilds its pending payment state from ChannelMonitor data, instead of leaving it up to random chance. There is no change to production code behavior and no security issue.
No security action required. This is a benign test-infrastructure change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces a new #[cfg(test)] field, reconstruct_manager_from_monitors: Option
Changed components
lightning/src/ln/channelmanager.rs (test-only ChannelManagerReadArgs struct and from_channel_manager_data logic)lightning/src/ln/functional_test_utils.rs (test helper _reload_node)lightning/src/ln/reload_tests.rs (test callers)Inspect captured patch +43 / −22
diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index e50a9b8..569bb37 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -17819,6 +17819,15 @@ pub struct ChannelManagerReadArgs<
///
/// This is not exported to bindings users because we have no HashMap bindings
pub channel_monitors: HashMap<ChannelId, &'a ChannelMonitor<SP::EcdsaSigner>>,
+
+ /// Whether the `ChannelManager` should attempt to reconstruct its set of pending HTLCs from
+ /// `Channel{Monitor}` data rather than its own persisted maps, which is planned to become
+ /// the default behavior in upcoming versions.
+ ///
+ /// If `None`, whether we reconstruct or use the legacy maps will be decided randomly during
+ /// `ChannelManager::from_channel_manager_data`.
+ #[cfg(test)]
+ pub reconstruct_manager_from_monitors: Option<bool>,
}
impl<
@@ -17856,6 +17865,8 @@ impl<
channel_monitors: hash_map_from_iter(
channel_monitors.drain(..).map(|monitor| (monitor.channel_id(), monitor)),
),
+ #[cfg(test)]
+ reconstruct_manager_from_monitors: None,
}
}
}
@@ -18553,26 +18564,30 @@ impl<
#[cfg(not(test))]
let reconstruct_manager_from_monitors = false;
#[cfg(test)]
- let reconstruct_manager_from_monitors = {
- use core::hash::{BuildHasher, Hasher};
-
- match std::env::var("LDK_TEST_REBUILD_MGR_FROM_MONITORS") {
- Ok(val) => match val.as_str() {
- "1" => true,
- "0" => false,
- _ => panic!("LDK_TEST_REBUILD_MGR_FROM_MONITORS must be 0 or 1, got: {}", val),
- },
- Err(_) => {
- let rand_val =
- std::collections::hash_map::RandomState::new().build_hasher().finish();
- if rand_val % 2 == 0 {
- true
- } else {
- false
- }
- },
- }
- };
+ let reconstruct_manager_from_monitors =
+ args.reconstruct_manager_from_monitors.unwrap_or_else(|| {
+ use core::hash::{BuildHasher, Hasher};
+
+ match std::env::var("LDK_TEST_REBUILD_MGR_FROM_MONITORS") {
+ Ok(val) => match val.as_str() {
+ "1" => true,
+ "0" => false,
+ _ => panic!(
+ "LDK_TEST_REBUILD_MGR_FROM_MONITORS must be 0 or 1, got: {}",
+ val
+ ),
+ },
+ Err(_) => {
+ let rand_val =
+ std::collections::hash_map::RandomState::new().build_hasher().finish();
+ if rand_val % 2 == 0 {
+ true
+ } else {
+ false
+ }
+ },
+ }
+ });
// If there's any preimages for forwarded HTLCs hanging around in ChannelMonitors we
// should ensure we try them again on the inbound edge. We put them here and do so after we
diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs
index 6800078..25b5408 100644
--- a/lightning/src/ln/functional_test_utils.rs
+++ b/lightning/src/ln/functional_test_utils.rs
@@ -911,6 +911,8 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
tx_broadcaster: &broadcaster,
logger: &self.logger,
channel_monitors,
+ #[cfg(test)]
+ reconstruct_manager_from_monitors: None,
},
)
.unwrap();
@@ -1309,7 +1311,7 @@ fn check_claimed_htlcs_match_route<'a, 'b, 'c>(
pub fn _reload_node<'a, 'b, 'c>(
node: &'a Node<'a, 'b, 'c>, config: UserConfig, chanman_encoded: &[u8],
- monitors_encoded: &[&[u8]],
+ monitors_encoded: &[&[u8]], _reconstruct_manager_from_monitors: Option<bool>,
) -> TestChannelManager<'b, 'c> {
let mut monitors_read = Vec::with_capacity(monitors_encoded.len());
for encoded in monitors_encoded {
@@ -1343,6 +1345,8 @@ pub fn _reload_node<'a, 'b, 'c>(
tx_broadcaster: node.tx_broadcaster,
logger: node.logger,
channel_monitors,
+ #[cfg(test)]
+ reconstruct_manager_from_monitors: _reconstruct_manager_from_monitors,
},
)
.unwrap()
@@ -1378,7 +1382,7 @@ macro_rules! reload_node {
$node.chain_monitor = &$new_chain_monitor;
$new_channelmanager =
- _reload_node(&$node, $new_config, &chanman_encoded, $monitors_encoded);
+ _reload_node(&$node, $new_config, &chanman_encoded, $monitors_encoded, None);
$node.node = &$new_channelmanager;
$node.onion_messenger.set_offers_handler(&$new_channelmanager);
$node.onion_messenger.set_async_payments_handler(&$new_channelmanager);
diff --git a/lightning/src/ln/reload_tests.rs b/lightning/src/ln/reload_tests.rs
index 360ffe2..cac1871 100644
--- a/lightning/src/ln/reload_tests.rs
+++ b/lightning/src/ln/reload_tests.rs
@@ -438,6 +438,7 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() {
tx_broadcaster: nodes[0].tx_broadcaster,
logger: &logger,
channel_monitors: node_0_stale_monitors.iter().map(|monitor| { (monitor.channel_id(), monitor) }).collect(),
+ reconstruct_manager_from_monitors: None,
}) { } else {
panic!("If the monitor(s) are stale, this indicates a bug and we should get an Err return");
};
@@ -456,6 +457,7 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() {
tx_broadcaster: nodes[0].tx_broadcaster,
logger: &logger,
channel_monitors: node_0_monitors.iter().map(|monitor| { (monitor.channel_id(), monitor) }).collect(),
+ reconstruct_manager_from_monitors: None,
}).unwrap();
nodes_0_deserialized = nodes_0_deserialized_tmp;
assert!(nodes_0_read.is_empty());
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.