Include rounded msat balances in Balance::ClaimableOnChannelClose

If we're gonna push users towards using `Balance` to determine
their current balances, we really need to provide more information,
including msat balances.

Here we add rounded-out msat balances to the pre-close balance
information
This commit is contained in:
Matt Corallo 2023-11-14 22:19:19 +00:00 committed by Duncan Dean
parent a39357e08a
commit f5a614eb0b
No known key found for this signature in database
2 changed files with 108 additions and 16 deletions

View file

@ -629,6 +629,32 @@ pub enum Balance {
/// transaction fee) this value will be zero. For [`ChannelMonitor`]s created prior to LDK
/// 0.0.124, the channel is always treated as outbound (and thus this value is never zero).
transaction_fee_satoshis: u64,
/// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound
/// from us and are related to a payment which was sent by us. This is the sum of the
/// millisatoshis part of all HTLCs which are otherwise represented by
/// [`Balance::MaybeTimeoutClaimableHTLC`] with their
/// [`Balance::MaybeTimeoutClaimableHTLC::outbound_payment`] flag set, as well as any dust
/// HTLCs which would otherwise be represented the same.
outbound_payment_htlc_rounded_msat: u64,
/// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound
/// from us and are related to a forwarded HTLC. This is the sum of the millisatoshis part
/// of all HTLCs which are otherwise represented by [`Balance::MaybeTimeoutClaimableHTLC`]
/// with their [`Balance::MaybeTimeoutClaimableHTLC::outbound_payment`] flag *not* set, as
/// well as any dust HTLCs which would otherwise be represented the same.
outbound_forwarded_htlc_rounded_msat: u64,
/// The amount of millisatoshis which has been burned to fees from HTLCs which are inbound
/// to us and for which we know the preimage. This is the sum of the millisatoshis part of
/// all HTLCs which would be represented by [`Balance::ContentiousClaimable`] on channel
/// close, but whose current value is included in
/// [`Balance::ClaimableOnChannelClose::amount_satoshis`], as well as any dust HTLCs which
/// would otherwise be represented the same.
inbound_claiming_htlc_rounded_msat: u64,
/// The amount of millisatoshis which has been burned to fees from HTLCs which are inbound
/// to us and for which we do not know the preimage. This is the sum of the millisatoshis
/// part of all HTLCs which would be represented by [`Balance::MaybePreimageClaimableHTLC`]
/// on channel close, as well as any dust HTLCs which would otherwise be represented the
/// same.
inbound_htlc_rounded_msat: u64,
},
/// The channel has been closed, and the given balance is ours but awaiting confirmations until
/// we consider it spendable.
@ -2320,10 +2346,17 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
} else {
let mut claimable_inbound_htlc_value_sat = 0;
let mut nondust_htlc_count = 0;
let mut outbound_payment_htlc_rounded_msat = 0;
let mut outbound_forwarded_htlc_rounded_msat = 0;
let mut inbound_claiming_htlc_rounded_msat = 0;
let mut inbound_htlc_rounded_msat = 0;
for (htlc, _, source) in us.current_holder_commitment_tx.htlc_outputs.iter() {
if htlc.transaction_output_index.is_some() {
nondust_htlc_count += 1;
} else { continue; }
}
let rounded_value_msat = if htlc.transaction_output_index.is_none() {
htlc.amount_msat
} else { htlc.amount_msat % 1000 };
if htlc.offered {
let outbound_payment = match source {
None => {
@ -2333,22 +2366,35 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
Some(HTLCSource::PreviousHopData(_)) => false,
Some(HTLCSource::OutboundRoute { .. }) => true,
};
res.push(Balance::MaybeTimeoutClaimableHTLC {
amount_satoshis: htlc.amount_msat / 1000,
claimable_height: htlc.cltv_expiry,
payment_hash: htlc.payment_hash,
outbound_payment,
});
if outbound_payment {
outbound_payment_htlc_rounded_msat += rounded_value_msat;
} else {
outbound_forwarded_htlc_rounded_msat += rounded_value_msat;
}
if htlc.transaction_output_index.is_some() {
res.push(Balance::MaybeTimeoutClaimableHTLC {
amount_satoshis: htlc.amount_msat / 1000,
claimable_height: htlc.cltv_expiry,
payment_hash: htlc.payment_hash,
outbound_payment,
});
}
} else if us.payment_preimages.get(&htlc.payment_hash).is_some() {
claimable_inbound_htlc_value_sat += htlc.amount_msat / 1000;
inbound_claiming_htlc_rounded_msat += rounded_value_msat;
if htlc.transaction_output_index.is_some() {
claimable_inbound_htlc_value_sat += htlc.amount_msat / 1000;
}
} else {
// As long as the HTLC is still in our latest commitment state, treat
// it as potentially claimable, even if it has long-since expired.
res.push(Balance::MaybePreimageClaimableHTLC {
amount_satoshis: htlc.amount_msat / 1000,
expiry_height: htlc.cltv_expiry,
payment_hash: htlc.payment_hash,
});
inbound_htlc_rounded_msat += rounded_value_msat;
if htlc.transaction_output_index.is_some() {
// As long as the HTLC is still in our latest commitment state, treat
// it as potentially claimable, even if it has long-since expired.
res.push(Balance::MaybePreimageClaimableHTLC {
amount_satoshis: htlc.amount_msat / 1000,
expiry_height: htlc.cltv_expiry,
payment_hash: htlc.payment_hash,
});
}
}
}
res.push(Balance::ClaimableOnChannelClose {
@ -2358,6 +2404,10 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
us.current_holder_commitment_tx.feerate_per_kw, nondust_htlc_count,
us.onchain_tx_handler.channel_type_features())
} else { 0 },
outbound_payment_htlc_rounded_msat,
outbound_forwarded_htlc_rounded_msat,
inbound_claiming_htlc_rounded_msat,
inbound_htlc_rounded_msat,
});
}

