Skip to content

Commit 45c0a0f

Browse files
committed
Test async get per commitment point for revoke_and_ack
Note: this does not test the CS -> RAA resend ordering, because this requires handling async get_per_commitment_point for channel reestablishment, which will be addressed in a follow up PR.
1 parent 614da40 commit 45c0a0f

File tree

2 files changed

+157
-24
lines changed

2 files changed

+157
-24
lines changed

lightning/src/ln/async_signer_tests.rs

+153-22
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ fn test_async_commitment_signature_for_funding_signed() {
127127

128128
#[test]
129129
fn test_async_commitment_signature_for_commitment_signed() {
130+
do_test_async_commitment_signature_for_commitment_signed_revoke_and_ack(true);
131+
do_test_async_commitment_signature_for_commitment_signed_revoke_and_ack(false);
132+
}
133+
134+
fn do_test_async_commitment_signature_for_commitment_signed_revoke_and_ack(enable_sign_counterparty_commit_first: bool) {
130135
let chanmon_cfgs = create_chanmon_cfgs(2);
131136
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
132137
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
@@ -154,23 +159,33 @@ fn test_async_commitment_signature_for_commitment_signed() {
154159

155160
// Mark dst's signer as unavailable and handle src's commitment_signed: while dst won't yet have a
156161
// `commitment_signed` of its own to offer, it should publish a `revoke_and_ack`.
162+
dst.disable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::GetPerCommitmentPoint);
157163
dst.disable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
158164
dst.node.handle_commitment_signed(&src.node.get_our_node_id(), &payment_event.commitment_msg);
159165
check_added_monitors(dst, 1);
160166

161-
get_event_msg!(dst, MessageSendEvent::SendRevokeAndACK, src.node.get_our_node_id());
162-
163-
// Mark dst's signer as available and retry: we now expect to see dst's `commitment_signed`.
164-
dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
165-
dst.node.signer_unblocked(Some((src.node.get_our_node_id(), chan_id)));
166-
167-
let events = dst.node.get_and_clear_pending_msg_events();
168-
assert_eq!(events.len(), 1, "expected one message, got {}", events.len());
169-
if let MessageSendEvent::UpdateHTLCs { ref node_id, .. } = events[0] {
170-
assert_eq!(node_id, &src.node.get_our_node_id());
167+
if enable_sign_counterparty_commit_first {
168+
// Unblock CS -> no messages should be sent, since we must send RAA first.
169+
dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
170+
dst.node.signer_unblocked(Some((src.node.get_our_node_id(), chan_id)));
171+
let events = dst.node.get_and_clear_pending_msg_events();
172+
assert!(events.is_empty(), "expected no message, got {}", events.len());
173+
174+
// Unblock revoke_and_ack -> we should send both RAA + CS.
175+
dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::GetPerCommitmentPoint);
176+
dst.node.signer_unblocked(Some((src.node.get_our_node_id(), chan_id)));
177+
get_revoke_commit_msgs(&dst, &src.node.get_our_node_id());
171178
} else {
172-
panic!("expected UpdateHTLCs message, not {:?}", events[0]);
173-
};
179+
// Unblock revoke_and_ack -> we should send just RAA.
180+
dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::GetPerCommitmentPoint);
181+
dst.node.signer_unblocked(Some((src.node.get_our_node_id(), chan_id)));
182+
get_event_msg!(dst, MessageSendEvent::SendRevokeAndACK, src.node.get_our_node_id());
183+
184+
// Unblock commitment signed -> we should send CS.
185+
dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
186+
dst.node.signer_unblocked(Some((src.node.get_our_node_id(), chan_id)));
187+
get_htlc_update_msgs(dst, &src.node.get_our_node_id());
188+
}
174189
}
175190

176191
#[test]
@@ -272,9 +287,125 @@ fn test_async_commitment_signature_for_funding_signed_0conf() {
272287
assert_eq!(nodes[1].node.list_usable_channels().len(), 1);
273288
}
274289

