Skip to content

Commit b6de281

Browse files
authored
Merge pull request #918 from TheBlueMatt/2021-05-dup-claims
Make payments not duplicatively fail/succeed on reload/reconnect
2 parents 63a245e + 864375e commit b6de281

File tree

4 files changed

+210
-27
lines changed

4 files changed

+210
-27
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ impl chain::Watch<EnforcingSigner> for TestChainMonitor {
147147

148148
struct KeyProvider {
149149
node_id: u8,
150-
rand_bytes_id: atomic::AtomicU8,
150+
rand_bytes_id: atomic::AtomicU32,
151151
revoked_commitments: Mutex<HashMap<[u8;32], Arc<Mutex<u64>>>>,
152152
}
153153
impl KeysInterface for KeyProvider {
@@ -179,7 +179,7 @@ impl KeysInterface for KeyProvider {
179179
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, self.node_id]).unwrap(),
180180
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, self.node_id]).unwrap(),
181181
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, self.node_id]).unwrap(),
182-
[id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, self.node_id],
182+
[id as u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, self.node_id],
183183
channel_value_satoshis,
184184
[0; 32],
185185
);
@@ -189,7 +189,9 @@ impl KeysInterface for KeyProvider {
189189

190190
fn get_secure_random_bytes(&self) -> [u8; 32] {
191191
let id = self.rand_bytes_id.fetch_add(1, atomic::Ordering::Relaxed);
192-
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, id, 11, self.node_id]
192+
let mut res = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, self.node_id];
193+
res[30-4..30].copy_from_slice(&id.to_le_bytes());
194+
res
193195
}
194196

195197
fn read_chan_signer(&self, buffer: &[u8]) -> Result<Self::Signer, DecodeError> {
@@ -334,7 +336,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
334336
let logger: Arc<dyn Logger> = Arc::new(test_logger::TestLogger::new($node_id.to_string(), out.clone()));
335337
let monitor = Arc::new(TestChainMonitor::new(broadcast.clone(), logger.clone(), fee_est.clone(), Arc::new(TestPersister{})));
336338

337-
let keys_manager = Arc::new(KeyProvider { node_id: $node_id, rand_bytes_id: atomic::AtomicU8::new(0), revoked_commitments: Mutex::new(HashMap::new()) });
339+
let keys_manager = Arc::new(KeyProvider { node_id: $node_id, rand_bytes_id: atomic::AtomicU32::new(0), revoked_commitments: Mutex::new(HashMap::new()) });
338340
let mut config = UserConfig::default();
339341
config.channel_options.fee_proportional_millionths = 0;
340342
config.channel_options.announced_channel = true;

lightning/src/ln/channelmanager.rs

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,18 @@ pub struct ChannelManager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref,
442442
/// Locked *after* channel_state.
443443
pending_inbound_payments: Mutex<HashMap<PaymentHash, PendingInboundPayment>>,
444444

445+
/// The session_priv bytes of outbound payments which are pending resolution.
446+
/// The authoritative state of these HTLCs resides either within Channels or ChannelMonitors
447+
/// (if the channel has been force-closed), however we track them here to prevent duplicative
448+
/// PaymentSent/PaymentFailed events. Specifically, in the case of a duplicative
449+
/// update_fulfill_htlc message after a reconnect, we may "claim" a payment twice.
450+
/// Additionally, because ChannelMonitors are often not re-serialized after connecting block(s)
451+
/// which may generate a claim event, we may receive similar duplicate claim/fail MonitorEvents
452+
/// after reloading from disk while replaying blocks against ChannelMonitors.
453+
///
454+
/// Locked *after* channel_state.
455+
pending_outbound_payments: Mutex<HashSet<[u8; 32]>>,
456+
445457
our_network_key: SecretKey,
446458
our_network_pubkey: PublicKey,
447459

@@ -913,6 +925,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
913925
pending_msg_events: Vec::new(),
914926
}),
915927
pending_inbound_payments: Mutex::new(HashMap::new()),
928+
pending_outbound_payments: Mutex::new(HashSet::new()),
916929