View file

@ -242,9 +242,19 @@ fn do_chanmon_claim_value_coop_close(anchors: bool) {
assert_eq!(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 1_000_000 - 1_000 - commitment_tx_fee - anchor_outputs_value,
transaction_fee_satoshis: commitment_tx_fee,
outbound_payment_htlc_rounded_msat: 0,
outbound_forwarded_htlc_rounded_msat: 0,
inbound_claiming_htlc_rounded_msat: 0,
inbound_htlc_rounded_msat: 0,
}],
nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
assert_eq!(vec![Balance::ClaimableOnChannelClose { amount_satoshis: 1_000, transaction_fee_satoshis: 0 }],
assert_eq!(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 1_000, transaction_fee_satoshis: 0,
outbound_payment_htlc_rounded_msat: 0,
outbound_forwarded_htlc_rounded_msat: 0,
inbound_claiming_htlc_rounded_msat: 0,
inbound_htlc_rounded_msat: 0,
}],
nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
nodes[0].node.close_channel(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
@ -443,11 +453,19 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) {
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 1_000_000 - 3_000 - 4_000 - 1_000 - 3 - commitment_tx_fee - anchor_outputs_value,
transaction_fee_satoshis: commitment_tx_fee,
outbound_payment_htlc_rounded_msat: 3000,
outbound_forwarded_htlc_rounded_msat: 0,
inbound_claiming_htlc_rounded_msat: 0,
inbound_htlc_rounded_msat: 0,
}, sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]),
sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 1_000,
transaction_fee_satoshis: 0,
outbound_payment_htlc_rounded_msat: 0,
outbound_forwarded_htlc_rounded_msat: 0,
inbound_claiming_htlc_rounded_msat: 0,
inbound_htlc_rounded_msat: 3000,
}, received_htlc_balance.clone(), received_htlc_timeout_balance.clone()]),
sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
@ -495,6 +513,10 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) {
commitment_tx_fee - // The commitment transaction fee with two HTLC outputs
anchor_outputs_value, // The anchor outputs value in satoshis
transaction_fee_satoshis: commitment_tx_fee,
outbound_payment_htlc_rounded_msat: 3000,
outbound_forwarded_htlc_rounded_msat: 0,
inbound_claiming_htlc_rounded_msat: 0,
inbound_htlc_rounded_msat: 0,
}, sent_htlc_timeout_balance.clone()];
if !prev_commitment_tx {
a_expected_balances.push(sent_htlc_balance.clone());
@ -504,6 +526,10 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) {
assert_eq!(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 1_000 + 3_000 + 4_000,
transaction_fee_satoshis: 0,
outbound_payment_htlc_rounded_msat: 0,
outbound_forwarded_htlc_rounded_msat: 0,
inbound_claiming_htlc_rounded_msat: 3000,
inbound_htlc_rounded_msat: 0,
}],
nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
@ -987,12 +1013,20 @@ fn test_no_preimage_inbound_htlc_balances() {
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 1_000_000 - 500_000 - 10_000 - commitment_tx_fee,
transaction_fee_satoshis: commitment_tx_fee,
outbound_payment_htlc_rounded_msat: 0,
outbound_forwarded_htlc_rounded_msat: 0,
inbound_claiming_htlc_rounded_msat: 0,
inbound_htlc_rounded_msat: 0,
}, a_received_htlc_balance.clone(), a_sent_htlc_balance.clone()]),
sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 500_000 - 20_000,
transaction_fee_satoshis: 0,
outbound_payment_htlc_rounded_msat: 0,
outbound_forwarded_htlc_rounded_msat: 0,
inbound_claiming_htlc_rounded_msat: 0,
inbound_htlc_rounded_msat: 0,
}, b_received_htlc_balance.clone(), b_sent_htlc_balance.clone()]),
sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
@ -1272,6 +1306,10 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 100_000 - 5_000 - 4_000 - 3 - 2_000 + 3_000,
transaction_fee_satoshis: 0,
outbound_payment_htlc_rounded_msat: 3000,
outbound_forwarded_htlc_rounded_msat: 0,
inbound_claiming_htlc_rounded_msat: 0,
inbound_htlc_rounded_msat: 0,
}, Balance::MaybeTimeoutClaimableHTLC {
amount_satoshis: 2_000,
claimable_height: missing_htlc_cltv_timeout,
@ -1826,6 +1864,10 @@ fn do_test_revoked_counterparty_aggregated_claims(anchors: bool) {
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 100_000 - 4_000 - 3_000,
transaction_fee_satoshis: 0,
outbound_payment_htlc_rounded_msat: 0,
outbound_forwarded_htlc_rounded_msat: 0,
inbound_claiming_htlc_rounded_msat: 0,
inbound_htlc_rounded_msat: 0,
}, Balance::MaybeTimeoutClaimableHTLC {
amount_satoshis: 4_000,
claimable_height: htlc_cltv_timeout,