Skip to content

Commit f47d9be

Browse files
committed
f use all input value (minus fees) when contributing
1 parent 92d943e commit f47d9be

File tree

2 files changed

+50
-79
lines changed

2 files changed

+50
-79
lines changed

lightning/src/ln/channel.rs

Lines changed: 36 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,29 +1461,10 @@ pub(super) trait InteractivelyFunded<SP: Deref> where SP::Target: SignerProvider
14611461
fn is_initiator(&self) -> bool;
14621462

14631463
fn begin_interactive_funding_tx_construction<ES: Deref>(
1464-
&mut self, signer_provider: &SP, entropy_source: &ES,
1464+
&mut self, entropy_source: &ES,
14651465
) -> Result<Option<InteractiveTxMessageSend>, APIError>
14661466
where ES::Target: EntropySource
14671467
{
1468-
let mut funding_inputs_prev_outputs: Vec<TxOut> = Vec::with_capacity(self.dual_funding_context_mut().our_funding_inputs.len());
1469-
// Check that vouts exist for each TxIn in provided transactions.
1470-
for (idx, input) in self.dual_funding_context_mut().our_funding_inputs.iter().enumerate() {
1471-
if let Some(output) = input.1.as_transaction().output.get(input.0.previous_output.vout as usize) {
1472-
funding_inputs_prev_outputs.push(output.clone());
1473-
} else {
1474-
return Err(APIError::APIMisuseError {
1475-
err: format!("Transaction with txid {} does not have an output with vout of {} corresponding to TxIn at funding_inputs[{}]",
1476-
input.1.as_transaction().txid(), input.0.previous_output.vout, idx) });
1477-
}
1478-
}
1479-
let total_input_satoshis: u64 = self.dual_funding_context_mut().our_funding_inputs.iter().map(
1480-
|input| input.1.as_transaction().output[input.0.previous_output.vout as usize].value.to_sat()).sum();
1481-
if total_input_satoshis < self.dual_funding_context_mut().our_funding_satoshis {
1482-
return Err(APIError::APIMisuseError {
1483-
err: format!("Total value of funding inputs must be at least funding amount. It was {} sats",
1484-
total_input_satoshis) });
1485-
}
1486-
14871468
let mut funding_outputs = Vec::new();
14881469
if self.is_initiator() {
14891470
funding_outputs.push(TxOut {
@@ -1492,11 +1473,6 @@ pub(super) trait InteractivelyFunded<SP: Deref> where SP::Target: SignerProvider
14921473
});
14931474
}
14941475

1495-
maybe_add_funding_change_output(signer_provider, self.is_initiator(), self.dual_funding_context_mut().our_funding_satoshis,
1496-
&funding_inputs_prev_outputs, &mut funding_outputs, self.dual_funding_context_mut().funding_feerate_sat_per_1000_weight,
1497-
total_input_satoshis, self.context().holder_dust_limit_satoshis, self.context().channel_keys_id).map_err(
1498-
|_| APIError::APIMisuseError { err: "Could not create change output".to_string() })?;
1499-
15001476
let (tx_constructor, msg) = InteractiveTxConstructor::new(
15011477
entropy_source, self.context().channel_id(),
15021478
self.dual_funding_context_mut().funding_feerate_sat_per_1000_weight, self.is_initiator(),
@@ -3670,53 +3646,39 @@ pub(crate) fn per_outbound_htlc_counterparty_commit_tx_fee_msat(feerate_per_kw:
36703646
}
36713647

36723648
#[cfg(any(dual_funding, splicing))]
3673-
pub(super) fn maybe_add_funding_change_output<SP: Deref>(
3674-
signer_provider: &SP, is_initiator: bool, our_funding_satoshis: u64,
3675-
funding_inputs_prev_outputs: &Vec<TxOut>, funding_outputs: &mut Vec<TxOut>,
3676-
funding_feerate_sat_per_1000_weight: u32, total_input_satoshis: u64,
3677-
holder_dust_limit_satoshis: u64, channel_keys_id: [u8; 32],
3678-
) -> Result<Option<TxOut>, ChannelError> where
3679-
SP::Target: SignerProvider,
3680-
{
3681-
// Add the total estimated weight of our contributed inputs...
3682-
let mut our_contributed_weight = funding_inputs_prev_outputs.iter().fold(0u64, |weight, prev_output| {
3683-
weight.saturating_add(estimate_input_weight(prev_output).to_wu())
3684-
}).saturating_add(
3685-
// ... with the total weight of our contributed outputs.
3686-
funding_outputs.iter().fold(0u64, |weight, txout| {
3687-
weight.saturating_add(get_output_weight(&txout.script_pubkey).to_wu())
3688-
})
3689-
);
3649+
pub(super) fn calculate_our_funding_satoshis(
3650+
is_initiator: bool, funding_inputs: &[(TxIn, TransactionU16LenLimited)],
3651+
funding_outputs: &[TxOut], funding_feerate_sat_per_1000_weight: u32,
3652+
holder_dust_limit_satoshis: u64,
3653+
) -> Result<u64, APIError> {
3654+
let mut total_input_satoshis = 0u64;
3655+
let mut our_contributed_weight = 0u64;
3656+
3657+
for (idx, input) in funding_inputs.iter().enumerate() {
3658+
if let Some(output) = input.1.as_transaction().output.get(input.0.previous_output.vout as usize) {
3659+
total_input_satoshis = total_input_satoshis.saturating_add(output.value.to_sat());
3660+
our_contributed_weight = our_contributed_weight.saturating_add(estimate_input_weight(output).to_wu());
3661+
} else {
3662+
return Err(APIError::APIMisuseError {
3663+
err: format!("Transaction with txid {} does not have an output with vout of {} corresponding to TxIn at funding_inputs[{}]",
3664+
input.1.as_transaction().txid(), input.0.previous_output.vout, idx) });
3665+
}
3666+
}
3667+
our_contributed_weight = our_contributed_weight.saturating_add(funding_outputs.iter().fold(0u64, |weight, txout| {
3668+
weight.saturating_add(get_output_weight(&txout.script_pubkey).to_wu())
3669+
}));
36903670

36913671
// If we are the initiator, we must pay for weight of all common fields in the funding transaction.
36923672
if is_initiator {
3693-
our_contributed_weight += TX_COMMON_FIELDS_WEIGHT;
3673+
our_contributed_weight = our_contributed_weight.saturating_add(TX_COMMON_FIELDS_WEIGHT);
36943674
}
36953675

3696-
let remaining_value = total_input_satoshis
3697-
.saturating_sub(our_funding_satoshis)
3676+
let funding_satoshis = total_input_satoshis
36983677
.saturating_sub(fee_for_weight(funding_feerate_sat_per_1000_weight, our_contributed_weight));
3699-
3700-
if remaining_value < holder_dust_limit_satoshis {
3701-
Ok(None)
3678+
if funding_satoshis < holder_dust_limit_satoshis {
3679+
Ok(0)
37023680
} else {
3703-
let change_script = signer_provider.get_destination_script(channel_keys_id).map_err(
3704-
|_| ChannelError::Close(
3705-
(
3706-
"Failed to get change script as new destination script".to_owned(),
3707-
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
3708-
))
3709-
)?;
3710-
let mut change_output = TxOut {
3711-
value: Amount::from_sat(remaining_value),
3712-
script_pubkey: change_script,
3713-
};
3714-
let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
3715-
3716-
let change_output_fee = fee_for_weight(funding_feerate_sat_per_1000_weight, change_output_weight);
3717-
change_output.value = Amount::from_sat(remaining_value.saturating_sub(change_output_fee));
3718-
funding_outputs.push(change_output.clone());
3719-
Ok(Some(change_output))
3681+
Ok(funding_satoshis)
37203682
}
37213683
}
37223684

@@ -8423,14 +8385,22 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
84238385
pub fn new<ES: Deref, F: Deref, L: Deref>(
84248386
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
84258387
counterparty_node_id: PublicKey, our_supported_features: &ChannelTypeFeatures,
8426-
their_features: &InitFeatures, msg: &msgs::OpenChannelV2, funding_satoshis: u64,
8388+
their_features: &InitFeatures, msg: &msgs::OpenChannelV2,
84278389
funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>, user_id: u128, config: &UserConfig,
84288390
current_chain_height: u32, logger: &L,
84298391
) -> Result<InboundV2Channel<SP>, ChannelError>
84308392
where ES::Target: EntropySource,
84318393
F::Target: FeeEstimator,
84328394
L::Target: Logger,
84338395
{
8396+
let funding_satoshis = calculate_our_funding_satoshis(
8397+
false, &funding_inputs, &[], msg.funding_feerate_sat_per_1000_weight,
8398+
msg.common_fields.dust_limit_satoshis
8399+
).map_err(|_| ChannelError::Close(
8400+
(
8401+
"Failed to accept channel".to_string(),
8402+
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
8403+
)))?;
84348404
let channel_value_satoshis = funding_satoshis.saturating_add(msg.common_fields.funding_satoshis);
84358405
let counterparty_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
84368406
channel_value_satoshis, msg.common_fields.dust_limit_satoshis);

lightning/src/ln/channelmanager.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6668,7 +6668,7 @@ where
66686668
/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
66696669
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
66706670
pub fn accept_inbound_channel(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, user_channel_id: u128) -> Result<(), APIError> {
6671-
self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, false, user_channel_id, 0, vec![])
6671+
self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, false, user_channel_id, vec![])
66726672
}
66736673

66746674
/// Accepts a request to open a channel after a [`events::Event::OpenChannelRequest`], treating
@@ -6690,7 +6690,7 @@ where
66906690
/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
66916691
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
66926692
pub fn accept_inbound_channel_from_trusted_peer_0conf(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, user_channel_id: u128) -> Result<(), APIError> {
6693-
self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, true, user_channel_id, 0, vec![])
6693+
self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, true, user_channel_id, vec![])
66946694
}
66956695

