Skip to content

[Splicing] Clone for ChannelContext #3332

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 185 additions & 22 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ use crate::prelude::*;
use core::{cmp,mem,fmt};
use core::ops::Deref;
#[cfg(any(test, fuzzing, debug_assertions))]
use crate::sync::Mutex;
use crate::sync::{Arc, Mutex};
use crate::sign::type_resolver::ChannelSignerType;

use super::channel_keys::{DelayedPaymentBasepoint, HtlcBasepoint, RevocationBasepoint};
Expand Down Expand Up @@ -112,6 +112,7 @@ enum FeeUpdateState {
Outbound,
}

#[derive(Clone)]
enum InboundHTLCRemovalReason {
FailRelay(msgs::OnionErrorPacket),
FailMalformed(([u8; 32], u16)),
Expand Down Expand Up @@ -146,6 +147,7 @@ impl_writeable_tlv_based_enum!(InboundHTLCResolution,
},
);

#[derive(Clone)]
enum InboundHTLCState {
/// Offered by remote, to be included in next local commitment tx. I.e., the remote sent an
/// update_add_htlc message for this HTLC.
Expand Down Expand Up @@ -220,6 +222,7 @@ impl From<&InboundHTLCState> for Option<InboundHTLCStateDetails> {
}
}

#[derive(Clone)]
struct InboundHTLCOutput {
htlc_id: u64,
amount_msat: u64,
Expand All @@ -228,7 +231,8 @@ struct InboundHTLCOutput {
state: InboundHTLCState,
}

#[cfg_attr(test, derive(Clone, Debug, PartialEq))]
#[derive(Clone)]
#[cfg_attr(test, derive(Debug, PartialEq))]
enum OutboundHTLCState {
/// Added by us and included in a commitment_signed (if we were AwaitingRemoteRevoke when we
/// created it we would have put it in the holding cell instead). When they next revoke_and_ack
Expand Down Expand Up @@ -310,7 +314,8 @@ impl<'a> Into<Option<&'a HTLCFailReason>> for &'a OutboundHTLCOutcome {
}
}