917930
our_network_key: keys_manager.get_node_secret(),
918931
our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret()),
@@ -1467,7 +1480,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
14671480
pub(crate) fn send_payment_along_path(&self, path: &Vec<RouteHop>, payment_hash: &PaymentHash, payment_secret: &Option<PaymentSecret>, total_value: u64, cur_height: u32) -> Result<(), APIError> {
14681481
log_trace!(self.logger, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
14691482
let prng_seed = self.keys_manager.get_secure_random_bytes();
1470-
let session_priv = SecretKey::from_slice(&self.keys_manager.get_secure_random_bytes()[..]).expect("RNG is busted");
1483+
let session_priv_bytes = self.keys_manager.get_secure_random_bytes();
1484+
let session_priv = SecretKey::from_slice(&session_priv_bytes[..]).expect("RNG is busted");
14711485

14721486
let onion_keys = onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv)
14731487
.map_err(|_| APIError::RouteError{err: "Pubkey along hop was maliciously selected"})?;
@@ -1478,6 +1492,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
14781492
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash);
14791493

14801494
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
1495+
assert!(self.pending_outbound_payments.lock().unwrap().insert(session_priv_bytes));
14811496

14821497
let err: Result<(), _> = loop {
14831498
let mut channel_lock = self.channel_state.lock().unwrap();
@@ -2228,17 +2243,25 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
22282243
self.fail_htlc_backwards_internal(channel_state,
22292244
htlc_src, &payment_hash, HTLCFailReason::Reason { failure_code, data: onion_failure_data});
22302245
},
2231-
HTLCSource::OutboundRoute { .. } => {
2232-
self.pending_events.lock().unwrap().push(
2233-
events::Event::PaymentFailed {
2234-
payment_hash,
2235-
rejected_by_dest: false,
2246+
HTLCSource::OutboundRoute { session_priv, .. } => {
2247+
if {
2248+
let mut session_priv_bytes = [0; 32];
2249+
session_priv_bytes.copy_from_slice(&session_priv[..]);
2250+
self.pending_outbound_payments.lock().unwrap().remove(&session_priv_bytes)
2251+
} {
2252+
self.pending_events.lock().unwrap().push(
2253+
events::Event::PaymentFailed {
2254+
payment_hash,
2255+
rejected_by_dest: false,
22362256
#[cfg(test)]
2237-
error_code: None,
2257+
error_code: None,
22382258
#[cfg(test)]
2239-
error_data: None,
2240-
}
2241-
)
2259+
error_data: None,
2260+
}
2261+
)
2262+
} else {
2263+
log_trace!(self.logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0));
2264+
}
22422265
},
22432266
};
22442267
}
@@ -2260,7 +2283,15 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
22602283
// from block_connected which may run during initialization prior to the chain_monitor
22612284
// being fully configured. See the docs for `ChannelManagerReadArgs` for more.
22622285
match source {
2263-
HTLCSource::OutboundRoute { ref path, .. } => {
2286+
HTLCSource::OutboundRoute { ref path, session_priv, .. } => {
2287+
if {
2288+
let mut session_priv_bytes = [0; 32];
2289+
session_priv_bytes.copy_from_slice(&session_priv[..]);
2290+
!self.pending_outbound_payments.lock().unwrap().remove(&session_priv_bytes)
2291+
} {
2292+
log_trace!(self.logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0));
2293+
return;
2294+
}
22642295
log_trace!(self.logger, "Failing outbound payment HTLC with payment_hash {}", log_bytes!(payment_hash.0));
22652296
mem::drop(channel_state_lock);
22662297
match &onion_error {
@@ -2489,12 +2520,20 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
24892520

24902521
fn claim_funds_internal(&self, mut channel_state_lock: MutexGuard<ChannelHolder<Signer>>, source: HTLCSource, payment_preimage: PaymentPreimage) {
24912522
match source {
2492-
HTLCSource::OutboundRoute { .. } => {
2523+
HTLCSource::OutboundRoute { session_priv, .. } => {
24932524
mem::drop(channel_state_lock);
2494-
let mut pending_events = self.pending_events.lock().unwrap();
2495-
pending_events.push(events::Event::PaymentSent {
2496-
payment_preimage
2497-
});
2525+
if {
2526+
let mut session_priv_bytes = [0; 32];
2527+
session_priv_bytes.copy_from_slice(&session_priv[..]);
2528+
self.pending_outbound_payments.lock().unwrap().remove(&session_priv_bytes)
2529+
} {
2530+
let mut pending_events = self.pending_events.lock().unwrap();
2531+
pending_events.push(events::Event::PaymentSent {
2532+
payment_preimage
2533+
});
2534+
} else {
2535+
log_trace!(self.logger, "Received duplicative fulfill for HTLC with payment_preimage {}", log_bytes!(payment_preimage.0));
2536+
}
24982537
},
24992538
HTLCSource::PreviousHopData(hop_data) => {
25002539
let prev_outpoint = hop_data.outpoint;
@@ -4470,6 +4509,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
44704509
pending_payment.write(writer)?;
44714510
}
44724511

4512+
let pending_outbound_payments = self.pending_outbound_payments.lock().unwrap();
4513+
(pending_outbound_payments.len() as u64).write(writer)?;
4514+
for session_priv in pending_outbound_payments.iter() {
4515+
session_priv.write(writer)?;
4516+
}
4517+
44734518
Ok(())
44744519
}
44754520
}
@@ -4709,6 +4754,14 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
47094754
}
47104755
}
47114756

4757+
let pending_outbound_payments_count: u64 = Readable::read(reader)?;
4758+
let mut pending_outbound_payments: HashSet<[u8; 32]> = HashSet::with_capacity(cmp::min(pending_outbound_payments_count as usize, MAX_ALLOC_SIZE/32));
4759+
for _ in 0..pending_outbound_payments_count {
4760+
if !pending_outbound_payments.insert(Readable::read(reader)?) {
4761+
return Err(DecodeError::InvalidValue);
4762+
}
4763+
}
4764+
47124765
let mut secp_ctx = Secp256k1::new();
47134766
secp_ctx.seeded_randomize(&args.keys_manager.get_secure_random_bytes());
47144767

@@ -4728,6 +4781,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
47284781
pending_msg_events: Vec::new(),
47294782
}),
47304783
pending_inbound_payments: Mutex::new(pending_inbound_payments),
4784+
pending_outbound_payments: Mutex::new(pending_outbound_payments),
47314785