66966696
/// Accepts a request to open a dual-funded channel with a contribution provided by us after an
@@ -6704,8 +6704,10 @@ where
67046704
/// [`Event::ChannelClosed::user_channel_id`] to allow tracking of which events correspond
67056705
/// with which `accept_inbound_channel_*` call.
67066706
///
6707-
/// `funding_satoshis` is the amount we are contributing to the channel.
6708-
/// Raises [`APIError::APIMisuseError`] when `funding_satoshis` > 2**24.
6707+
/// The `funding_inputs` parameter provides the `txin`s along with their previous transactions that
6708+
/// will be used to contribute towards our portion of the channel value. Our contribution will be
6709+
/// calculated as the total value of these inputs minus the fees we need to cover for the
6710+
/// interactive funding transaction.
67096711
///
67106712
/// Note that this method will return an error and reject the channel, if it requires support
67116713
/// for zero confirmations.
@@ -6718,11 +6720,11 @@ where
67186720
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
67196721
#[cfg(any(dual_funding, splicing))]
67206722
pub fn accept_inbound_channel_with_contribution(&self, temporary_channel_id: &ChannelId,
6721-
counterparty_node_id: &PublicKey, user_channel_id: u128, funding_satoshis: u64,
6722-
funding_inputs: Vec<(TxIn, Transaction)>) -> Result<(), APIError> {
6723+
counterparty_node_id: &PublicKey, user_channel_id: u128, funding_inputs: Vec<(TxIn, Transaction)>,
6724+
) -> Result<(), APIError> {
67236725
let funding_inputs = Self::length_limit_holder_input_prev_txs(funding_inputs)?;
67246726
self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, false, user_channel_id,
6725-
funding_satoshis, funding_inputs)
6727+
funding_inputs)
67266728
}
67276729