290+
#[derive(PartialEq)]
291+
enum UnblockSignerAcrossDisconnectCase {
292+
AtEnd,
293+
BeforeMonitorRestored,
294+
BeforeReestablish,
295+
}
296+
297+
#[test]
298+
fn test_async_raa_peer_disconnect() {
299+
do_test_async_raa_peer_disconnect(UnblockSignerAcrossDisconnectCase::AtEnd);
300+
do_test_async_raa_peer_disconnect(UnblockSignerAcrossDisconnectCase::BeforeMonitorRestored);
301+
do_test_async_raa_peer_disconnect(UnblockSignerAcrossDisconnectCase::BeforeReestablish);
302+
}
303+
304+
fn do_test_async_raa_peer_disconnect(test_case: UnblockSignerAcrossDisconnectCase) {
305+
let chanmon_cfgs = create_chanmon_cfgs(2);
306+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
307+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
308+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
309+
let (_, _, chan_id, _) = create_announced_chan_between_nodes(&nodes, 0, 1);
310+
311+
// Send a payment.
312+
let src = &nodes[0];
313+
let dst = &nodes[1];
314+
let (route, our_payment_hash, _our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(src, dst, 8000000);
315+
src.node.send_payment_with_route(&route, our_payment_hash,
316+
RecipientOnionFields::secret_only(our_payment_secret), PaymentId(our_payment_hash.0)).unwrap();
317+
check_added_monitors!(src, 1);
318+
319+
// Pass the payment along the route.
320+
let payment_event = {
321+
let mut events = src.node.get_and_clear_pending_msg_events();
322+
assert_eq!(events.len(), 1);
323+
SendEvent::from_event(events.remove(0))
324+
};
325+
assert_eq!(payment_event.node_id, dst.node.get_our_node_id());
326+
assert_eq!(payment_event.msgs.len(), 1);
327+
328+
dst.node.handle_update_add_htlc(&src.node.get_our_node_id(), &payment_event.msgs[0]);
329+
330+
if test_case == UnblockSignerAcrossDisconnectCase::BeforeMonitorRestored {
331+
// Fail to persist the monitor update when handling the commitment_signed.
332+
chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
333+
}
334+
335+
// Mark dst's signer as unavailable and handle src's commitment_signed: while dst won't yet have a
336+
// `commitment_signed` of its own to offer, it should publish a `revoke_and_ack`.
337+
dst.disable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::GetPerCommitmentPoint);
338+
dst.node.handle_commitment_signed(&src.node.get_our_node_id(), &payment_event.commitment_msg);
339+
check_added_monitors(dst, 1);
340+
341+
let events = dst.node.get_and_clear_pending_msg_events();
342+
assert!(events.is_empty(), "expected no message, got {}", events.len());
343+
344+
// Now disconnect and reconnect the peers.
345+
src.node.peer_disconnected(&dst.node.get_our_node_id());
346+
dst.node.peer_disconnected(&src.node.get_our_node_id());
347+
348+
// do reestablish stuff
349+
src.node.peer_connected(&dst.node.get_our_node_id(), &msgs::Init {
350+
features: dst.node.init_features(), networks: None, remote_network_address: None
351+
}, true).unwrap();
352+
let reestablish_1 = get_chan_reestablish_msgs!(src, dst);
353+
assert_eq!(reestablish_1.len(), 1);
354+
dst.node.peer_connected(&src.node.get_our_node_id(), &msgs::Init {
355+
features: src.node.init_features(), networks: None, remote_network_address: None
356+
}, false).unwrap();
357+
let reestablish_2 = get_chan_reestablish_msgs!(dst, src);
358+
assert_eq!(reestablish_2.len(), 1);
359+
360+
if test_case == UnblockSignerAcrossDisconnectCase::BeforeReestablish {
361+
// Reenable the signer before the reestablish.
362+
dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::GetPerCommitmentPoint);
363+
}
364+
365+
dst.node.handle_channel_reestablish(&src.node.get_our_node_id(), &reestablish_1[0]);
366+
367+
if test_case == UnblockSignerAcrossDisconnectCase::BeforeMonitorRestored {
368+
dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::GetPerCommitmentPoint);
369+
chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
370+
let (outpoint, latest_update, _) = dst.chain_monitor.latest_monitor_update_id.lock().unwrap().get(&chan_id).unwrap().clone();
371+
dst.chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update);
372+
check_added_monitors!(dst, 0);
373+
}
374+
375+
// Expect the RAA
376+
let (_, revoke_and_ack, commitment_signed, resend_order) = handle_chan_reestablish_msgs!(dst, src);
377+
if test_case == UnblockSignerAcrossDisconnectCase::AtEnd {
378+
assert!(revoke_and_ack.is_none());
379+
assert!(commitment_signed.is_none());
380+
} else {
381+
assert!(revoke_and_ack.is_some());
382+
assert!(commitment_signed.is_some());
383+
assert!(resend_order == RAACommitmentOrder::RevokeAndACKFirst);
384+
}
385+
386+
// Mark dst's signer as available and retry: we now expect to see dst's RAA + CS.
387+
dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::GetPerCommitmentPoint);
388+
dst.node.signer_unblocked(Some((src.node.get_our_node_id(), chan_id)));
389+
390+
if test_case == UnblockSignerAcrossDisconnectCase::AtEnd {
391+
let (_, revoke_and_ack, commitment_signed, resend_order) = handle_chan_reestablish_msgs!(dst, src);
392+
assert!(revoke_and_ack.is_some());
393+
assert!(commitment_signed.is_some());
394+
assert!(resend_order == RAACommitmentOrder::RevokeAndACKFirst);
395+
} else {
396+
// Make sure we don't double send the RAA.
397+
let (_, revoke_and_ack, commitment_signed, _) = handle_chan_reestablish_msgs!(dst, src);
398+
assert!(revoke_and_ack.is_none());
399+
assert!(commitment_signed.is_none());
400+
}
401+
}
402+
403+
275404
#[test]
276405
fn test_async_commitment_signature_peer_disconnect() {
277-
do_test_async_commitment_signature_peer_disconnect(0);
406+
// This tests that if our signer is blocked and gets unblocked
407+
// after a peer disconnect + channel reestablish, we'll send the right messages.
408+
do_test_async_commitment_signature_peer_disconnect(UnblockSignerAcrossDisconnectCase::AtEnd);
278409
}
279410