47324786
our_network_key: args.keys_manager.get_node_secret(),
47334787
our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &args.keys_manager.get_node_secret()),

lightning/src/ln/functional_tests.rs

Lines changed: 134 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3496,6 +3496,34 @@ fn test_force_close_fail_back() {
34963496
check_spends!(node_txn[0], tx);
34973497
}
34983498

3499+
#[test]
3500+
fn test_dup_events_on_peer_disconnect() {
3501+
// Test that if we receive a duplicative update_fulfill_htlc message after a reconnect we do
3502+
// not generate a corresponding duplicative PaymentSent event. This did not use to be the case
3503+
// as we used to generate the event immediately upon receipt of the payment preimage in the
3504+
// update_fulfill_htlc message.
3505+
3506+
let chanmon_cfgs = create_chanmon_cfgs(2);
3507+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
3508+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
3509+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
3510+
create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
3511+
3512+
let payment_preimage = route_payment(&nodes[0], &[&nodes[1]], 1000000).0;
3513+
3514+
assert!(nodes[1].node.claim_funds(payment_preimage));
3515+
check_added_monitors!(nodes[1], 1);
3516+
let claim_msgs = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
3517+
nodes[0].node.handle_update_fulfill_htlc(&nodes[1].node.get_our_node_id(), &claim_msgs.update_fulfill_htlcs[0]);
3518+
expect_payment_sent!(nodes[0], payment_preimage);
3519+
3520+
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
3521+
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
3522+
3523+
reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (1, 0), (0, 0), (0, 0), (false, false));
3524+
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
3525+
}
3526+
34993527
#[test]
35003528
fn test_simple_peer_disconnect() {
35013529
// Test that we can reconnect when there are no lost messages
@@ -3718,8 +3746,7 @@ fn do_test_drop_messages_peer_disconnect(messages_delivered: u8) {
37183746
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
37193747
if messages_delivered < 2 {
37203748
reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (1, 0), (0, 0), (0, 0), (false, false));
3721-
//TODO: Deduplicate PaymentSent events, then enable this if:
3722-
//if messages_delivered < 1 {
3749+
if messages_delivered < 1 {
37233750
let events_4 = nodes[0].node.get_and_clear_pending_events();
37243751
assert_eq!(events_4.len(), 1);
37253752
match events_4[0] {
@@ -3728,7 +3755,9 @@ fn do_test_drop_messages_peer_disconnect(messages_delivered: u8) {
37283755
},
37293756
_ => panic!("Unexpected event"),
37303757
}
3731-
//}
3758+
} else {
3759+
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
3760+
}
37323761
} else if messages_delivered == 2 {
37333762
// nodes[0] still wants its RAA + commitment_signed
37343763
reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, -1), (0, 0), (0, 0), (0, 0), (false, true));
@@ -4302,6 +4331,108 @@ fn test_no_txn_manager_serialize_deserialize() {
43024331
send_payment(&nodes[0], &[&nodes[1]], 1000000);
43034332
}
43044333

