Skip to content

Commit ec12549

Browse files
committed
f another test
1 parent c7d375e commit ec12549

File tree

1 file changed

+183
-0
lines changed

1 file changed

+183
-0
lines changed

lightning/src/ln/monitor_tests.rs

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,3 +1172,186 @@ fn test_revoked_counterparty_htlc_tx_balances() {
11721172

11731173
assert_eq!(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances(), Vec::new());
11741174
}
1175+
1176+
#[test]
1177+
fn test_revoked_counterparty_aggregated_claims() {
1178+
// Tests `get_claimable_balances` for revoked counterparty commitment transactions when
1179+
// claiming with an aggregated claim transaction.
1180+
let mut chanmon_cfgs = create_chanmon_cfgs(2);
1181+
// We broadcast a second-to-latest commitment transaction, without providing the revocation
1182+
// secret to the counterparty. However, because we always immediately take the revocation
1183+
// secret from the keys_manager, we would panic at broadcast as we're trying to sign a
1184+
// transaction which, from the point of view of our keys_manager, is revoked.
1185+
chanmon_cfgs[1].keys_manager.disable_revocation_policy_check = true;
1186+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
1187+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
1188+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
1189+
1190+
let (_, _, chan_id, funding_tx) =
1191+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 100_000_000, InitFeatures::known(), InitFeatures::known());
1192+
let funding_outpoint = OutPoint { txid: funding_tx.txid(), index: 0 };
1193+
assert_eq!(funding_outpoint.to_channel_id(), chan_id);
1194+
1195+
// We create two HTLCs, one which we will give A the preimage to to generate an HTLC-Success
1196+
// transaction, and one which we will not, allowing B to claim the HTLC output in an aggregated
1197+
// revocation-claim transaction.
1198+
1199+
let (claimed_payment_preimage, claimed_payment_hash, ..) = route_payment(&nodes[1], &[&nodes[0]], 3_000_000);
1200+
let revoked_payment_hash = route_payment(&nodes[1], &[&nodes[0]], 4_000_000).1;
1201+
1202+
let htlc_cltv_timeout = nodes[1].best_block_info().1 + TEST_FINAL_CLTV + 1; // Note ChannelManager adds one to CLTV timeouts for safety
1203+
1204+
// Cheat by giving A's ChannelMonitor the preimage to the to-be-claimed HTLC so that we have an
1205+
// HTLC-claim transaction on the to-be-revoked state.
1206+
get_monitor!(nodes[0], chan_id).provide_payment_preimage(&claimed_payment_hash, &claimed_payment_preimage, &nodes[0].tx_broadcaster, &node_cfgs[0].fee_estimator, &nodes[0].logger);
1207+
1208+
// Now get the latest commitment transaction from A and then update the fee to revoke it
1209+
let as_revoked_txn = get_local_commitment_txn!(nodes[0], chan_id);
1210+
1211+
assert_eq!(as_revoked_txn.len(), 2);
1212+
check_spends!(as_revoked_txn[0], funding_tx);
1213+
check_spends!(as_revoked_txn[1], as_revoked_txn[0]); // The HTLC-Claim transaction
1214+
1215+
let opt_anchors = get_opt_anchors!(nodes[0], chan_id);
1216+
let chan_feerate = get_feerate!(nodes[0], chan_id) as u64;
1217+
1218+
{
1219+
let mut feerate = chanmon_cfgs[0].fee_estimator.sat_per_kw.lock().unwrap();
1220+
*feerate += 1;
1221+
}
1222+
nodes[0].node.timer_tick_occurred();
1223+
check_added_monitors!(nodes[0], 1);
1224+
1225+
let fee_update = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
1226+
nodes[1].node.handle_update_fee(&nodes[0].node.get_our_node_id(), &fee_update.update_fee.unwrap());
1227+
commitment_signed_dance!(nodes[1], nodes[0], fee_update.commitment_signed, false);
1228+
1229+
nodes[0].node.claim_funds(claimed_payment_preimage);
1230+
expect_payment_claimed!(nodes[0], claimed_payment_hash, 3_000_000);
1231+
check_added_monitors!(nodes[0], 1);
1232+
let _a_htlc_msgs = get_htlc_update_msgs!(&nodes[0], nodes[1].node.get_our_node_id());
1233+
1234+
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
1235+
claimable_amount_satoshis: 100_000 - 4_000 - 3_000,
1236+
}, Balance::MaybeClaimableHTLCAwaitingTimeout {
1237+
claimable_amount_satoshis: 4_000,
1238+
claimable_height: htlc_cltv_timeout,
1239+
}, Balance::MaybeClaimableHTLCAwaitingTimeout {
1240+
claimable_amount_satoshis: 3_000,
1241+
claimable_height: htlc_cltv_timeout,
1242+
}]),
1243+
sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
1244+
1245+
mine_transaction(&nodes[1], &as_revoked_txn[0]);
1246+
check_closed_broadcast!(nodes[1], true);
1247+
check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
1248+
check_added_monitors!(nodes[1], 1);
1249+
1250+
let mut claim_txn: Vec<_> = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().drain(..).filter(|tx| tx.input.iter().any(|inp| inp.previous_output.txid == as_revoked_txn[0].txid())).collect();
1251+
// Currently the revoked commitment outputs are all claimed in one aggregated transaction
1252+
assert_eq!(claim_txn.len(), 1);
1253+
assert_eq!(claim_txn[0].input.len(), 3);
1254+
check_spends!(claim_txn[0], as_revoked_txn[0]);
1255+
1256+
let to_self_maturity = nodes[1].best_block_info().1 + ANTI_REORG_DELAY - 1;
1257+
1258+
assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { // to_remote output to A
1259+
claimable_amount_satoshis: 100_000 - 4_000 - 3_000,
1260+
confirmation_height: to_self_maturity,
1261+
}, Balance::CounterpartyRevokedOutputClaimable { // to_self output to A
1262+
claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1263+
(channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
1264+
}, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1
1265+
claimable_amount_satoshis: 4_000,
1266+
}, Balance::CounterpartyRevokedOutputClaimable { // HTLC 2
1267+
claimable_amount_satoshis: 3_000,
1268+
}]),
1269+
sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
1270+
1271+
// Confirm A's HTLC-Success tranasction which presumably raced B's claim, causing B to create a
1272+
// new claim.
1273+
mine_transaction(&nodes[1], &as_revoked_txn[1]);
1274+
expect_payment_sent!(nodes[1], claimed_payment_preimage);
1275+
let mut claim_txn_2: Vec<_> = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
1276+
claim_txn_2.sort_unstable_by_key(|tx| if tx.input.iter().any(|inp| inp.previous_output.txid == as_revoked_txn[0].txid()) { 0 } else { 1 });
1277+
// Once B sees the HTLC-Success transaction it splits its claim transaction into two, though in
1278+
// theory it could re-aggregate the claims as well.
1279+
assert_eq!(claim_txn_2.len(), 2);
1280+
assert_eq!(claim_txn_2[0].input.len(), 2);
1281+
check_spends!(claim_txn_2[0], as_revoked_txn[0]);
1282+
assert_eq!(claim_txn_2[1].input.len(), 1);
1283+
check_spends!(claim_txn_2[1], as_revoked_txn[1]);
1284+
1285+
assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { // to_remote output to A
1286+
claimable_amount_satoshis: 100_000 - 4_000 - 3_000,
1287+
confirmation_height: to_self_maturity,
1288+
}, Balance::CounterpartyRevokedOutputClaimable { // to_self output to A
1289+
claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1290+
(channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
1291+
}, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1
1292+
claimable_amount_satoshis: 4_000,
1293+
}, Balance::CounterpartyRevokedOutputClaimable { // HTLC 2
1294+
// The amount here is a bit of a misnomer, really its been reduced by the HTLC
1295+
// transaction fee, but the claimable amount is always a bit of an overshoot for HTLCs
1296+
// anyway, so its not a big change.
1297+
claimable_amount_satoshis: 3_000,
1298+
}]),
1299+
sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
1300+
1301+
connect_blocks(&nodes[1], 5);
1302+
test_spendable_output(&nodes[1], &as_revoked_txn[0]);
1303+
1304+
assert_eq!(sorted_vec(vec![Balance::CounterpartyRevokedOutputClaimable { // to_self output to A
1305+
claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1306+
(channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
1307+
}, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1
1308+
claimable_amount_satoshis: 4_000,
1309+
}, Balance::CounterpartyRevokedOutputClaimable { // HTLC 2
1310+
// The amount here is a bit of a misnomer, really its been reduced by the HTLC
1311+
// transaction fee, but the claimable amount is always a bit of an overshoot for HTLCs
1312+
// anyway, so its not a big change.
1313+
claimable_amount_satoshis: 3_000,
1314+
}]),
1315+
sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
1316+
1317+
mine_transaction(&nodes[1], &claim_txn_2[1]);
1318+
let htlc_2_claim_maturity = nodes[1].best_block_info().1 + ANTI_REORG_DELAY - 1;
1319+
1320+
assert_eq!(sorted_vec(vec![Balance::CounterpartyRevokedOutputClaimable { // to_self output to A
1321+
claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1322+
(channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
1323+
}, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1
1324+
claimable_amount_satoshis: 4_000,
1325+
}, Balance::ClaimableAwaitingConfirmations { // HTLC 2
1326+
claimable_amount_satoshis: claim_txn_2[1].output[0].value,
1327+
confirmation_height: htlc_2_claim_maturity,
1328+
}]),
1329+
sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
1330+
1331+
connect_blocks(&nodes[1], 5);
1332+
test_spendable_output(&nodes[1], &claim_txn_2[1]);
1333+
1334+
assert_eq!(sorted_vec(vec![Balance::CounterpartyRevokedOutputClaimable { // to_self output to A
1335+
claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1336+
(channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
1337+
}, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1
1338+
claimable_amount_satoshis: 4_000,
1339+
}]),
1340+
sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
1341+
1342+
mine_transaction(&nodes[1], &claim_txn_2[0]);
1343+
let rest_claim_maturity = nodes[1].best_block_info().1 + ANTI_REORG_DELAY - 1;
1344+
1345+
assert_eq!(vec![Balance::ClaimableAwaitingConfirmations {
1346+
claimable_amount_satoshis: claim_txn_2[0].output[0].value,
1347+
confirmation_height: rest_claim_maturity,
1348+
}],
1349+
nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
1350+
1351+
assert!(nodes[1].node.get_and_clear_pending_events().is_empty()); // We shouldn't fail the payment until we spend the output
1352+
1353+
connect_blocks(&nodes[1], 5);
1354+
expect_payment_failed!(nodes[1], revoked_payment_hash, true);
1355+
test_spendable_output(&nodes[1], &claim_txn_2[0]);
1356+
assert!(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances().is_empty());
1357+
}

0 commit comments

Comments
 (0)