280411
#[test]
@@ -283,18 +414,18 @@ fn test_async_commitment_signature_peer_disconnect_signer_restored_before_monito
283414
// and needed to send a CS, that if our signer becomes available before the monitor
284415
// update completes, then we don't send duplicate messages upon calling `signer_unblocked`
285416
// after the monitor update completes.
286-
do_test_async_commitment_signature_peer_disconnect(1);
417+
do_test_async_commitment_signature_peer_disconnect(UnblockSignerAcrossDisconnectCase::BeforeMonitorRestored);
287418
}
288419

289420
#[test]
290421
fn test_async_commitment_signature_peer_disconnect_signer_restored_before_reestablish() {
291422
// This tests that if we tried to send a commitment_signed, but our signer was blocked,
292423
// if we disconnect, reconnect, the signer becomes available, then handle channel_reestablish,
293424
// that we don't send duplicate messages upon calling `signer_unblocked`.
294-
do_test_async_commitment_signature_peer_disconnect(2);
425+
do_test_async_commitment_signature_peer_disconnect(UnblockSignerAcrossDisconnectCase::BeforeReestablish);
295426
}
296427

297-
fn do_test_async_commitment_signature_peer_disconnect(test_case: u8) {
428+
fn do_test_async_commitment_signature_peer_disconnect(test_case: UnblockSignerAcrossDisconnectCase) {
298429
let chanmon_cfgs = create_chanmon_cfgs(2);
299430
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
300431
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
@@ -320,7 +451,7 @@ fn do_test_async_commitment_signature_peer_disconnect(test_case: u8) {
320451

321452
dst.node.handle_update_add_htlc(&src.node.get_our_node_id(), &payment_event.msgs[0]);
322453

323-
if test_case == 1 {
454+
if test_case == UnblockSignerAcrossDisconnectCase::BeforeMonitorRestored {
324455
// Fail to persist the monitor update when handling the commitment_signed.
325456
chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
326457
}
@@ -331,7 +462,7 @@ fn do_test_async_commitment_signature_peer_disconnect(test_case: u8) {
331462
dst.node.handle_commitment_signed(&src.node.get_our_node_id(), &payment_event.commitment_msg);
332463
check_added_monitors(dst, 1);
333464

334-
if test_case != 1 {
465+
if test_case != UnblockSignerAcrossDisconnectCase::BeforeMonitorRestored {
335466
get_event_msg!(dst, MessageSendEvent::SendRevokeAndACK, src.node.get_our_node_id());
336467
}
337468

@@ -351,14 +482,14 @@ fn do_test_async_commitment_signature_peer_disconnect(test_case: u8) {
351482
let reestablish_2 = get_chan_reestablish_msgs!(dst, src);
352483
assert_eq!(reestablish_2.len(), 1);
353484

354-
if test_case == 2 {
485+
if test_case == UnblockSignerAcrossDisconnectCase::BeforeReestablish {
355486
// Reenable the signer before the reestablish.
356487
dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
357488
}
358489

359490
dst.node.handle_channel_reestablish(&src.node.get_our_node_id(), &reestablish_1[0]);
360491

361-
if test_case == 1 {
492+
if test_case == UnblockSignerAcrossDisconnectCase::BeforeMonitorRestored {
362493
dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
363494
chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
364495
let (outpoint, latest_update, _) = dst.chain_monitor.latest_monitor_update_id.lock().unwrap().get(&chan_id).unwrap().clone();
@@ -369,7 +500,7 @@ fn do_test_async_commitment_signature_peer_disconnect(test_case: u8) {
369500
// Expect the RAA
370501
let (_, revoke_and_ack, commitment_signed, _) = handle_chan_reestablish_msgs!(dst, src);
371502
assert!(revoke_and_ack.is_some());
372-
if test_case == 0 {
503+
if test_case == UnblockSignerAcrossDisconnectCase::AtEnd {
373504
assert!(commitment_signed.is_none());
374505
} else {
375506
assert!(commitment_signed.is_some());
@@ -379,7 +510,7 @@ fn do_test_async_commitment_signature_peer_disconnect(test_case: u8) {
379510
dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
380511
dst.node.signer_unblocked(Some((src.node.get_our_node_id(), chan_id)));
381512

382-
if test_case == 0 {
513+
if test_case == UnblockSignerAcrossDisconnectCase::AtEnd {
383514
let (_, _, commitment_signed, _) = handle_chan_reestablish_msgs!(dst, src);
384515
assert!(commitment_signed.is_some());
385516
} else {

lightning/src/util/test_channel_signer.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,10 @@ impl TestChannelSigner {
165165

166166
impl ChannelSigner for TestChannelSigner {
167167
fn get_per_commitment_point(&self, idx: u64, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<PublicKey, ()> {
168-
// TODO: implement a mask in EnforcementState to let you test signatures being
169-
// unavailable
168+
#[cfg(test)]
169+
if !self.is_signer_available(SignerOp::GetPerCommitmentPoint) {
170+
return Err(());
171+
}
170172
self.inner.get_per_commitment_point(idx, secp_ctx)
171173
}
172174

0 commit comments

Comments
 (0)