4334+
#[test]
4335+
fn test_dup_htlc_onchain_fails_on_reload() {
4336+
// When a Channel is closed, any outbound HTLCs which were relayed through it are simply
4337+
// dropped when the Channel is. From there, the ChannelManager relies on the ChannelMonitor
4338+
// having a copy of the relevant fail-/claim-back data and processes the HTLC fail/claim when
4339+
// the ChannelMonitor tells it to.
4340+
//
4341+
// If, due to an on-chain event, an HTLC is failed/claimed, and then we serialize the
4342+
// ChannelManager, we generally expect there not to be a duplicate HTLC fail/claim (eg via a
4343+
// PaymentFailed event appearing). However, because we may not serialize the relevant
4344+
// ChannelMonitor at the same time, this isn't strictly guaranteed. In order to provide this
4345+
// consistency, the ChannelManager explicitly tracks pending-onchain-resolution outbound HTLCs
4346+
// and de-duplicates ChannelMonitor events.
4347+
//
4348+
// This tests that explicit tracking behavior.
4349+
let chanmon_cfgs = create_chanmon_cfgs(2);
4350+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
4351+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
4352+
let persister: test_utils::TestPersister;
4353+
let new_chain_monitor: test_utils::TestChainMonitor;
4354+
let nodes_0_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
4355+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
4356+
4357+
create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
4358+
4359+
// Route a payment, but force-close the channel before the HTLC fulfill message arrives at
4360+
// nodes[0].
4361+
let (payment_preimage, _, _) = route_payment(&nodes[0], &[&nodes[1]], 10000000);
4362+
nodes[0].node.force_close_channel(&nodes[0].node.list_channels()[0].channel_id).unwrap();
4363+
check_closed_broadcast!(nodes[0], true);
4364+
check_added_monitors!(nodes[0], 1);
4365+
4366+
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
4367+
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
4368+
4369+
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
4370+
assert_eq!(node_txn.len(), 2);
4371+
4372+
assert!(nodes[1].node.claim_funds(payment_preimage));
4373+
check_added_monitors!(nodes[1], 1);
4374+
4375+
let mut header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
4376+
connect_block(&nodes[1], &Block { header, txdata: vec![node_txn[0].clone(), node_txn[1].clone()]});
4377+
check_closed_broadcast!(nodes[1], true);
4378+
check_added_monitors!(nodes[1], 1);
4379+
let claim_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
4380+
4381+
connect_block(&nodes[0], &Block { header, txdata: node_txn});
4382+
4383+
// Serialize out the ChannelMonitor before connecting the on-chain claim transactions. This is
4384+
// fairly normal behavior as ChannelMonitor(s) are often not re-serialized when on-chain events
4385+
// happen, unlike ChannelManager which tends to be re-serialized after any relevant event(s).
4386+
let mut chan_0_monitor_serialized = test_utils::TestVecWriter(Vec::new());
4387+
nodes[0].chain_monitor.chain_monitor.monitors.read().unwrap().iter().next().unwrap().1.write(&mut chan_0_monitor_serialized).unwrap();
4388+
4389+
header.prev_blockhash = header.block_hash();
4390+
let claim_block = Block { header, txdata: claim_txn};
4391+
connect_block(&nodes[0], &claim_block);
4392+
expect_payment_sent!(nodes[0], payment_preimage);
4393+
4394+
// ChannelManagers generally get re-serialized after any relevant event(s). Since we just
4395+
// connected a highly-relevant block, it likely gets serialized out now.
4396+
let mut chan_manager_serialized = test_utils::TestVecWriter(Vec::new());
4397+
nodes[0].node.write(&mut chan_manager_serialized).unwrap();
4398+
4399+
// Now reload nodes[0]...
4400+
persister = test_utils::TestPersister::new();
4401+
let keys_manager = &chanmon_cfgs[0].keys_manager;
4402+
new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), nodes[0].logger, node_cfgs[0].fee_estimator, &persister, keys_manager);
4403+
nodes[0].chain_monitor = &new_chain_monitor;
4404+
let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..];
4405+
let (_, mut chan_0_monitor) = <(BlockHash, ChannelMonitor<EnforcingSigner>)>::read(
4406+
&mut chan_0_monitor_read, keys_manager).unwrap();
4407+
assert!(chan_0_monitor_read.is_empty());
4408+
4409+
let (_, nodes_0_deserialized_tmp) = {
4410+
let mut channel_monitors = HashMap::new();
4411+
channel_monitors.insert(chan_0_monitor.get_funding_txo().0, &mut chan_0_monitor);
4412+
<(BlockHash, ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>)>
4413+
::read(&mut std::io::Cursor::new(&chan_manager_serialized.0[..]), ChannelManagerReadArgs {
4414+
default_config: Default::default(),
4415+
keys_manager,
4416+
fee_estimator: node_cfgs[0].fee_estimator,
4417+
chain_monitor: nodes[0].chain_monitor,
4418+
tx_broadcaster: nodes[0].tx_broadcaster.clone(),
4419+
logger: nodes[0].logger,
4420+
channel_monitors,
4421+
}).unwrap()
4422+
};
4423+
nodes_0_deserialized = nodes_0_deserialized_tmp;
4424+
4425+
assert!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor).is_ok());
4426+
check_added_monitors!(nodes[0], 1);
4427+
nodes[0].node = &nodes_0_deserialized;
4428+
4429+
// Note that if we re-connect the block which exposed nodes[0] to the payment preimage (but
4430+
// which the current ChannelMonitor has not seen), the ChannelManager's de-duplication of
4431+
// payment events should kick in, leaving us with no pending events here.
4432+
nodes[0].chain_monitor.chain_monitor.block_connected(&claim_block, nodes[0].blocks.borrow().len() as u32 - 1);
4433+
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
4434+
}
4435+
43054436
#[test]
43064437
fn test_manager_serialize_deserialize_events() {
43074438
// This test makes sure the events field in ChannelManager survives de/serialization

lightning/src/util/events.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,6 @@ pub enum Event {
9595
},
9696
/// Indicates an outbound payment we made succeeded (ie it made it all the way to its target
9797
/// and we got back the payment preimage for it).
98-
/// Note that duplicative PaymentSent Events may be generated - it is your responsibility to
99-
/// deduplicate them by payment_preimage (which MUST be unique)!
10098
PaymentSent {
10199
/// The preimage to the hash given to ChannelManager::send_payment.
102100
/// Note that this serves as a payment receipt, if you wish to have such a thing, you must
@@ -105,8 +103,6 @@ pub enum Event {
105103
},
106104
/// Indicates an outbound payment we made failed. Probably some intermediary node dropped
107105
/// something. You may wish to retry with a different route.
108-
/// Note that duplicative PaymentFailed Events may be generated - it is your responsibility to
109-
/// deduplicate them by payment_hash (which MUST be unique)!
110106
PaymentFailed {
111107
/// The hash which was given to ChannelManager::send_payment.
112108
payment_hash: PaymentHash,

0 commit comments

Comments
 (0)