/// The amount available to claim, in satoshis, excluding the on-chain fees which will be
/// required to do so.
amount_satoshis: u64,
+ /// The transaction fee we pay for the closing commitment transaction. This amount is not
+ /// included in the [`Balance::ClaimableOnChannelClose::amount_satoshis`] value.
+ ///
+ /// Note that if this channel is inbound (and thus our counterparty pays the commitment
+ /// 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 channel has been closed, and the given balance is ours but awaiting confirmations until
/// we consider it spendable.
// of block connection between ChannelMonitors and the ChannelManager.
funding_spend_seen: bool,
+ /// True if the commitment transaction fee is paid by us.
+ /// Added in 0.0.124.
+ holder_pays_commitment_tx_fee: Option<bool>,
+
/// Set to `Some` of the confirmed transaction spending the funding input of the channel after
/// reaching `ANTI_REORG_DELAY` confirmations.
funding_spend_confirmed: Option<Txid>,
(17, self.initial_counterparty_commitment_info, option),
(19, self.channel_id, required),
(21, self.balances_empty_height, option),
+ (23, self.holder_pays_commitment_tx_fee, option),
});
Ok(())
pub(crate) fn new(secp_ctx: Secp256k1<secp256k1::All>, keys: Signer, shutdown_script: Option<ScriptBuf>,
on_counterparty_tx_csv: u16, destination_script: &Script, funding_info: (OutPoint, ScriptBuf),
- channel_parameters: &ChannelTransactionParameters,
+ channel_parameters: &ChannelTransactionParameters, holder_pays_commitment_tx_fee: bool,
funding_redeemscript: ScriptBuf, channel_value_satoshis: u64,
commitment_transaction_number_obscure_factor: u64,
initial_holder_commitment_tx: HolderCommitmentTransaction,
onchain_tx_handler,
+ holder_pays_commitment_tx_fee: Some(holder_pays_commitment_tx_fee),
lockdown_from_offchain: false,
holder_tx_signed: false,
funding_spend_seen: false,
}
} else {
let mut claimable_inbound_htlc_value_sat = 0;
+ let mut nondust_htlc_count = 0;
for (htlc, _, source) in us.current_holder_commitment_tx.htlc_outputs.iter() {
- if htlc.transaction_output_index.is_none() { continue; }
+ if htlc.transaction_output_index.is_some() {
+ nondust_htlc_count += 1;
+ } else { continue; }
if htlc.offered {
let outbound_payment = match source {
None => {
}
res.push(Balance::ClaimableOnChannelClose {
amount_satoshis: us.current_holder_commitment_tx.to_self_value_sat + claimable_inbound_htlc_value_sat,
+ transaction_fee_satoshis: if us.holder_pays_commitment_tx_fee.unwrap_or(true) {
+ chan_utils::commit_tx_fee_sat(
+ us.current_holder_commitment_tx.feerate_per_kw, nondust_htlc_count,
+ us.onchain_tx_handler.channel_type_features())
+ } else { 0 },
});
}
let mut initial_counterparty_commitment_info = None;
let mut balances_empty_height = None;
let mut channel_id = None;
+ let mut holder_pays_commitment_tx_fee = None;
read_tlv_fields!(reader, {
(1, funding_spend_confirmed, option),
(3, htlcs_resolved_on_chain, optional_vec),
(17, initial_counterparty_commitment_info, option),
(19, channel_id, option),
(21, balances_empty_height, option),
+ (23, holder_pays_commitment_tx_fee, option),
});
// `HolderForceClosedWithInfo` replaced `HolderForceClosed` in v0.0.122. If we have both
lockdown_from_offchain,
holder_tx_signed,
+ holder_pays_commitment_tx_fee,
funding_spend_seen: funding_spend_seen.unwrap(),
funding_spend_confirmed,
confirmed_commitment_tx_counterparty_output,
let monitor = ChannelMonitor::new(Secp256k1::new(), keys,
Some(ShutdownScript::new_p2wpkh_from_pubkey(shutdown_pubkey).into_inner()), 0, &ScriptBuf::new(),
(OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, ScriptBuf::new()),
- &channel_parameters, ScriptBuf::new(), 46, 0, HolderCommitmentTransaction::dummy(&mut Vec::new()),
+ &channel_parameters, true, ScriptBuf::new(), 46, 0, HolderCommitmentTransaction::dummy(&mut Vec::new()),
best_block, dummy_key, channel_id);
let mut htlcs = preimages_slice_to_htlcs!(preimages[0..10]);
let monitor = ChannelMonitor::new(Secp256k1::new(), keys,
Some(ShutdownScript::new_p2wpkh_from_pubkey(shutdown_pubkey).into_inner()), 0, &ScriptBuf::new(),
(OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, ScriptBuf::new()),
- &channel_parameters, ScriptBuf::new(), 46, 0, HolderCommitmentTransaction::dummy(&mut Vec::new()),
+ &channel_parameters, true, ScriptBuf::new(), 46, 0, HolderCommitmentTransaction::dummy(&mut Vec::new()),
best_block, dummy_key, channel_id);
let chan_id = monitor.inner.lock().unwrap().channel_id();
let channel_monitor = ChannelMonitor::new(self.context.secp_ctx.clone(), monitor_signer,
shutdown_script, self.context.get_holder_selected_contest_delay(),
&self.context.destination_script, (funding_txo, funding_txo_script),
- &self.context.channel_transaction_parameters,
+ &self.context.channel_transaction_parameters, self.context.is_outbound(),
funding_redeemscript.clone(), self.context.channel_value_satoshis,
obscure_factor,
holder_commitment_tx, best_block, self.context.counterparty_node_id, self.context.channel_id());
let channel_monitor = ChannelMonitor::new(self.context.secp_ctx.clone(), monitor_signer,
shutdown_script, self.context.get_holder_selected_contest_delay(),
&self.context.destination_script, (funding_txo, funding_txo_script.clone()),
- &self.context.channel_transaction_parameters,
+ &self.context.channel_transaction_parameters, self.context.is_outbound(),
funding_redeemscript.clone(), self.context.channel_value_satoshis,
obscure_factor,
holder_commitment_tx, best_block, self.context.counterparty_node_id, self.context.channel_id());
let commitment_tx_fee = chan_feerate * chan_utils::commitment_tx_base_weight(&channel_type_features) / 1000;
let anchor_outputs_value = if anchors { channel::ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 };
assert_eq!(vec![Balance::ClaimableOnChannelClose {
- amount_satoshis: 1_000_000 - 1_000 - commitment_tx_fee - anchor_outputs_value
+ amount_satoshis: 1_000_000 - 1_000 - commitment_tx_fee - anchor_outputs_value,
+ transaction_fee_satoshis: commitment_tx_fee,
}],
nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
- assert_eq!(vec![Balance::ClaimableOnChannelClose { amount_satoshis: 1_000, }],
+ assert_eq!(vec![Balance::ClaimableOnChannelClose { amount_satoshis: 1_000, transaction_fee_satoshis: 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();
let anchor_outputs_value = if anchors { 2 * channel::ANCHOR_OUTPUT_VALUE_SATOSHI } else { 0 };
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,
}, 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,
}, 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()));
3 - // The dust HTLC value in satoshis
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,
}, sent_htlc_timeout_balance.clone()];
if !prev_commitment_tx {
a_expected_balances.push(sent_htlc_balance.clone());
sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
assert_eq!(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 1_000 + 3_000 + 4_000,
+ transaction_fee_satoshis: 0,
}],
nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
// Both A and B will have an HTLC that's claimable on timeout and one that's claimable if they
// receive the preimage. These will remain the same through the channel closure and until the
// HTLC output is spent.
-
+ let commitment_tx_fee = chan_feerate *
+ (chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
- amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate *
- (chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+ amount_satoshis: 1_000_000 - 500_000 - 10_000 - commitment_tx_fee,
+ transaction_fee_satoshis: commitment_tx_fee,
}, 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,
}, 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()));
// lists the two on-chain timeout-able HTLCs as claimable balances.
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 100_000 - 5_000 - 4_000 - 3 - 2_000 + 3_000,
+ transaction_fee_satoshis: 0,
}, Balance::MaybeTimeoutClaimableHTLC {
amount_satoshis: 2_000,
claimable_height: missing_htlc_cltv_timeout,
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 100_000 - 4_000 - 3_000,
+ transaction_fee_satoshis: 0,
}, Balance::MaybeTimeoutClaimableHTLC {
amount_satoshis: 4_000,
claimable_height: htlc_cltv_timeout,