/// This is used to provide payment preimage(s) out-of-band during startup without updating the
/// off-chain state with a new commitment transaction.
- pub(crate) fn provide_payment_preimage<B: Deref, F: Deref, L: Deref>(
+ ///
+ /// It is used only for legacy (created prior to LDK 0.1) pending payments on upgrade, and the
+ /// flow that uses it assumes that this [`ChannelMonitor`] is persisted prior to the
+ /// [`ChannelManager`] being persisted (as the state necessary to call this method again is
+ /// removed from the [`ChannelManager`] and thus a persistence inversion would imply we do not
+ /// get the preimage back into this [`ChannelMonitor`] on startup).
+ ///
+ /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
+ pub(crate) fn provide_payment_preimage_unsafe_legacy<B: Deref, F: Deref, L: Deref>(
&self,
payment_hash: &PaymentHash,
payment_preimage: &PaymentPreimage,
preimages_slice_to_htlc_outputs!(preimages[15..20]), 281474976710654, dummy_key, &logger);
for &(ref preimage, ref hash) in preimages.iter() {
let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&fee_estimator);
- monitor.provide_payment_preimage(hash, preimage, &broadcaster, &bounded_fee_estimator, &logger);
+ monitor.provide_payment_preimage_unsafe_legacy(
+ hash, preimage, &broadcaster, &bounded_fee_estimator, &logger
+ );
}
// Now provide a secret, pruning preimages 10-15
/// Claims an HTLC while we're disconnected from a peer, dropping the [`ChannelMonitorUpdate`]
/// entirely.
///
+ /// This is only used for payments received prior to LDK 0.1.
+ ///
/// The [`ChannelMonitor`] for this channel MUST be updated out-of-band with the preimage
/// provided (i.e. without calling [`crate::chain::Watch::update_channel`]).
///
/// The HTLC claim will end up in the holding cell (because the caller must ensure the peer is
/// disconnected).
- pub fn claim_htlc_while_disconnected_dropping_mon_update<L: Deref>
+ pub fn claim_htlc_while_disconnected_dropping_mon_update_legacy<L: Deref>
(&mut self, htlc_id_arg: u64, payment_preimage_arg: PaymentPreimage, logger: &L)
where L::Target: Logger {
// Assert that we'll add the HTLC claim to the holding cell in `get_update_fulfill_htlc`
let peer_state = &mut *peer_state_lock;
if let Some(ChannelPhase::Funded(channel)) = peer_state.channel_by_id.get_mut(&previous_channel_id) {
let logger = WithChannelContext::from(&channel_manager.logger, &channel.context, Some(payment_hash));
- channel.claim_htlc_while_disconnected_dropping_mon_update(claimable_htlc.prev_hop.htlc_id, payment_preimage, &&logger);
+ channel.claim_htlc_while_disconnected_dropping_mon_update_legacy(
+ claimable_htlc.prev_hop.htlc_id, payment_preimage, &&logger
+ );
}
}
if let Some(previous_hop_monitor) = args.channel_monitors.get(&claimable_htlc.prev_hop.outpoint) {
- previous_hop_monitor.provide_payment_preimage(&payment_hash, &payment_preimage, &channel_manager.tx_broadcaster, &channel_manager.fee_estimator, &channel_manager.logger);
+ // Note that this is unsafe as we no longer require the
+ // `ChannelMonitor`s to be re-persisted prior to this
+ // `ChannelManager` being persisted after we get started running.
+ // If this `ChannelManager` gets persisted first then we crash, we
+ // won't have the `claimable_payments` entry we need to re-enter
+ // this code block, causing us to not re-apply the preimage to this
+ // `ChannelMonitor`.
+ //
+ // We should never be here with modern payment claims, however, as
+ // they should always include the HTLC list. Instead, this is only
+ // for nodes during upgrade, and we explicitly require the old
+ // persistence semantics on upgrade in the release notes.
+ previous_hop_monitor.provide_payment_preimage_unsafe_legacy(
+ &payment_hash, &payment_preimage, &channel_manager.tx_broadcaster,
+ &channel_manager.fee_estimator, &channel_manager.logger
+ );
}
}
let mut pending_events = channel_manager.pending_events.lock().unwrap();
// Now check that if we add the preimage to ChannelMonitor it broadcasts our HTLC-Success..
{
get_monitor!(nodes[2], payment_event.commitment_msg.channel_id)
- .provide_payment_preimage(&our_payment_hash, &our_payment_preimage, &node_cfgs[2].tx_broadcaster, &LowerBoundedFeeEstimator::new(node_cfgs[2].fee_estimator), &node_cfgs[2].logger);
+ .provide_payment_preimage_unsafe_legacy(
+ &our_payment_hash, &our_payment_preimage, &node_cfgs[2].tx_broadcaster,
+ &LowerBoundedFeeEstimator::new(node_cfgs[2].fee_estimator), &node_cfgs[2].logger
+ );
}
mine_transaction(&nodes[2], &commitment_tx);
let mut node_txn = nodes[2].tx_broadcaster.txn_broadcast();
// Cheat by giving A's ChannelMonitor the preimage to the to-be-claimed HTLC so that we have an
// HTLC-claim transaction on the to-be-revoked state.
- get_monitor!(nodes[0], chan_id).provide_payment_preimage(&claimed_payment_hash, &claimed_payment_preimage,
- &node_cfgs[0].tx_broadcaster, &LowerBoundedFeeEstimator::new(node_cfgs[0].fee_estimator), &nodes[0].logger);
+ get_monitor!(nodes[0], chan_id).provide_payment_preimage_unsafe_legacy(
+ &claimed_payment_hash, &claimed_payment_preimage, &node_cfgs[0].tx_broadcaster,
+ &LowerBoundedFeeEstimator::new(node_cfgs[0].fee_estimator), &nodes[0].logger
+ );
// Now get the latest commitment transaction from A and then update the fee to revoke it
let as_revoked_txn = get_local_commitment_txn!(nodes[0], chan_id);
}
if have_htlcs {
- get_monitor!(nodes[0], chan_id).provide_payment_preimage(
+ get_monitor!(nodes[0], chan_id).provide_payment_preimage_unsafe_legacy(
&payment_hash_2.unwrap(), &payment_preimage_2.unwrap(), &node_cfgs[0].tx_broadcaster,
&LowerBoundedFeeEstimator::new(node_cfgs[0].fee_estimator), &nodes[0].logger
);
- get_monitor!(nodes[1], chan_id).provide_payment_preimage(
+ get_monitor!(nodes[1], chan_id).provide_payment_preimage_unsafe_legacy(
&payment_hash_1.unwrap(), &payment_preimage_1.unwrap(), &node_cfgs[1].tx_broadcaster,
&LowerBoundedFeeEstimator::new(node_cfgs[1].fee_estimator), &nodes[1].logger
);
for chan_id in [chan_a.2, chan_b.2].iter() {
let monitor = get_monitor!(nodes[1], chan_id);
for payment in [payment_a, payment_b, payment_c, payment_d].iter() {
- monitor.provide_payment_preimage(
+ monitor.provide_payment_preimage_unsafe_legacy(
&payment.1, &payment.0, &node_cfgs[1].tx_broadcaster,
&LowerBoundedFeeEstimator::new(node_cfgs[1].fee_estimator), &nodes[1].logger
);
check_added_monitors!(nodes[2], 1);
if claim_htlc {
- get_monitor!(nodes[2], chan_id_2).provide_payment_preimage(&payment_hash, &payment_preimage,
- &nodes[2].tx_broadcaster, &LowerBoundedFeeEstimator(nodes[2].fee_estimator), &nodes[2].logger);
+ get_monitor!(nodes[2], chan_id_2).provide_payment_preimage_unsafe_legacy(
+ &payment_hash, &payment_preimage, &nodes[2].tx_broadcaster,
+ &LowerBoundedFeeEstimator(nodes[2].fee_estimator), &nodes[2].logger
+ );
}
assert!(nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap().is_empty());
// Provide the preimage now, such that we only claim from the holder commitment (since it's
// currently confirmed) and not the counterparty's.
- get_monitor!(nodes[1], chan_id).provide_payment_preimage(
+ get_monitor!(nodes[1], chan_id).provide_payment_preimage_unsafe_legacy(
&payment_hash, &payment_preimage, &nodes[1].tx_broadcaster,
&LowerBoundedFeeEstimator(nodes[1].fee_estimator), &nodes[1].logger
);
// Provide the preimage now, such that we only claim from the previous commitment (since it's
// currently confirmed) and not the latest.
- get_monitor!(nodes[1], chan_id).provide_payment_preimage(
+ get_monitor!(nodes[1], chan_id).provide_payment_preimage_unsafe_legacy(
&payment_hash, &payment_preimage, &nodes[1].tx_broadcaster,
&LowerBoundedFeeEstimator(nodes[1].fee_estimator), &nodes[1].logger
);
--- /dev/null
+# Backwards Compatibility
+ * The `ChannelManager` deserialization semantics no longer require that
+ `ChannelMonitor`s be re-persisted after `(BlockHash, ChannelManager)::read`
+ is called prior to normal node operation. This applies to upgraded nodes
+ only *after* a startup with the old semantics completes at least once. IOW,
+ you must deserialize the `ChannelManager` with upgraded LDK, persist the
+ `ChannelMonitor`s then continue to normal startup once, and thereafter you
+ may skip the `ChannelMonitor` persistence step.