@@ -112,6 +112,7 @@ enum FeeUpdateState {
112112 Outbound,
113113}
114114
115+ #[derive(Clone)]
115116enum InboundHTLCRemovalReason {
116117 FailRelay(msgs::OnionErrorPacket),
117118 FailMalformed(([u8; 32], u16)),
@@ -146,6 +147,7 @@ impl_writeable_tlv_based_enum!(InboundHTLCResolution,
146147 },
147148);
148149
150+ #[derive(Clone)]
149151enum InboundHTLCState {
150152 /// Offered by remote, to be included in next local commitment tx. I.e., the remote sent an
151153 /// update_add_htlc message for this HTLC.
@@ -220,6 +222,7 @@ impl From<&InboundHTLCState> for Option<InboundHTLCStateDetails> {
220222 }
221223}
222224
225+ #[derive(Clone)]
223226struct InboundHTLCOutput {
224227 htlc_id: u64,
225228 amount_msat: u64,
@@ -228,7 +231,8 @@ struct InboundHTLCOutput {
228231 state: InboundHTLCState,
229232}
230233
231- #[cfg_attr(test, derive(Clone, Debug, PartialEq))]
234+ #[derive(Clone)]
235+ #[cfg_attr(test, derive(Debug, PartialEq))]
232236enum OutboundHTLCState {
233237 /// Added by us and included in a commitment_signed (if we were AwaitingRemoteRevoke when we
234238 /// created it we would have put it in the holding cell instead). When they next revoke_and_ack
@@ -310,7 +314,8 @@ impl<'a> Into<Option<&'a HTLCFailReason>> for &'a OutboundHTLCOutcome {
310314 }
311315}
312316
313- #[cfg_attr(test, derive(Clone, Debug, PartialEq))]
317+ #[derive(Clone)]
318+ #[cfg_attr(test, derive(Debug, PartialEq))]
314319struct OutboundHTLCOutput {
315320 htlc_id: u64,
316321 amount_msat: u64,
@@ -323,7 +328,8 @@ struct OutboundHTLCOutput {
323328}
324329
325330/// See AwaitingRemoteRevoke ChannelState for more info
326- #[cfg_attr(test, derive(Clone, Debug, PartialEq))]
331+ #[derive(Clone)]
332+ #[cfg_attr(test, derive(Debug, PartialEq))]
327333enum HTLCUpdateAwaitingACK {
328334 AddHTLC { // TODO: Time out if we're getting close to cltv_expiry
329335 // always outbound
@@ -801,7 +807,7 @@ pub(super) enum ChannelUpdateStatus {
801807}
802808
803809/// We track when we sent an `AnnouncementSignatures` to our peer in a few states, described here.
804- #[derive(PartialEq)]
810+ #[derive(Clone, PartialEq)]
805811pub enum AnnouncementSigsState {
806812 /// We have not sent our peer an `AnnouncementSignatures` yet, or our peer disconnected since
807813 /// we sent the last `AnnouncementSignatures`.
@@ -1126,6 +1132,7 @@ pub(crate) const UNFUNDED_CHANNEL_AGE_LIMIT_TICKS: usize = 60;
11261132/// Number of blocks needed for an output from a coinbase transaction to be spendable.
11271133pub(crate) const COINBASE_MATURITY: u32 = 100;
11281134
1135+ #[derive(Clone)]
11291136struct PendingChannelMonitorUpdate {
11301137 update: ChannelMonitorUpdate,
11311138}
@@ -4413,6 +4420,111 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
44134420 self.channel_transaction_parameters = channel_transaction_parameters;
44144421 self.get_initial_counterparty_commitment_signature(logger)
44154422 }
4423+
4424+ /// Clone, each field, with a few exceptions, notably the channel signer, and
4425+ /// a few non-cloneable fields (such as Secp256k1 context)
4426+ #[allow(unused)]
4427+ fn clone(&self, holder_signer: <SP::Target as SignerProvider>::EcdsaSigner) -> Self {
4428+ Self {
4429+ config: self.config,
4430+ prev_config: self.prev_config,
4431+ inbound_handshake_limits_override: self.inbound_handshake_limits_override,
4432+ user_id: self.user_id,
4433+ channel_id: self.channel_id,
4434+ temporary_channel_id: self.temporary_channel_id,
4435+ channel_state: self.channel_state,
4436+ announcement_sigs_state: self.announcement_sigs_state.clone(),
4437+ // Create new Secp256k context
4438+ secp_ctx: Secp256k1::new(),
4439+ channel_value_satoshis: self.channel_value_satoshis,
4440+ latest_monitor_update_id: self.latest_monitor_update_id,
4441+ // Use provided channel signer
4442+ holder_signer: ChannelSignerType::Ecdsa(holder_signer),
4443+ shutdown_scriptpubkey: self.shutdown_scriptpubkey.clone(),
4444+ destination_script: self.destination_script.clone(),
4445+ cur_counterparty_commitment_transaction_number: self.cur_counterparty_commitment_transaction_number,
4446+ value_to_self_msat: self.value_to_self_msat,
4447+ pending_inbound_htlcs: self.pending_inbound_htlcs.clone(),
4448+ pending_outbound_htlcs: self.pending_outbound_htlcs.clone(),
4449+ holding_cell_htlc_updates: self.holding_cell_htlc_updates.clone(),
4450+ resend_order: self.resend_order.clone(),
4451+ monitor_pending_channel_ready: self.monitor_pending_channel_ready,
4452+ monitor_pending_revoke_and_ack: self.monitor_pending_revoke_and_ack,
4453+ monitor_pending_commitment_signed: self.monitor_pending_commitment_signed,
4454+ monitor_pending_forwards: self.monitor_pending_forwards.clone(),
4455+ monitor_pending_failures: self.monitor_pending_failures.clone(),
4456+ monitor_pending_finalized_fulfills: self.monitor_pending_finalized_fulfills.clone(),
4457+ monitor_pending_update_adds: self.monitor_pending_update_adds.clone(),
4458+ monitor_pending_tx_signatures: self.monitor_pending_tx_signatures.clone(),
4459+ signer_pending_revoke_and_ack: self.signer_pending_revoke_and_ack,
4460+ signer_pending_commitment_update: self.signer_pending_commitment_update,
4461+ signer_pending_funding: self.signer_pending_funding,
4462+ signer_pending_closing: self.signer_pending_closing,
4463+ signer_pending_channel_ready: self.signer_pending_channel_ready,
4464+ pending_update_fee: self.pending_update_fee,
4465+ holding_cell_update_fee: self.holding_cell_update_fee,
4466+ next_holder_htlc_id: self.next_holder_htlc_id,
4467+ next_counterparty_htlc_id: self.next_counterparty_htlc_id,
4468+ feerate_per_kw: self.feerate_per_kw,
4469+ update_time_counter: self.update_time_counter,
4470+ // Create new mutex with copied values
4471+ #[cfg(debug_assertions)]
4472+ holder_max_commitment_tx_output: Mutex::new(*self.holder_max_commitment_tx_output.lock().unwrap()),
4473+ #[cfg(debug_assertions)]
4474+ counterparty_max_commitment_tx_output: Mutex::new(*self.counterparty_max_commitment_tx_output.lock().unwrap()),
4475+ last_sent_closing_fee: self.last_sent_closing_fee.clone(),
4476+ last_received_closing_sig: self.last_received_closing_sig,
4477+ target_closing_feerate_sats_per_kw: self.target_closing_feerate_sats_per_kw,
4478+ pending_counterparty_closing_signed: self.pending_counterparty_closing_signed.clone(),
4479+ closing_fee_limits: self.closing_fee_limits,
4480+ expecting_peer_commitment_signed: self.expecting_peer_commitment_signed,
4481+ funding_tx_confirmed_in: self.funding_tx_confirmed_in,
4482+ funding_tx_confirmation_height: self.funding_tx_confirmation_height,
4483+ short_channel_id: self.short_channel_id,
4484+ channel_creation_height: self.channel_creation_height,
4485+ counterparty_dust_limit_satoshis: self.counterparty_dust_limit_satoshis,
4486+ holder_dust_limit_satoshis: self.holder_dust_limit_satoshis,
4487+ counterparty_max_htlc_value_in_flight_msat: self.counterparty_max_htlc_value_in_flight_msat,
4488+ holder_max_htlc_value_in_flight_msat: self.holder_max_htlc_value_in_flight_msat,
4489+ counterparty_selected_channel_reserve_satoshis: self.counterparty_selected_channel_reserve_satoshis,
4490+ holder_selected_channel_reserve_satoshis: self.holder_selected_channel_reserve_satoshis,
4491+ counterparty_htlc_minimum_msat: self.counterparty_htlc_minimum_msat,
4492+ holder_htlc_minimum_msat: self.holder_htlc_minimum_msat,
4493+ counterparty_max_accepted_htlcs: self.counterparty_max_accepted_htlcs,
4494+ holder_max_accepted_htlcs: self.holder_max_accepted_htlcs,
4495+ minimum_depth: self.minimum_depth,
4496+ counterparty_forwarding_info: self.counterparty_forwarding_info.clone(),
4497+ channel_transaction_parameters: self.channel_transaction_parameters.clone(),
4498+ funding_transaction: self.funding_transaction.clone(),
4499+ is_manual_broadcast: self.is_manual_broadcast,
4500+ is_batch_funding: self.is_batch_funding,
4501+ counterparty_cur_commitment_point: self.counterparty_cur_commitment_point,
4502+ counterparty_prev_commitment_point: self.counterparty_prev_commitment_point,
4503+ counterparty_node_id: self.counterparty_node_id,
4504+ counterparty_shutdown_scriptpubkey: self.counterparty_shutdown_scriptpubkey.clone(),
4505+ commitment_secrets: self.commitment_secrets.clone(),
4506+ channel_update_status: self.channel_update_status,
4507+ closing_signed_in_flight: self.closing_signed_in_flight,
4508+ announcement_sigs: self.announcement_sigs,
4509+ // Create new mutex with copied values
4510+ #[cfg(any(test, fuzzing))]
4511+ next_local_commitment_tx_fee_info_cached: Mutex::new(self.next_local_commitment_tx_fee_info_cached.lock().unwrap().clone()),
4512+ #[cfg(any(test, fuzzing))]
4513+ next_remote_commitment_tx_fee_info_cached: Mutex::new(self.next_remote_commitment_tx_fee_info_cached.lock().unwrap().clone()),
4514+ workaround_lnd_bug_4006: self.workaround_lnd_bug_4006.clone(),
4515+ sent_message_awaiting_response: self.sent_message_awaiting_response,
4516+ channel_type: self.channel_type.clone(),
4517+ latest_inbound_scid_alias: self.latest_inbound_scid_alias,
4518+ outbound_scid_alias: self.outbound_scid_alias,
4519+ channel_pending_event_emitted: self.channel_pending_event_emitted,
4520+ funding_tx_broadcast_safe_event_emitted: self.funding_tx_broadcast_safe_event_emitted,
4521+ channel_ready_event_emitted: self.channel_ready_event_emitted,
4522+ local_initiated_shutdown: self.local_initiated_shutdown.clone(),
4523+ channel_keys_id: self.channel_keys_id,
4524+ blocked_monitor_updates: self.blocked_monitor_updates.clone(),
4525+ next_funding_txid: self.next_funding_txid.clone(),
4526+ }
4527+ }
44164528}
44174529
44184530// Internal utility functions for channels
@@ -4540,6 +4652,7 @@ pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
45404652}
45414653
45424654#[cfg(any(test, fuzzing))]
4655+ #[derive(Clone)]
45434656struct CommitmentTxInfoCached {
45444657 fee: u64,
45454658 total_pending_htlcs: usize,
@@ -10474,7 +10587,7 @@ mod tests {
1047410587 use crate::ln::channel_keys::{RevocationKey, RevocationBasepoint};
1047510588 use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
1047610589 use crate::ln::channel::InitFeatures;
10477- use crate::ln::channel::{AwaitingChannelReadyFlags, ChannelState, FundedChannel, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_sat};
10590+ use crate::ln::channel::{AwaitingChannelReadyFlags, ChannelContext, ChannelState, FundedChannel, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_sat};
1047810591 use crate::ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS};
1047910592 use crate::types::features::{ChannelFeatures, ChannelTypeFeatures, NodeFeatures};
1048010593 use crate::ln::msgs;
@@ -12238,4 +12351,55 @@ mod tests {
1223812351 assert_eq!(node_a_chan.context.channel_state, ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::THEIR_CHANNEL_READY));
1223912352 assert!(node_a_chan.check_get_channel_ready(0, &&logger).is_some());
1224012353 }
12354+
12355+ #[test]
12356+ fn channel_context_clone() {
12357+ let fee_estimator = TestFeeEstimator {fee_est: 253 };
12358+ let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&fee_estimator);
12359+ let seed = [42; 32];
12360+ let network = Network::Testnet;
12361+ let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
12362+ let secp_ctx = Secp256k1::new();
12363+ let node_a_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
12364+ let config = UserConfig::default();
12365+
12366+ let signer_provider: &TestKeysInterface = &&keys_provider;
12367+ let channel_value_satoshis = 10000000;
12368+ let user_id = 42;
12369+ let channel_keys_id = signer_provider.generate_channel_keys_id(false, channel_value_satoshis, user_id);
12370+ let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id);
12371+ let logger = test_utils::TestLogger::new();
12372+ let pubkeys = holder_signer.pubkeys().clone();
12373+
12374+ // Create a context
12375+ let context = ChannelContext::<&TestKeysInterface>::new_for_outbound_channel(
12376+ &bounded_fee_estimator,
12377+ &&keys_provider,
12378+ &signer_provider,
12379+ node_a_node_id,
12380+ &channelmanager::provided_init_features(&config),
12381+ channel_value_satoshis,
12382+ 100000,
12383+ user_id,
12384+ &config,
12385+ 0,
12386+ 42,
12387+ None,
12388+ 100000,
12389+ [42; 32],
12390+ holder_signer,
12391+ pubkeys,
12392+ &logger,
12393+ ).unwrap();
12394+
12395+ // Clone it
12396+ let holder_signer2 = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id);
12397+ let context_cloned = context.clone(holder_signer2);
12398+
12399+ // Compare some fields
12400+ assert_eq!(context_cloned.channel_value_satoshis, context.channel_value_satoshis);
12401+ assert_eq!(context_cloned.channel_id, context.channel_id);
12402+ assert_eq!(context_cloned.funding_tx_broadcast_safe_event_emitted, context.funding_tx_broadcast_safe_event_emitted);
12403+ assert_eq!(context_cloned.channel_keys_id, context.channel_keys_id);
12404+ }
1224112405}
0 commit comments