67286730
#[cfg(any(dual_funding, splicing))]
@@ -6739,7 +6741,7 @@ where
67396741
// TODO(dual_funding): Remove param _-prefix once #[cfg(dual_funding)] is dropped.
67406742
fn do_accept_inbound_channel(
67416743
&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, accept_0conf: bool,
6742-
user_channel_id: u128, _funding_satoshis: u64, _funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
6744+
user_channel_id: u128, _funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
67436745
) -> Result<(), APIError> {
67446746
let logger = WithContext::from(&self.logger, Some(*counterparty_node_id), Some(*temporary_channel_id), None);
67456747
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
@@ -6779,12 +6781,11 @@ where
67796781
OpenChannelMessage::V2(open_channel_msg) => {
67806782
let channel_res = InboundV2Channel::new(&self.fee_estimator, &self.entropy_source, &self.signer_provider,
67816783
counterparty_node_id.clone(), &self.channel_type_features(), &peer_state.latest_features,
6782-
&open_channel_msg, _funding_satoshis, _funding_inputs, user_channel_id, &self.default_configuration, best_block_height,
6784+
&open_channel_msg, _funding_inputs, user_channel_id, &self.default_configuration, best_block_height,
67836785
&self.logger);
67846786
match channel_res {
67856787
Ok(mut channel) => {
6786-
let tx_msg_opt_res = channel.begin_interactive_funding_tx_construction(&self.signer_provider,
6787-
&self.entropy_source);
6788+
let tx_msg_opt_res = channel.begin_interactive_funding_tx_construction(&self.entropy_source);
67886789
match tx_msg_opt_res {
67896790
Ok(tx_msg_opt) => {
67906791
if let Some(tx_msg) = tx_msg_opt {
@@ -7148,7 +7149,7 @@ where
71487149
let user_channel_id = u128::from_be_bytes(random_bytes);
71497150
let mut channel = match InboundV2Channel::new(&self.fee_estimator, &self.entropy_source,
71507151
&self.signer_provider, counterparty_node_id.clone(), &self.channel_type_features(),
7151-
&peer_state.latest_features, &msg, 0, vec![], user_channel_id, &self.default_configuration,
7152+
&peer_state.latest_features, &msg, vec![], user_channel_id, &self.default_configuration,
71527153
best_block_height, &self.logger)
71537154
{
71547155
Err(e) => {
@@ -7168,7 +7169,7 @@ where
71687169
let outbound_scid_alias = self.create_and_insert_outbound_scid_alias();
71697170
channel.context.set_outbound_scid_alias(outbound_scid_alias);
71707171

7171-
channel.begin_interactive_funding_tx_construction(&self.signer_provider, &self.entropy_source)
7172+
channel.begin_interactive_funding_tx_construction(&self.entropy_source)
71727173
.map_err(|_| MsgHandleErrInternal::send_err_msg_no_close(
71737174
"Failed to start interactive transaction construction".to_owned(), msg.common_fields.temporary_channel_id))?;
71747175

0 commit comments

Comments
 (0)