Skip to content

Commit d6c540d

Browse files
committed
Test claimable balance is expected for forwarded/outbound payments
1 parent 728192e commit d6c540d

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

lightning/src/ln/monitor_tests.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2145,6 +2145,100 @@ fn test_revoked_counterparty_aggregated_claims() {
21452145
do_test_revoked_counterparty_aggregated_claims(true);
21462146
}
21472147

2148+
fn do_test_claimable_balance_correct_while_payment_pending(outbound_payment: bool, anchors: bool) {
2149+
// Previously when a user fetched their balances via `get_claimable_balances` after forwarding a
2150+
// payment, but before it cleared, and summed up their balance using `Balance::claimable_amount_satoshis`
2151+
// neither the value of preimage claimable HTLC nor the timeout claimable HTLC would be included.
2152+
// This was incorrect as exactly one of these outcomes is true. This has been fixed by including the
2153+
// timeout claimable HTLC value in the balance as this excludes the routing fees and is the more
2154+
// prudent approach.
2155+
//
2156+
// In the case of the holder sending a payment, the above value will not be included while the payment
2157+
// is pending.
2158+
//
2159+
// This tests that we get the correct balance in either of the cases above.
2160+
let mut chanmon_cfgs = create_chanmon_cfgs(3);
2161+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
2162+
let mut user_config = test_default_channel_config();
2163+
if anchors {
2164+
user_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
2165+
user_config.manually_accept_inbound_channels = true;
2166+
}
2167+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[Some(user_config), Some(user_config), Some(user_config)]);
2168+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
2169+
2170+
let coinbase_tx = Transaction {
2171+
version: Version::TWO,
2172+
lock_time: LockTime::ZERO,
2173+
input: vec![TxIn { ..Default::default() }],
2174+
output: vec![
2175+
TxOut {
2176+
value: Amount::ONE_BTC,
2177+
script_pubkey: nodes[0].wallet_source.get_change_script().unwrap(),
2178+
},
2179+
TxOut {
2180+
value: Amount::ONE_BTC,
2181+
script_pubkey: nodes[1].wallet_source.get_change_script().unwrap(),
2182+
},
2183+
],
2184+
};
2185+
if anchors {
2186+
nodes[0].wallet_source.add_utxo(bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 0 }, coinbase_tx.output[0].value);
2187+
nodes[1].wallet_source.add_utxo(bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 1 }, coinbase_tx.output[1].value);
2188+
}
2189+
2190+
// Create a channel from A -> B
2191+
let (_, _, chan_ab_id, funding_tx_ab) =
2192+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000 /* channel_value (sat) */, 0 /* push_msat */);
2193+
let funding_outpoint_ab = OutPoint { txid: funding_tx_ab.txid(), index: 0 };
2194+
assert_eq!(ChannelId::v1_from_funding_outpoint(funding_outpoint_ab), chan_ab_id);
2195+
// Create a channel from B -> C
2196+
let (_, _, chan_bc_id, funding_tx_bc) =
2197+
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000 /* channel_value (sat) */, 0 /* push_msat */);
2198+
let funding_outpoint_bc = OutPoint { txid: funding_tx_bc.txid(), index: 0 };
2199+
assert_eq!(ChannelId::v1_from_funding_outpoint(funding_outpoint_bc), chan_bc_id);
2200+
2201+
let (chan_feerate, channel_type_features) = if outbound_payment {
2202+
let chan_ab_feerate = get_feerate!(nodes[0], nodes[1], chan_ab_id);
2203+
let channel_type_features_ab = get_channel_type_features!(nodes[0], nodes[1], chan_ab_id);
2204+
(chan_ab_feerate, channel_type_features_ab)
2205+
} else {
2206+
let chan_bc_feerate = get_feerate!(nodes[1], nodes[2], chan_bc_id);
2207+
let channel_type_features_bc = get_channel_type_features!(nodes[1], nodes[2], chan_bc_id);
2208+
(chan_bc_feerate, channel_type_features_bc)
2209+
};
2210+
let commitment_tx_fee = chan_feerate as u64 *
2211+
(chan_utils::commitment_tx_base_weight(&channel_type_features) + chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
2212+
2213+
// This HTLC will be forwarded by B from A -> C
2214+
let _ = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 4_000_000);
2215+
let anchor_outputs_value = if anchors { 2 * channel::ANCHOR_OUTPUT_VALUE_SATOSHI } else { 0 };
2216+
2217+
if outbound_payment {
2218+
assert_eq!(
2219+
1_000_000 - commitment_tx_fee - anchor_outputs_value - 4_001 /* Note HTLC timeout amount of 4001 sats is excluded for outbound payment */,
2220+
nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint_ab).unwrap().get_claimable_balances().iter().map(
2221+
|x| x.claimable_amount_satoshis()).sum());
2222+
} else {
2223+
assert_eq!(
2224+
0u64,
2225+
nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint_ab).unwrap().get_claimable_balances().iter().map(
2226+
|x| x.claimable_amount_satoshis()).sum());
2227+
assert_eq!(
2228+
1_000_000 - commitment_tx_fee - anchor_outputs_value /* Note HTLC timeout amount of 4000 sats is included */,
2229+
nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint_bc).unwrap().get_claimable_balances().iter().map(
2230+
|x| x.claimable_amount_satoshis()).sum());
2231+
}
2232+
}
2233+
2234+
#[test]
2235+
fn test_claimable_balance_correct_while_payment_pending() {
2236+
do_test_claimable_balance_correct_while_payment_pending(false, false);
2237+
do_test_claimable_balance_correct_while_payment_pending(false, true);
2238+
do_test_claimable_balance_correct_while_payment_pending(true, false);
2239+
do_test_claimable_balance_correct_while_payment_pending(true, true);
2240+
}
2241+
21482242
fn do_test_restored_packages_retry(check_old_monitor_retries_after_upgrade: bool) {
21492243
// Tests that we'll retry packages that were previously timelocked after we've restored them.
21502244
let chanmon_cfgs = create_chanmon_cfgs(2);

0 commit comments

Comments
 (0)