Skip to content

Commit 10114e6

Browse files
committed
f use all input value (minus fees) when contributing
1 parent 26b8b03 commit 10114e6

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
@@ -6697,7 +6697,7 @@ where
66976697
/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
66986698
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
66996699
pub fn accept_inbound_channel(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, user_channel_id: u128) -> Result<(), APIError> {
6700-
self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, false, user_channel_id, 0, vec![])
6700+
self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, false, user_channel_id, vec![])
67016701
}
67026702

67036703
/// Accepts a request to open a channel after a [`events::Event::OpenChannelRequest`], treating
@@ -6719,7 +6719,7 @@ where
67196719
/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
67206720
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
67216721
pub fn accept_inbound_channel_from_trusted_peer_0conf(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, user_channel_id: u128) -> Result<(), APIError> {
6722-
self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, true, user_channel_id, 0, vec![])
6722+
self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, true, user_channel_id, vec![])
67236723
}
67246724

67256725
/// Accepts a request to open a dual-funded channel with a contribution provided by us after an
@@ -6733,8 +6733,10 @@ where
67336733
/// [`Event::ChannelClosed::user_channel_id`] to allow tracking of which events correspond
67346734
/// with which `accept_inbound_channel_*` call.
67356735
///
6736-
/// `funding_satoshis` is the amount we are contributing to the channel.
6737-
/// Raises [`APIError::APIMisuseError`] when `funding_satoshis` > 2**24.
6736+
/// The `funding_inputs` parameter provides the `txin`s along with their previous transactions that
6737+
/// will be used to contribute towards our portion of the channel value. Our contribution will be
6738+
/// calculated as the total value of these inputs minus the fees we need to cover for the
6739+
/// interactive funding transaction.
67386740
///
67396741
/// Note that this method will return an error and reject the channel, if it requires support
67406742
/// for zero confirmations.
@@ -6747,11 +6749,11 @@ where
67476749
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
67486750
#[cfg(any(dual_funding, splicing))]
67496751
pub fn accept_inbound_channel_with_contribution(&self, temporary_channel_id: &ChannelId,
6750-
counterparty_node_id: &PublicKey, user_channel_id: u128, funding_satoshis: u64,
6751-
funding_inputs: Vec<(TxIn, Transaction)>) -> Result<(), APIError> {
6752+
counterparty_node_id: &PublicKey, user_channel_id: u128, funding_inputs: Vec<(TxIn, Transaction)>,
6753+
) -> Result<(), APIError> {
67526754
let funding_inputs = Self::length_limit_holder_input_prev_txs(funding_inputs)?;
67536755
self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, false, user_channel_id,
6754-
funding_satoshis, funding_inputs)
6756+
funding_inputs)
67556757
}
67566758

67576759
#[cfg(any(dual_funding, splicing))]
@@ -6768,7 +6770,7 @@ where
67686770
// TODO(dual_funding): Remove param _-prefix once #[cfg(dual_funding)] is dropped.
67696771
fn do_accept_inbound_channel(
67706772
&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, accept_0conf: bool,
6771-
user_channel_id: u128, _funding_satoshis: u64, _funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
6773+
user_channel_id: u128, _funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
67726774
) -> Result<(), APIError> {
67736775
let logger = WithContext::from(&self.logger, Some(*counterparty_node_id), Some(*temporary_channel_id), None);
67746776
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
@@ -6808,12 +6810,11 @@ where
68086810
OpenChannelMessage::V2(open_channel_msg) => {
68096811
let channel_res = InboundV2Channel::new(&self.fee_estimator, &self.entropy_source, &self.signer_provider,
68106812
counterparty_node_id.clone(), &self.channel_type_features(), &peer_state.latest_features,
6811-
&open_channel_msg, _funding_satoshis, _funding_inputs, user_channel_id, &self.default_configuration, best_block_height,
6813+
&open_channel_msg, _funding_inputs, user_channel_id, &self.default_configuration, best_block_height,
68126814
&self.logger);
68136815
match channel_res {
68146816
Ok(mut channel) => {
6815-
let tx_msg_opt_res = channel.begin_interactive_funding_tx_construction(&self.signer_provider,
6816-
&self.entropy_source);
6817+
let tx_msg_opt_res = channel.begin_interactive_funding_tx_construction(&self.entropy_source);
68176818
match tx_msg_opt_res {
68186819
Ok(tx_msg_opt) => {
68196820
if let Some(tx_msg) = tx_msg_opt {
@@ -7177,7 +7178,7 @@ where
71777178
let user_channel_id = u128::from_be_bytes(random_bytes);
71787179
let mut channel = match InboundV2Channel::new(&self.fee_estimator, &self.entropy_source,
71797180
&self.signer_provider, counterparty_node_id.clone(), &self.channel_type_features(),
7180-
&peer_state.latest_features, &msg, 0, vec![], user_channel_id, &self.default_configuration,
7181+
&peer_state.latest_features, &msg, vec![], user_channel_id, &self.default_configuration,
71817182
best_block_height, &self.logger)
71827183
{
71837184
Err(e) => {
@@ -7197,7 +7198,7 @@ where
71977198
let outbound_scid_alias = self.create_and_insert_outbound_scid_alias();
71987199
channel.context.set_outbound_scid_alias(outbound_scid_alias);
71997200

7200-
channel.begin_interactive_funding_tx_construction(&self.signer_provider, &self.entropy_source)
7201+
channel.begin_interactive_funding_tx_construction(&self.entropy_source)
72017202
.map_err(|_| MsgHandleErrInternal::send_err_msg_no_close(
72027203
"Failed to start interactive transaction construction".to_owned(), msg.common_fields.temporary_channel_id))?;
72037204

0 commit comments

Comments
 (0)