#[cfg_attr(test, derive(Clone, Debug, PartialEq))]
#[derive(Clone)]
#[cfg_attr(test, derive(Debug, PartialEq))]
struct OutboundHTLCOutput {
htlc_id: u64,
amount_msat: u64,
Expand All @@ -323,7 +328,8 @@ struct OutboundHTLCOutput {
}

/// See AwaitingRemoteRevoke ChannelState for more info
#[cfg_attr(test, derive(Clone, Debug, PartialEq))]
#[derive(Clone)]
#[cfg_attr(test, derive(Debug, PartialEq))]
enum HTLCUpdateAwaitingACK {
AddHTLC { // TODO: Time out if we're getting close to cltv_expiry
// always outbound
Expand Down Expand Up @@ -801,7 +807,7 @@ pub(super) enum ChannelUpdateStatus {
}

/// We track when we sent an `AnnouncementSignatures` to our peer in a few states, described here.
#[derive(PartialEq)]
#[derive(Clone, PartialEq)]
pub enum AnnouncementSigsState {
/// We have not sent our peer an `AnnouncementSignatures` yet, or our peer disconnected since
/// we sent the last `AnnouncementSignatures`.
Expand Down Expand Up @@ -1126,6 +1132,7 @@ pub(crate) const UNFUNDED_CHANNEL_AGE_LIMIT_TICKS: usize = 60;
/// Number of blocks needed for an output from a coinbase transaction to be spendable.
pub(crate) const COINBASE_MATURITY: u32 = 100;

#[derive(Clone)]
struct PendingChannelMonitorUpdate {
update: ChannelMonitorUpdate,
}
Expand Down Expand Up @@ -1666,10 +1673,10 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {

#[cfg(debug_assertions)]
/// Max to_local and to_remote outputs in a locally-generated commitment transaction
holder_max_commitment_tx_output: Mutex<(u64, u64)>,
holder_max_commitment_tx_output: Arc<Mutex<(u64, u64)>>,
#[cfg(debug_assertions)]
/// Max to_local and to_remote outputs in a remote-generated commitment transaction
counterparty_max_commitment_tx_output: Mutex<(u64, u64)>,
counterparty_max_commitment_tx_output: Arc<Mutex<(u64, u64)>>,

// (fee_sats, skip_remote_output, fee_range, holder_sig)
last_sent_closing_fee: Option<(u64, bool, ClosingSignedFeeRange, Option<Signature>)>,
Expand Down Expand Up @@ -1781,9 +1788,9 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
// be, by comparing the cached values to the fee of the tranaction generated by
// `build_commitment_transaction`.
#[cfg(any(test, fuzzing))]
next_local_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
next_local_commitment_tx_fee_info_cached: Arc<Mutex<Option<CommitmentTxInfoCached>>>,
#[cfg(any(test, fuzzing))]
next_remote_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
next_remote_commitment_tx_fee_info_cached: Arc<Mutex<Option<CommitmentTxInfoCached>>>,

/// lnd has a long-standing bug where, upon reconnection, if the channel is not yet confirmed
/// they will not send a channel_reestablish until the channel locks in. Then, they will send a
Expand Down Expand Up @@ -2454,9 +2461,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {


#[cfg(debug_assertions)]
holder_max_commitment_tx_output: Mutex::new((value_to_self_msat, (channel_value_satoshis * 1000 - msg_push_msat).saturating_sub(value_to_self_msat))),
holder_max_commitment_tx_output: Arc::new(Mutex::new((value_to_self_msat, (channel_value_satoshis * 1000 - msg_push_msat).saturating_sub(value_to_self_msat)))),
#[cfg(debug_assertions)]
counterparty_max_commitment_tx_output: Mutex::new((value_to_self_msat, (channel_value_satoshis * 1000 - msg_push_msat).saturating_sub(value_to_self_msat))),
counterparty_max_commitment_tx_output: Arc::new(Mutex::new((value_to_self_msat, (channel_value_satoshis * 1000 - msg_push_msat).saturating_sub(value_to_self_msat)))),

last_sent_closing_fee: None,
last_received_closing_sig: None,
Expand Down Expand Up @@ -2514,9 +2521,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
announcement_sigs: None,

#[cfg(any(test, fuzzing))]
next_local_commitment_tx_fee_info_cached: Mutex::new(None),
next_local_commitment_tx_fee_info_cached: Arc::new(Mutex::new(None)),
#[cfg(any(test, fuzzing))]
next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
next_remote_commitment_tx_fee_info_cached: Arc::new(Mutex::new(None)),

workaround_lnd_bug_4006: None,
sent_message_awaiting_response: None,
Expand Down Expand Up @@ -2686,9 +2693,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
// We'll add our counterparty's `funding_satoshis` to these max commitment output assertions
// when we receive `accept_channel2`.
#[cfg(debug_assertions)]
holder_max_commitment_tx_output: Mutex::new((channel_value_satoshis * 1000 - push_msat, push_msat)),
holder_max_commitment_tx_output: Arc::new(Mutex::new((channel_value_satoshis * 1000 - push_msat, push_msat))),
#[cfg(debug_assertions)]
counterparty_max_commitment_tx_output: Mutex::new((channel_value_satoshis * 1000 - push_msat, push_msat)),
counterparty_max_commitment_tx_output: Arc::new(Mutex::new((channel_value_satoshis * 1000 - push_msat, push_msat))),

last_sent_closing_fee: None,
last_received_closing_sig: None,
Expand Down Expand Up @@ -2744,9 +2751,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
announcement_sigs: None,

#[cfg(any(test, fuzzing))]
next_local_commitment_tx_fee_info_cached: Mutex::new(None),
next_local_commitment_tx_fee_info_cached: Arc::new(Mutex::new(None)),
#[cfg(any(test, fuzzing))]
next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
next_remote_commitment_tx_fee_info_cached: Arc::new(Mutex::new(None)),

workaround_lnd_bug_4006: None,
sent_message_awaiting_response: None,
Expand Down Expand Up @@ -4413,6 +4420,110 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
self.channel_transaction_parameters = channel_transaction_parameters;
self.get_initial_counterparty_commitment_signature(logger)
}

/// Clone, each field, with the exception of the channel signer.
#[allow(unused)]
fn clone(&self, holder_signer: <SP::Target as SignerProvider>::EcdsaSigner) -> Self {
Self {
// Use provided channel signer
holder_signer: ChannelSignerType::Ecdsa(holder_signer),

config: self.config,
prev_config: self.prev_config,
inbound_handshake_limits_override: self.inbound_handshake_limits_override,
user_id: self.user_id,
channel_id: self.channel_id,
temporary_channel_id: self.temporary_channel_id,
channel_state: self.channel_state,
announcement_sigs_state: self.announcement_sigs_state.clone(),
secp_ctx: self.secp_ctx.clone(),
channel_value_satoshis: self.channel_value_satoshis,
latest_monitor_update_id: self.latest_monitor_update_id,
shutdown_scriptpubkey: self.shutdown_scriptpubkey.clone(),
destination_script: self.destination_script.clone(),
cur_counterparty_commitment_transaction_number: self.cur_counterparty_commitment_transaction_number,
value_to_self_msat: self.value_to_self_msat,
pending_inbound_htlcs: self.pending_inbound_htlcs.clone(),
pending_outbound_htlcs: self.pending_outbound_htlcs.clone(),
holding_cell_htlc_updates: self.holding_cell_htlc_updates.clone(),
resend_order: self.resend_order.clone(),
monitor_pending_channel_ready: self.monitor_pending_channel_ready,
monitor_pending_revoke_and_ack: self.monitor_pending_revoke_and_ack,
monitor_pending_commitment_signed: self.monitor_pending_commitment_signed,
monitor_pending_forwards: self.monitor_pending_forwards.clone(),
monitor_pending_failures: self.monitor_pending_failures.clone(),
monitor_pending_finalized_fulfills: self.monitor_pending_finalized_fulfills.clone(),
monitor_pending_update_adds: self.monitor_pending_update_adds.clone(),
monitor_pending_tx_signatures: self.monitor_pending_tx_signatures.clone(),
signer_pending_revoke_and_ack: self.signer_pending_revoke_and_ack,
signer_pending_commitment_update: self.signer_pending_commitment_update,
signer_pending_funding: self.signer_pending_funding,
signer_pending_closing: self.signer_pending_closing,
signer_pending_channel_ready: self.signer_pending_channel_ready,
pending_update_fee: self.pending_update_fee,
holding_cell_update_fee: self.holding_cell_update_fee,
next_holder_htlc_id: self.next_holder_htlc_id,
next_counterparty_htlc_id: self.next_counterparty_htlc_id,
feerate_per_kw: self.feerate_per_kw,
update_time_counter: self.update_time_counter,
// Create new mutex with copied values
#[cfg(debug_assertions)]
holder_max_commitment_tx_output: self.holder_max_commitment_tx_output.clone(),
#[cfg(debug_assertions)]
counterparty_max_commitment_tx_output: self.counterparty_max_commitment_tx_output.clone(),
last_sent_closing_fee: self.last_sent_closing_fee.clone(),
last_received_closing_sig: self.last_received_closing_sig,
target_closing_feerate_sats_per_kw: self.target_closing_feerate_sats_per_kw,
pending_counterparty_closing_signed: self.pending_counterparty_closing_signed.clone(),
closing_fee_limits: self.closing_fee_limits,
expecting_peer_commitment_signed: self.expecting_peer_commitment_signed,
funding_tx_confirmed_in: self.funding_tx_confirmed_in,
funding_tx_confirmation_height: self.funding_tx_confirmation_height,
short_channel_id: self.short_channel_id,
channel_creation_height: self.channel_creation_height,
counterparty_dust_limit_satoshis: self.counterparty_dust_limit_satoshis,
holder_dust_limit_satoshis: self.holder_dust_limit_satoshis,
counterparty_max_htlc_value_in_flight_msat: self.counterparty_max_htlc_value_in_flight_msat,
holder_max_htlc_value_in_flight_msat: self.holder_max_htlc_value_in_flight_msat,
counterparty_selected_channel_reserve_satoshis: self.counterparty_selected_channel_reserve_satoshis,
holder_selected_channel_reserve_satoshis: self.holder_selected_channel_reserve_satoshis,
counterparty_htlc_minimum_msat: self.counterparty_htlc_minimum_msat,
holder_htlc_minimum_msat: self.holder_htlc_minimum_msat,
counterparty_max_accepted_htlcs: self.counterparty_max_accepted_htlcs,
holder_max_accepted_htlcs: self.holder_max_accepted_htlcs,
minimum_depth: self.minimum_depth,
counterparty_forwarding_info: self.counterparty_forwarding_info.clone(),
channel_transaction_parameters: self.channel_transaction_parameters.clone(),
funding_transaction: self.funding_transaction.clone(),
is_manual_broadcast: self.is_manual_broadcast,
is_batch_funding: self.is_batch_funding,
counterparty_cur_commitment_point: self.counterparty_cur_commitment_point,
counterparty_prev_commitment_point: self.counterparty_prev_commitment_point,
counterparty_node_id: self.counterparty_node_id,
counterparty_shutdown_scriptpubkey: self.counterparty_shutdown_scriptpubkey.clone(),
commitment_secrets: self.commitment_secrets.clone(),
channel_update_status: self.channel_update_status,
closing_signed_in_flight: self.closing_signed_in_flight,
announcement_sigs: self.announcement_sigs,
// Create new mutex with copied values
#[cfg(any(test, fuzzing))]
next_local_commitment_tx_fee_info_cached: self.next_local_commitment_tx_fee_info_cached.clone(),
#[cfg(any(test, fuzzing))]
next_remote_commitment_tx_fee_info_cached: self.next_remote_commitment_tx_fee_info_cached.clone(),
workaround_lnd_bug_4006: self.workaround_lnd_bug_4006.clone(),
sent_message_awaiting_response: self.sent_message_awaiting_response,
channel_type: self.channel_type.clone(),
latest_inbound_scid_alias: self.latest_inbound_scid_alias,
outbound_scid_alias: self.outbound_scid_alias,
channel_pending_event_emitted: self.channel_pending_event_emitted,
funding_tx_broadcast_safe_event_emitted: self.funding_tx_broadcast_safe_event_emitted,
channel_ready_event_emitted: self.channel_ready_event_emitted,
local_initiated_shutdown: self.local_initiated_shutdown.clone(),
channel_keys_id: self.channel_keys_id,
blocked_monitor_updates: self.blocked_monitor_updates.clone(),
next_funding_txid: self.next_funding_txid.clone(),
}
}
}

// Internal utility functions for channels
Expand Down Expand Up @@ -4540,6 +4651,7 @@ pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
}

#[cfg(any(test, fuzzing))]
#[derive(Clone)]
struct CommitmentTxInfoCached {
fee: u64,
total_pending_htlcs: usize,
Expand Down Expand Up @@ -10377,9 +10489,9 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
feerate_per_kw,

#[cfg(debug_assertions)]
holder_max_commitment_tx_output: Mutex::new((0, 0)),
holder_max_commitment_tx_output: Arc::new(Mutex::new((0, 0))),
#[cfg(debug_assertions)]
counterparty_max_commitment_tx_output: Mutex::new((0, 0)),
counterparty_max_commitment_tx_output: Arc::new(Mutex::new((0, 0))),

last_sent_closing_fee: None,
last_received_closing_sig: None,
Expand Down Expand Up @@ -10424,9 +10536,9 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
announcement_sigs,

#[cfg(any(test, fuzzing))]
next_local_commitment_tx_fee_info_cached: Mutex::new(None),
next_local_commitment_tx_fee_info_cached: Arc::new(Mutex::new(None)),
#[cfg(any(test, fuzzing))]
next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
next_remote_commitment_tx_fee_info_cached: Arc::new(Mutex::new(None)),

workaround_lnd_bug_4006: None,
sent_message_awaiting_response: None,
Expand Down Expand Up @@ -10474,7 +10586,7 @@ mod tests {
use crate::ln::channel_keys::{RevocationKey, RevocationBasepoint};
use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
use crate::ln::channel::InitFeatures;
use crate::ln::channel::{AwaitingChannelReadyFlags, ChannelState, FundedChannel, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_sat};
use crate::ln::channel::{AwaitingChannelReadyFlags, ChannelContext, ChannelState, FundedChannel, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_sat};
use crate::ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS};
use crate::types::features::{ChannelFeatures, ChannelTypeFeatures, NodeFeatures};
use crate::ln::msgs;
Expand Down Expand Up @@ -12238,4 +12350,55 @@ mod tests {
assert_eq!(node_a_chan.context.channel_state, ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::THEIR_CHANNEL_READY));
assert!(node_a_chan.check_get_channel_ready(0, &&logger).is_some());
}

#[test]
fn channel_context_clone() {
let fee_estimator = TestFeeEstimator {fee_est: 253 };
let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&fee_estimator);
let seed = [42; 32];
let network = Network::Testnet;
let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
let secp_ctx = Secp256k1::new();
let node_a_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let config = UserConfig::default();

let signer_provider: &TestKeysInterface = &&keys_provider;
let channel_value_satoshis = 10000000;
let user_id = 42;
let channel_keys_id = signer_provider.generate_channel_keys_id(false, channel_value_satoshis, user_id);
let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id);
let logger = test_utils::TestLogger::new();
let pubkeys = holder_signer.pubkeys().clone();

// Create a context
let context = ChannelContext::<&TestKeysInterface>::new_for_outbound_channel(
&bounded_fee_estimator,
&&keys_provider,
&signer_provider,
node_a_node_id,
&channelmanager::provided_init_features(&config),
channel_value_satoshis,
100000,
user_id,
&config,
0,
42,
None,
100000,
[42; 32],
holder_signer,
pubkeys,
&logger,
).unwrap();

// Clone it
let holder_signer2 = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id);
let context_cloned = context.clone(holder_signer2);

// Compare some fields
assert_eq!(context_cloned.channel_value_satoshis, context.channel_value_satoshis);
assert_eq!(context_cloned.channel_id, context.channel_id);
assert_eq!(context_cloned.funding_tx_broadcast_safe_event_emitted, context.funding_tx_broadcast_safe_event_emitted);
assert_eq!(context_cloned.channel_keys_id, context.channel_keys_id);
}
}
1 change: 1 addition & 0 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ use crate::ln::inbound_payment;
use crate::ln::types::ChannelId;
use crate::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
use crate::ln::channel::{self, Channel, ChannelError, ChannelUpdateStatus, FundedChannel, ShutdownResult, UpdateFulfillCommitFetch, OutboundV1Channel, ReconnectionMsg, InboundV1Channel, WithChannelContext};
#[cfg(dual_funding)]
#[cfg(any(dual_funding, splicing))]
use crate::ln::channel::PendingV2Channel;
use crate::ln::channel_state::ChannelDetails;
Expand Down
Loading