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
117 changes: 95 additions & 22 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1132,14 +1132,15 @@ pub(super) enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
#[allow(dead_code)] // TODO(dual_funding): Remove once creating V2 channels is enabled.
UnfundedOutboundV2(OutboundV2Channel<SP>),
UnfundedInboundV2(InboundV2Channel<SP>),
Funded(Channel<SP>),
Funded(FundedChannel<SP>),
}

impl<'a, SP: Deref> ChannelPhase<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: ChannelSigner,
{
pub fn context(&'a self) -> &'a ChannelContext<SP> {
#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
match self {
ChannelPhase::Funded(chan) => &chan.context,
ChannelPhase::UnfundedOutboundV1(chan) => &chan.context,
Expand All@@ -1149,7 +1150,8 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

pub fn context_mut(&'a mut self) -> &'a mut ChannelContext<SP> {
#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
match self {
ChannelPhase::Funded(ref mut chan) => &mut chan.context,
ChannelPhase::UnfundedOutboundV1(ref mut chan) => &mut chan.context,
Expand All@@ -1160,6 +1162,77 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

/// A top-level channel struct, containing a channel phase
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
/// The inner channel phase
/// Option is used to facilitate in-place replacement (see e.g. move_v2_to_funded),
/// but it is never None, ensured in new() and set_phase()
phase: Option<ChannelPhase<SP>>,
Comment on lines +1167 to +1170

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment about moving ChannelContext here. Seems we shouldn't need to use an Option.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that logically it should not be Option, but I found no other way to transport the context from one phase to another. This may be Rust technicality. Option can be taken out and left empty, which is needed as I was not able to make the transfer in one atomic operation. Maybe another solution would be if ChannelContext had a default().

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would swap work?

}

impl<'a, SP: Deref> Channel<SP> where SP::Target: SignerProvider {
pub fn new(phase: ChannelPhase<SP>) -> Self {
Self {
phase: Some(phase),
}
}

#[inline]
pub fn phase(&self) -> &ChannelPhase<SP> {
self.phase.as_ref().unwrap()
}

#[inline]
pub fn phase_mut(&mut self) -> &mut ChannelPhase<SP> {
self.phase.as_mut().unwrap()
}

pub fn phase_take(self) -> ChannelPhase<SP> {
match self.phase {
Some(phase) => phase,
None => panic!("None phase"),
}
}

pub fn funded_channel(&self) -> Option<&FundedChannel<SP>> {
if let ChannelPhase::Funded(chan) = &self.phase.as_ref().unwrap() {
Some(chan)
} else {
None
}
}

/// Change the internal phase
#[inline]
pub fn set_phase(&mut self, new_phase: ChannelPhase<SP>) {
self.phase = Some(new_phase);
}

pub fn move_v2_to_funded(&mut self, signing_session: InteractiveTxSigningSession) -> Result<(), ChannelError> {
// We need a borrow to the phase field, but self is only a mut ref
let phase_inline = self.phase.take().unwrap();
let new_phase = match phase_inline {
ChannelPhase::UnfundedOutboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
ChannelPhase::UnfundedInboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
_ => phase_inline,
};
self.set_phase(new_phase);
Ok(())
}

#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
self.phase().context()
}

#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
self.phase_mut().context_mut()
}
}

/// Contains all state common to unfunded inbound/outbound channels.
pub(super) struct UnfundedChannelContext {
/// A counter tracking how many ticks have elapsed since this unfunded channel was
Expand DownExpand Up@@ -1270,7 +1343,7 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
/// the future when the signer indicates it may have a signature for us.
///
/// This flag is set in such a case. Note that we don't need to persist this as we'll end up
/// setting it again as a side-effect of [`Channel::channel_reestablish`].
/// setting it again as a side-effect of [`FundedChannel::channel_reestablish`].
signer_pending_commitment_update: bool,
/// Similar to [`Self::signer_pending_commitment_update`] but we're waiting to send either a
/// [`msgs::FundingCreated`] or [`msgs::FundingSigned`] depending on if this channel is
Expand DownExpand Up@@ -1661,7 +1734,7 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for InboundV1Channel<SP> whe
}
}

impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for FundedChannel<SP> where SP::Target: SignerProvider {
fn context(&self) -> &ChannelContext<SP> {
&self.context
}
Expand DownExpand Up@@ -1928,7 +2001,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
if open_channel_fields.htlc_minimum_msat >= full_channel_value_msat {
return Err(ChannelError::close(format!("Minimum htlc value ({}) was larger than full channel value ({})", open_channel_fields.htlc_minimum_msat, full_channel_value_msat)));
}
Channel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;
FundedChannel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;

let max_counterparty_selected_contest_delay = u16::min(config.channel_handshake_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
if open_channel_fields.to_self_delay > max_counterparty_selected_contest_delay {
Expand DownExpand Up@@ -4211,7 +4284,7 @@ pub(super) struct DualFundingChannelContext {

// Holder designates channel data owned for the benefit of the user client.
// Counterparty designates channel data owned by the another channel participant entity.
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
pub context: ChannelContext<SP>,
pub interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
}
Expand DownExpand Up@@ -4281,7 +4354,7 @@ impl FailHTLCMessageName for msgs::UpdateFailMalformedHTLC {
}
}

impl<SP: Deref> Channel<SP> where
impl<SP: Deref> FundedChannel<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: EcdsaChannelSigner
{
Expand DownExpand Up@@ -6073,7 +6146,7 @@ impl<SP: Deref> Channel<SP> where
if self.context.channel_state.is_peer_disconnected() {
return Err(ChannelError::close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
}
Channel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;
FundedChannel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;

self.context.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced));
self.context.update_time_counter += 1;
Expand DownExpand Up@@ -8465,7 +8538,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
/// If this call is successful, broadcast the funding transaction (and not before!)
pub fn funding_signed<L: Deref>(
mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
) -> Result<(FundedChannel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
where
L::Target: Logger
{
Expand All@@ -8488,7 +8561,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {

log_info!(logger, "Received funding_signed from peer for channel {}", &self.context.channel_id());

let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8673,7 +8746,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

pub fn funding_created<L: Deref>(
mut self, msg: &msgs::FundingCreated, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
) -> Result<(FundedChannel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
where
L::Target: Logger
{
Expand DownExpand Up@@ -8713,7 +8786,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

// Promote the channel to a full-fledged one now that we have updated the state and have a
// `ChannelMonitor`.
let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8857,8 +8930,8 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
}
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9051,8 +9124,8 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
self.generate_accept_channel_v2_message()
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9143,7 +9216,7 @@ impl Readable for AnnouncementSigsState {
}
}

impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
// Note that we write out as if remove_uncommitted_htlcs_and_mark_paused had just been
// called.
Expand DownExpand Up@@ -9522,7 +9595,7 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
}

const MAX_ALLOC_SIZE: usize = 64*1024;
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for Channel<SP>
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for FundedChannel<SP>
where
ES::Target: EntropySource,
SP::Target: SignerProvider
Expand DownExpand Up@@ -9994,7 +10067,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
},
};

Ok(Channel {
Ok(FundedChannel {
context: ChannelContext {
user_id,

Expand DownExpand Up@@ -10151,7 +10224,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, Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_sat};
use crate::ln::channel::{AwaitingChannelReadyFlags, FundedChannel, ChannelState, 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 DownExpand Up@@ -10817,7 +10890,7 @@ mod tests {
let mut s = crate::io::Cursor::new(&encoded_chan);
let mut reader = crate::util::ser::FixedLengthReader::new(&mut s, encoded_chan.len() as u64);
let features = channelmanager::provided_channel_type_features(&config);
let decoded_chan = Channel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
let decoded_chan = FundedChannel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
assert_eq!(decoded_chan.context.pending_outbound_htlcs, pending_outbound_htlcs);
assert_eq!(decoded_chan.context.holding_cell_htlc_updates, holding_cell_htlc_updates);
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
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
117 changes: 95 additions & 22 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1132,14 +1132,15 @@ pub(super) enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
#[allow(dead_code)] // TODO(dual_funding): Remove once creating V2 channels is enabled.
UnfundedOutboundV2(OutboundV2Channel<SP>),
UnfundedInboundV2(InboundV2Channel<SP>),
Funded(Channel<SP>),
Funded(FundedChannel<SP>),
}

impl<'a, SP: Deref> ChannelPhase<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: ChannelSigner,
{
pub fn context(&'a self) -> &'a ChannelContext<SP> {
#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
match self {
ChannelPhase::Funded(chan) => &chan.context,
ChannelPhase::UnfundedOutboundV1(chan) => &chan.context,
Expand All@@ -1149,7 +1150,8 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

pub fn context_mut(&'a mut self) -> &'a mut ChannelContext<SP> {
#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
match self {
ChannelPhase::Funded(ref mut chan) => &mut chan.context,
ChannelPhase::UnfundedOutboundV1(ref mut chan) => &mut chan.context,
Expand All@@ -1160,6 +1162,77 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

/// A top-level channel struct, containing a channel phase
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
/// The inner channel phase
/// Option is used to facilitate in-place replacement (see e.g. move_v2_to_funded),
/// but it is never None, ensured in new() and set_phase()
phase: Option<ChannelPhase<SP>>,
Comment on lines +1167 to +1170

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment about moving ChannelContext here. Seems we shouldn't need to use an Option.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that logically it should not be Option, but I found no other way to transport the context from one phase to another. This may be Rust technicality. Option can be taken out and left empty, which is needed as I was not able to make the transfer in one atomic operation. Maybe another solution would be if ChannelContext had a default().

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would swap work?

}

impl<'a, SP: Deref> Channel<SP> where SP::Target: SignerProvider {
pub fn new(phase: ChannelPhase<SP>) -> Self {
Self {
phase: Some(phase),
}
}

#[inline]
pub fn phase(&self) -> &ChannelPhase<SP> {
self.phase.as_ref().unwrap()
}

#[inline]
pub fn phase_mut(&mut self) -> &mut ChannelPhase<SP> {
self.phase.as_mut().unwrap()
}

pub fn phase_take(self) -> ChannelPhase<SP> {
match self.phase {
Some(phase) => phase,
None => panic!("None phase"),
}
}

pub fn funded_channel(&self) -> Option<&FundedChannel<SP>> {
if let ChannelPhase::Funded(chan) = &self.phase.as_ref().unwrap() {
Some(chan)
} else {
None
}
}

/// Change the internal phase
#[inline]
pub fn set_phase(&mut self, new_phase: ChannelPhase<SP>) {
self.phase = Some(new_phase);
}

pub fn move_v2_to_funded(&mut self, signing_session: InteractiveTxSigningSession) -> Result<(), ChannelError> {
// We need a borrow to the phase field, but self is only a mut ref
let phase_inline = self.phase.take().unwrap();
let new_phase = match phase_inline {
ChannelPhase::UnfundedOutboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
ChannelPhase::UnfundedInboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
_ => phase_inline,
};
self.set_phase(new_phase);
Ok(())
}

#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
self.phase().context()
}

#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
self.phase_mut().context_mut()
}
}

/// Contains all state common to unfunded inbound/outbound channels.
pub(super) struct UnfundedChannelContext {
/// A counter tracking how many ticks have elapsed since this unfunded channel was
Expand DownExpand Up@@ -1270,7 +1343,7 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
/// the future when the signer indicates it may have a signature for us.
///
/// This flag is set in such a case. Note that we don't need to persist this as we'll end up
/// setting it again as a side-effect of [`Channel::channel_reestablish`].
/// setting it again as a side-effect of [`FundedChannel::channel_reestablish`].
signer_pending_commitment_update: bool,
/// Similar to [`Self::signer_pending_commitment_update`] but we're waiting to send either a
/// [`msgs::FundingCreated`] or [`msgs::FundingSigned`] depending on if this channel is
Expand DownExpand Up@@ -1661,7 +1734,7 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for InboundV1Channel<SP> whe
}
}

impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for FundedChannel<SP> where SP::Target: SignerProvider {
fn context(&self) -> &ChannelContext<SP> {
&self.context
}
Expand DownExpand Up@@ -1928,7 +2001,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
if open_channel_fields.htlc_minimum_msat >= full_channel_value_msat {
return Err(ChannelError::close(format!("Minimum htlc value ({}) was larger than full channel value ({})", open_channel_fields.htlc_minimum_msat, full_channel_value_msat)));
}
Channel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;
FundedChannel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;

let max_counterparty_selected_contest_delay = u16::min(config.channel_handshake_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
if open_channel_fields.to_self_delay > max_counterparty_selected_contest_delay {
Expand DownExpand Up@@ -4211,7 +4284,7 @@ pub(super) struct DualFundingChannelContext {

// Holder designates channel data owned for the benefit of the user client.
// Counterparty designates channel data owned by the another channel participant entity.
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
pub context: ChannelContext<SP>,
pub interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
}
Expand DownExpand Up@@ -4281,7 +4354,7 @@ impl FailHTLCMessageName for msgs::UpdateFailMalformedHTLC {
}
}

impl<SP: Deref> Channel<SP> where
impl<SP: Deref> FundedChannel<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: EcdsaChannelSigner
{
Expand DownExpand Up@@ -6073,7 +6146,7 @@ impl<SP: Deref> Channel<SP> where
if self.context.channel_state.is_peer_disconnected() {
return Err(ChannelError::close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
}
Channel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;
FundedChannel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;

self.context.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced));
self.context.update_time_counter += 1;
Expand DownExpand Up@@ -8465,7 +8538,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
/// If this call is successful, broadcast the funding transaction (and not before!)
pub fn funding_signed<L: Deref>(
mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
) -> Result<(FundedChannel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
where
L::Target: Logger
{
Expand All@@ -8488,7 +8561,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {

log_info!(logger, "Received funding_signed from peer for channel {}", &self.context.channel_id());

let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8673,7 +8746,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

pub fn funding_created<L: Deref>(
mut self, msg: &msgs::FundingCreated, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
) -> Result<(FundedChannel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
where
L::Target: Logger
{
Expand DownExpand Up@@ -8713,7 +8786,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

// Promote the channel to a full-fledged one now that we have updated the state and have a
// `ChannelMonitor`.
let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8857,8 +8930,8 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
}
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9051,8 +9124,8 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
self.generate_accept_channel_v2_message()
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9143,7 +9216,7 @@ impl Readable for AnnouncementSigsState {
}
}

impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
// Note that we write out as if remove_uncommitted_htlcs_and_mark_paused had just been
// called.
Expand DownExpand Up@@ -9522,7 +9595,7 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
}

const MAX_ALLOC_SIZE: usize = 64*1024;
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for Channel<SP>
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for FundedChannel<SP>
where
ES::Target: EntropySource,
SP::Target: SignerProvider
Expand DownExpand Up@@ -9994,7 +10067,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
},
};

Ok(Channel {
Ok(FundedChannel {
context: ChannelContext {
user_id,

Expand DownExpand Up@@ -10151,7 +10224,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, Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_sat};
use crate::ln::channel::{AwaitingChannelReadyFlags, FundedChannel, ChannelState, 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 DownExpand Up@@ -10817,7 +10890,7 @@ mod tests {
let mut s = crate::io::Cursor::new(&encoded_chan);
let mut reader = crate::util::ser::FixedLengthReader::new(&mut s, encoded_chan.len() as u64);
let features = channelmanager::provided_channel_type_features(&config);
let decoded_chan = Channel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
let decoded_chan = FundedChannel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
assert_eq!(decoded_chan.context.pending_outbound_htlcs, pending_outbound_htlcs);
assert_eq!(decoded_chan.context.holding_cell_htlc_updates, holding_cell_htlc_updates);
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
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
117 changes: 95 additions & 22 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1132,14 +1132,15 @@ pub(super) enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
#[allow(dead_code)] // TODO(dual_funding): Remove once creating V2 channels is enabled.
UnfundedOutboundV2(OutboundV2Channel<SP>),
UnfundedInboundV2(InboundV2Channel<SP>),
Funded(Channel<SP>),
Funded(FundedChannel<SP>),
}

impl<'a, SP: Deref> ChannelPhase<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: ChannelSigner,
{
pub fn context(&'a self) -> &'a ChannelContext<SP> {
#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
match self {
ChannelPhase::Funded(chan) => &chan.context,
ChannelPhase::UnfundedOutboundV1(chan) => &chan.context,
Expand All@@ -1149,7 +1150,8 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

pub fn context_mut(&'a mut self) -> &'a mut ChannelContext<SP> {
#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
match self {
ChannelPhase::Funded(ref mut chan) => &mut chan.context,
ChannelPhase::UnfundedOutboundV1(ref mut chan) => &mut chan.context,
Expand All@@ -1160,6 +1162,77 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

/// A top-level channel struct, containing a channel phase
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
/// The inner channel phase
/// Option is used to facilitate in-place replacement (see e.g. move_v2_to_funded),
/// but it is never None, ensured in new() and set_phase()
phase: Option<ChannelPhase<SP>>,
Comment on lines +1167 to +1170

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment about moving ChannelContext here. Seems we shouldn't need to use an Option.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that logically it should not be Option, but I found no other way to transport the context from one phase to another. This may be Rust technicality. Option can be taken out and left empty, which is needed as I was not able to make the transfer in one atomic operation. Maybe another solution would be if ChannelContext had a default().

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would swap work?

}

impl<'a, SP: Deref> Channel<SP> where SP::Target: SignerProvider {
pub fn new(phase: ChannelPhase<SP>) -> Self {
Self {
phase: Some(phase),
}
}

#[inline]
pub fn phase(&self) -> &ChannelPhase<SP> {
self.phase.as_ref().unwrap()
}

#[inline]
pub fn phase_mut(&mut self) -> &mut ChannelPhase<SP> {
self.phase.as_mut().unwrap()
}

pub fn phase_take(self) -> ChannelPhase<SP> {
match self.phase {
Some(phase) => phase,
None => panic!("None phase"),
}
}

pub fn funded_channel(&self) -> Option<&FundedChannel<SP>> {
if let ChannelPhase::Funded(chan) = &self.phase.as_ref().unwrap() {
Some(chan)
} else {
None
}
}

/// Change the internal phase
#[inline]
pub fn set_phase(&mut self, new_phase: ChannelPhase<SP>) {
self.phase = Some(new_phase);
}

pub fn move_v2_to_funded(&mut self, signing_session: InteractiveTxSigningSession) -> Result<(), ChannelError> {
// We need a borrow to the phase field, but self is only a mut ref
let phase_inline = self.phase.take().unwrap();
let new_phase = match phase_inline {
ChannelPhase::UnfundedOutboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
ChannelPhase::UnfundedInboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
_ => phase_inline,
};
self.set_phase(new_phase);
Ok(())
}

#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
self.phase().context()
}

#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
self.phase_mut().context_mut()
}
}

/// Contains all state common to unfunded inbound/outbound channels.
pub(super) struct UnfundedChannelContext {
/// A counter tracking how many ticks have elapsed since this unfunded channel was
Expand DownExpand Up@@ -1270,7 +1343,7 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
/// the future when the signer indicates it may have a signature for us.
///
/// This flag is set in such a case. Note that we don't need to persist this as we'll end up
/// setting it again as a side-effect of [`Channel::channel_reestablish`].
/// setting it again as a side-effect of [`FundedChannel::channel_reestablish`].
signer_pending_commitment_update: bool,
/// Similar to [`Self::signer_pending_commitment_update`] but we're waiting to send either a
/// [`msgs::FundingCreated`] or [`msgs::FundingSigned`] depending on if this channel is
Expand DownExpand Up@@ -1661,7 +1734,7 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for InboundV1Channel<SP> whe
}
}

impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for FundedChannel<SP> where SP::Target: SignerProvider {
fn context(&self) -> &ChannelContext<SP> {
&self.context
}
Expand DownExpand Up@@ -1928,7 +2001,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
if open_channel_fields.htlc_minimum_msat >= full_channel_value_msat {
return Err(ChannelError::close(format!("Minimum htlc value ({}) was larger than full channel value ({})", open_channel_fields.htlc_minimum_msat, full_channel_value_msat)));
}
Channel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;
FundedChannel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;

let max_counterparty_selected_contest_delay = u16::min(config.channel_handshake_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
if open_channel_fields.to_self_delay > max_counterparty_selected_contest_delay {
Expand DownExpand Up@@ -4211,7 +4284,7 @@ pub(super) struct DualFundingChannelContext {

// Holder designates channel data owned for the benefit of the user client.
// Counterparty designates channel data owned by the another channel participant entity.
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
pub context: ChannelContext<SP>,
pub interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
}
Expand DownExpand Up@@ -4281,7 +4354,7 @@ impl FailHTLCMessageName for msgs::UpdateFailMalformedHTLC {
}
}

impl<SP: Deref> Channel<SP> where
impl<SP: Deref> FundedChannel<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: EcdsaChannelSigner
{
Expand DownExpand Up@@ -6073,7 +6146,7 @@ impl<SP: Deref> Channel<SP> where
if self.context.channel_state.is_peer_disconnected() {
return Err(ChannelError::close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
}
Channel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;
FundedChannel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;

self.context.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced));
self.context.update_time_counter += 1;
Expand DownExpand Up@@ -8465,7 +8538,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
/// If this call is successful, broadcast the funding transaction (and not before!)
pub fn funding_signed<L: Deref>(
mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
) -> Result<(FundedChannel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
where
L::Target: Logger
{
Expand All@@ -8488,7 +8561,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {

log_info!(logger, "Received funding_signed from peer for channel {}", &self.context.channel_id());

let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8673,7 +8746,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

pub fn funding_created<L: Deref>(
mut self, msg: &msgs::FundingCreated, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
) -> Result<(FundedChannel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
where
L::Target: Logger
{
Expand DownExpand Up@@ -8713,7 +8786,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

// Promote the channel to a full-fledged one now that we have updated the state and have a
// `ChannelMonitor`.
let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8857,8 +8930,8 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
}
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9051,8 +9124,8 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
self.generate_accept_channel_v2_message()
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9143,7 +9216,7 @@ impl Readable for AnnouncementSigsState {
}
}

impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
// Note that we write out as if remove_uncommitted_htlcs_and_mark_paused had just been
// called.
Expand DownExpand Up@@ -9522,7 +9595,7 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
}

const MAX_ALLOC_SIZE: usize = 64*1024;
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for Channel<SP>
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for FundedChannel<SP>
where
ES::Target: EntropySource,
SP::Target: SignerProvider
Expand DownExpand Up@@ -9994,7 +10067,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
},
};

Ok(Channel {
Ok(FundedChannel {
context: ChannelContext {
user_id,

Expand DownExpand Up@@ -10151,7 +10224,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, Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_sat};
use crate::ln::channel::{AwaitingChannelReadyFlags, FundedChannel, ChannelState, 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 DownExpand Up@@ -10817,7 +10890,7 @@ mod tests {
let mut s = crate::io::Cursor::new(&encoded_chan);
let mut reader = crate::util::ser::FixedLengthReader::new(&mut s, encoded_chan.len() as u64);
let features = channelmanager::provided_channel_type_features(&config);
let decoded_chan = Channel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
let decoded_chan = FundedChannel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
assert_eq!(decoded_chan.context.pending_outbound_htlcs, pending_outbound_htlcs);
assert_eq!(decoded_chan.context.holding_cell_htlc_updates, holding_cell_htlc_updates);
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
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
117 changes: 95 additions & 22 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1132,14 +1132,15 @@ pub(super) enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
#[allow(dead_code)] // TODO(dual_funding): Remove once creating V2 channels is enabled.
UnfundedOutboundV2(OutboundV2Channel<SP>),
UnfundedInboundV2(InboundV2Channel<SP>),
Funded(Channel<SP>),
Funded(FundedChannel<SP>),
}

impl<'a, SP: Deref> ChannelPhase<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: ChannelSigner,
{
pub fn context(&'a self) -> &'a ChannelContext<SP> {
#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
match self {
ChannelPhase::Funded(chan) => &chan.context,
ChannelPhase::UnfundedOutboundV1(chan) => &chan.context,
Expand All@@ -1149,7 +1150,8 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

pub fn context_mut(&'a mut self) -> &'a mut ChannelContext<SP> {
#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
match self {
ChannelPhase::Funded(ref mut chan) => &mut chan.context,
ChannelPhase::UnfundedOutboundV1(ref mut chan) => &mut chan.context,
Expand All@@ -1160,6 +1162,77 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

/// A top-level channel struct, containing a channel phase
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
/// The inner channel phase
/// Option is used to facilitate in-place replacement (see e.g. move_v2_to_funded),
/// but it is never None, ensured in new() and set_phase()
phase: Option<ChannelPhase<SP>>,
Comment on lines +1167 to +1170

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment about moving ChannelContext here. Seems we shouldn't need to use an Option.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that logically it should not be Option, but I found no other way to transport the context from one phase to another. This may be Rust technicality. Option can be taken out and left empty, which is needed as I was not able to make the transfer in one atomic operation. Maybe another solution would be if ChannelContext had a default().

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would swap work?

}

impl<'a, SP: Deref> Channel<SP> where SP::Target: SignerProvider {
pub fn new(phase: ChannelPhase<SP>) -> Self {
Self {
phase: Some(phase),
}
}

#[inline]
pub fn phase(&self) -> &ChannelPhase<SP> {
self.phase.as_ref().unwrap()
}

#[inline]
pub fn phase_mut(&mut self) -> &mut ChannelPhase<SP> {
self.phase.as_mut().unwrap()
}

pub fn phase_take(self) -> ChannelPhase<SP> {
match self.phase {
Some(phase) => phase,
None => panic!("None phase"),
}
}

pub fn funded_channel(&self) -> Option<&FundedChannel<SP>> {
if let ChannelPhase::Funded(chan) = &self.phase.as_ref().unwrap() {
Some(chan)
} else {
None
}
}

/// Change the internal phase
#[inline]
pub fn set_phase(&mut self, new_phase: ChannelPhase<SP>) {
self.phase = Some(new_phase);
}

pub fn move_v2_to_funded(&mut self, signing_session: InteractiveTxSigningSession) -> Result<(), ChannelError> {
// We need a borrow to the phase field, but self is only a mut ref
let phase_inline = self.phase.take().unwrap();
let new_phase = match phase_inline {
ChannelPhase::UnfundedOutboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
ChannelPhase::UnfundedInboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
_ => phase_inline,
};
self.set_phase(new_phase);
Ok(())
}

#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
self.phase().context()
}

#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
self.phase_mut().context_mut()
}
}

/// Contains all state common to unfunded inbound/outbound channels.
pub(super) struct UnfundedChannelContext {
/// A counter tracking how many ticks have elapsed since this unfunded channel was
Expand DownExpand Up@@ -1270,7 +1343,7 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
/// the future when the signer indicates it may have a signature for us.
///
/// This flag is set in such a case. Note that we don't need to persist this as we'll end up
/// setting it again as a side-effect of [`Channel::channel_reestablish`].
/// setting it again as a side-effect of [`FundedChannel::channel_reestablish`].
signer_pending_commitment_update: bool,
/// Similar to [`Self::signer_pending_commitment_update`] but we're waiting to send either a
/// [`msgs::FundingCreated`] or [`msgs::FundingSigned`] depending on if this channel is
Expand DownExpand Up@@ -1661,7 +1734,7 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for InboundV1Channel<SP> whe
}
}

impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for FundedChannel<SP> where SP::Target: SignerProvider {
fn context(&self) -> &ChannelContext<SP> {
&self.context
}
Expand DownExpand Up@@ -1928,7 +2001,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
if open_channel_fields.htlc_minimum_msat >= full_channel_value_msat {
return Err(ChannelError::close(format!("Minimum htlc value ({}) was larger than full channel value ({})", open_channel_fields.htlc_minimum_msat, full_channel_value_msat)));
}
Channel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;
FundedChannel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;

let max_counterparty_selected_contest_delay = u16::min(config.channel_handshake_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
if open_channel_fields.to_self_delay > max_counterparty_selected_contest_delay {
Expand DownExpand Up@@ -4211,7 +4284,7 @@ pub(super) struct DualFundingChannelContext {

// Holder designates channel data owned for the benefit of the user client.
// Counterparty designates channel data owned by the another channel participant entity.
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
pub context: ChannelContext<SP>,
pub interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
}
Expand DownExpand Up@@ -4281,7 +4354,7 @@ impl FailHTLCMessageName for msgs::UpdateFailMalformedHTLC {
}
}

impl<SP: Deref> Channel<SP> where
impl<SP: Deref> FundedChannel<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: EcdsaChannelSigner
{
Expand DownExpand Up@@ -6073,7 +6146,7 @@ impl<SP: Deref> Channel<SP> where
if self.context.channel_state.is_peer_disconnected() {
return Err(ChannelError::close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
}
Channel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;
FundedChannel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;

self.context.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced));
self.context.update_time_counter += 1;
Expand DownExpand Up@@ -8465,7 +8538,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
/// If this call is successful, broadcast the funding transaction (and not before!)
pub fn funding_signed<L: Deref>(
mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
) -> Result<(FundedChannel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
where
L::Target: Logger
{
Expand All@@ -8488,7 +8561,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {

log_info!(logger, "Received funding_signed from peer for channel {}", &self.context.channel_id());

let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8673,7 +8746,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

pub fn funding_created<L: Deref>(
mut self, msg: &msgs::FundingCreated, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
) -> Result<(FundedChannel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
where
L::Target: Logger
{
Expand DownExpand Up@@ -8713,7 +8786,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

// Promote the channel to a full-fledged one now that we have updated the state and have a
// `ChannelMonitor`.
let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8857,8 +8930,8 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
}
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9051,8 +9124,8 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
self.generate_accept_channel_v2_message()
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9143,7 +9216,7 @@ impl Readable for AnnouncementSigsState {
}
}

impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
// Note that we write out as if remove_uncommitted_htlcs_and_mark_paused had just been
// called.
Expand DownExpand Up@@ -9522,7 +9595,7 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
}

const MAX_ALLOC_SIZE: usize = 64*1024;
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for Channel<SP>
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for FundedChannel<SP>
where
ES::Target: EntropySource,
SP::Target: SignerProvider
Expand DownExpand Up@@ -9994,7 +10067,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
},
};

Ok(Channel {
Ok(FundedChannel {
context: ChannelContext {
user_id,

Expand DownExpand Up@@ -10151,7 +10224,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, Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_sat};
use crate::ln::channel::{AwaitingChannelReadyFlags, FundedChannel, ChannelState, 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 DownExpand Up@@ -10817,7 +10890,7 @@ mod tests {
let mut s = crate::io::Cursor::new(&encoded_chan);
let mut reader = crate::util::ser::FixedLengthReader::new(&mut s, encoded_chan.len() as u64);
let features = channelmanager::provided_channel_type_features(&config);
let decoded_chan = Channel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
let decoded_chan = FundedChannel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
assert_eq!(decoded_chan.context.pending_outbound_htlcs, pending_outbound_htlcs);
assert_eq!(decoded_chan.context.holding_cell_htlc_updates, holding_cell_htlc_updates);
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
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
117 changes: 95 additions & 22 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1132,14 +1132,15 @@ pub(super) enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
#[allow(dead_code)] // TODO(dual_funding): Remove once creating V2 channels is enabled.
UnfundedOutboundV2(OutboundV2Channel<SP>),
UnfundedInboundV2(InboundV2Channel<SP>),
Funded(Channel<SP>),
Funded(FundedChannel<SP>),
}

impl<'a, SP: Deref> ChannelPhase<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: ChannelSigner,
{
pub fn context(&'a self) -> &'a ChannelContext<SP> {
#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
match self {
ChannelPhase::Funded(chan) => &chan.context,
ChannelPhase::UnfundedOutboundV1(chan) => &chan.context,
Expand All@@ -1149,7 +1150,8 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

pub fn context_mut(&'a mut self) -> &'a mut ChannelContext<SP> {
#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
match self {
ChannelPhase::Funded(ref mut chan) => &mut chan.context,
ChannelPhase::UnfundedOutboundV1(ref mut chan) => &mut chan.context,
Expand All@@ -1160,6 +1162,77 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

/// A top-level channel struct, containing a channel phase
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
/// The inner channel phase
/// Option is used to facilitate in-place replacement (see e.g. move_v2_to_funded),
/// but it is never None, ensured in new() and set_phase()
phase: Option<ChannelPhase<SP>>,
Comment on lines +1167 to +1170

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment about moving ChannelContext here. Seems we shouldn't need to use an Option.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that logically it should not be Option, but I found no other way to transport the context from one phase to another. This may be Rust technicality. Option can be taken out and left empty, which is needed as I was not able to make the transfer in one atomic operation. Maybe another solution would be if ChannelContext had a default().

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would swap work?

}

impl<'a, SP: Deref> Channel<SP> where SP::Target: SignerProvider {
pub fn new(phase: ChannelPhase<SP>) -> Self {
Self {
phase: Some(phase),
}
}

#[inline]
pub fn phase(&self) -> &ChannelPhase<SP> {
self.phase.as_ref().unwrap()
}

#[inline]
pub fn phase_mut(&mut self) -> &mut ChannelPhase<SP> {
self.phase.as_mut().unwrap()
}

pub fn phase_take(self) -> ChannelPhase<SP> {
match self.phase {
Some(phase) => phase,
None => panic!("None phase"),
}
}

pub fn funded_channel(&self) -> Option<&FundedChannel<SP>> {
if let ChannelPhase::Funded(chan) = &self.phase.as_ref().unwrap() {
Some(chan)
} else {
None
}
}

/// Change the internal phase
#[inline]
pub fn set_phase(&mut self, new_phase: ChannelPhase<SP>) {
self.phase = Some(new_phase);
}

pub fn move_v2_to_funded(&mut self, signing_session: InteractiveTxSigningSession) -> Result<(), ChannelError> {
// We need a borrow to the phase field, but self is only a mut ref
let phase_inline = self.phase.take().unwrap();
let new_phase = match phase_inline {
ChannelPhase::UnfundedOutboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
ChannelPhase::UnfundedInboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
_ => phase_inline,
};
self.set_phase(new_phase);
Ok(())
}

#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
self.phase().context()
}

#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
self.phase_mut().context_mut()
}
}

/// Contains all state common to unfunded inbound/outbound channels.
pub(super) struct UnfundedChannelContext {
/// A counter tracking how many ticks have elapsed since this unfunded channel was
Expand DownExpand Up@@ -1270,7 +1343,7 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
/// the future when the signer indicates it may have a signature for us.
///
/// This flag is set in such a case. Note that we don't need to persist this as we'll end up
/// setting it again as a side-effect of [`Channel::channel_reestablish`].
/// setting it again as a side-effect of [`FundedChannel::channel_reestablish`].
signer_pending_commitment_update: bool,
/// Similar to [`Self::signer_pending_commitment_update`] but we're waiting to send either a
/// [`msgs::FundingCreated`] or [`msgs::FundingSigned`] depending on if this channel is
Expand DownExpand Up@@ -1661,7 +1734,7 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for InboundV1Channel<SP> whe
}
}

impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for FundedChannel<SP> where SP::Target: SignerProvider {
fn context(&self) -> &ChannelContext<SP> {
&self.context
}
Expand DownExpand Up@@ -1928,7 +2001,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
if open_channel_fields.htlc_minimum_msat >= full_channel_value_msat {
return Err(ChannelError::close(format!("Minimum htlc value ({}) was larger than full channel value ({})", open_channel_fields.htlc_minimum_msat, full_channel_value_msat)));
}
Channel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;
FundedChannel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;

let max_counterparty_selected_contest_delay = u16::min(config.channel_handshake_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
if open_channel_fields.to_self_delay > max_counterparty_selected_contest_delay {
Expand DownExpand Up@@ -4211,7 +4284,7 @@ pub(super) struct DualFundingChannelContext {

// Holder designates channel data owned for the benefit of the user client.
// Counterparty designates channel data owned by the another channel participant entity.
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
pub context: ChannelContext<SP>,
pub interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
}
Expand DownExpand Up@@ -4281,7 +4354,7 @@ impl FailHTLCMessageName for msgs::UpdateFailMalformedHTLC {
}
}

impl<SP: Deref> Channel<SP> where
impl<SP: Deref> FundedChannel<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: EcdsaChannelSigner
{
Expand DownExpand Up@@ -6073,7 +6146,7 @@ impl<SP: Deref> Channel<SP> where
if self.context.channel_state.is_peer_disconnected() {
return Err(ChannelError::close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
}
Channel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;
FundedChannel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;

self.context.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced));
self.context.update_time_counter += 1;
Expand DownExpand Up@@ -8465,7 +8538,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
/// If this call is successful, broadcast the funding transaction (and not before!)
pub fn funding_signed<L: Deref>(
mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
) -> Result<(FundedChannel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
where
L::Target: Logger
{
Expand All@@ -8488,7 +8561,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {

log_info!(logger, "Received funding_signed from peer for channel {}", &self.context.channel_id());

let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8673,7 +8746,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

pub fn funding_created<L: Deref>(
mut self, msg: &msgs::FundingCreated, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
) -> Result<(FundedChannel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
where
L::Target: Logger
{
Expand DownExpand Up@@ -8713,7 +8786,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

// Promote the channel to a full-fledged one now that we have updated the state and have a
// `ChannelMonitor`.
let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8857,8 +8930,8 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
}
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9051,8 +9124,8 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
self.generate_accept_channel_v2_message()
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9143,7 +9216,7 @@ impl Readable for AnnouncementSigsState {
}
}

impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
// Note that we write out as if remove_uncommitted_htlcs_and_mark_paused had just been
// called.
Expand DownExpand Up@@ -9522,7 +9595,7 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
}

const MAX_ALLOC_SIZE: usize = 64*1024;
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for Channel<SP>
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for FundedChannel<SP>
where
ES::Target: EntropySource,
SP::Target: SignerProvider
Expand DownExpand Up@@ -9994,7 +10067,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
},
};

Ok(Channel {
Ok(FundedChannel {
context: ChannelContext {
user_id,

Expand DownExpand Up@@ -10151,7 +10224,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, Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_sat};
use crate::ln::channel::{AwaitingChannelReadyFlags, FundedChannel, ChannelState, 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 DownExpand Up@@ -10817,7 +10890,7 @@ mod tests {
let mut s = crate::io::Cursor::new(&encoded_chan);
let mut reader = crate::util::ser::FixedLengthReader::new(&mut s, encoded_chan.len() as u64);
let features = channelmanager::provided_channel_type_features(&config);
let decoded_chan = Channel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
let decoded_chan = FundedChannel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
assert_eq!(decoded_chan.context.pending_outbound_htlcs, pending_outbound_htlcs);
assert_eq!(decoded_chan.context.holding_cell_htlc_updates, holding_cell_htlc_updates);
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
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
117 changes: 95 additions & 22 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1132,14 +1132,15 @@ pub(super) enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
#[allow(dead_code)] // TODO(dual_funding): Remove once creating V2 channels is enabled.
UnfundedOutboundV2(OutboundV2Channel<SP>),
UnfundedInboundV2(InboundV2Channel<SP>),
Funded(Channel<SP>),
Funded(FundedChannel<SP>),
}

impl<'a, SP: Deref> ChannelPhase<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: ChannelSigner,
{
pub fn context(&'a self) -> &'a ChannelContext<SP> {
#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
match self {
ChannelPhase::Funded(chan) => &chan.context,
ChannelPhase::UnfundedOutboundV1(chan) => &chan.context,
Expand All@@ -1149,7 +1150,8 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

pub fn context_mut(&'a mut self) -> &'a mut ChannelContext<SP> {
#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
match self {
ChannelPhase::Funded(ref mut chan) => &mut chan.context,
ChannelPhase::UnfundedOutboundV1(ref mut chan) => &mut chan.context,
Expand All@@ -1160,6 +1162,77 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

/// A top-level channel struct, containing a channel phase
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
/// The inner channel phase
/// Option is used to facilitate in-place replacement (see e.g. move_v2_to_funded),
/// but it is never None, ensured in new() and set_phase()
phase: Option<ChannelPhase<SP>>,
Comment on lines +1167 to +1170

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment about moving ChannelContext here. Seems we shouldn't need to use an Option.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that logically it should not be Option, but I found no other way to transport the context from one phase to another. This may be Rust technicality. Option can be taken out and left empty, which is needed as I was not able to make the transfer in one atomic operation. Maybe another solution would be if ChannelContext had a default().

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would swap work?

}

impl<'a, SP: Deref> Channel<SP> where SP::Target: SignerProvider {
pub fn new(phase: ChannelPhase<SP>) -> Self {
Self {
phase: Some(phase),
}
}

#[inline]
pub fn phase(&self) -> &ChannelPhase<SP> {
self.phase.as_ref().unwrap()
}

#[inline]
pub fn phase_mut(&mut self) -> &mut ChannelPhase<SP> {
self.phase.as_mut().unwrap()
}

pub fn phase_take(self) -> ChannelPhase<SP> {
match self.phase {
Some(phase) => phase,
None => panic!("None phase"),
}
}

pub fn funded_channel(&self) -> Option<&FundedChannel<SP>> {
if let ChannelPhase::Funded(chan) = &self.phase.as_ref().unwrap() {
Some(chan)
} else {
None
}
}

/// Change the internal phase
#[inline]
pub fn set_phase(&mut self, new_phase: ChannelPhase<SP>) {
self.phase = Some(new_phase);
}

pub fn move_v2_to_funded(&mut self, signing_session: InteractiveTxSigningSession) -> Result<(), ChannelError> {
// We need a borrow to the phase field, but self is only a mut ref
let phase_inline = self.phase.take().unwrap();
let new_phase = match phase_inline {
ChannelPhase::UnfundedOutboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
ChannelPhase::UnfundedInboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
_ => phase_inline,
};
self.set_phase(new_phase);
Ok(())
}

#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
self.phase().context()
}

#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
self.phase_mut().context_mut()
}
}

/// Contains all state common to unfunded inbound/outbound channels.
pub(super) struct UnfundedChannelContext {
/// A counter tracking how many ticks have elapsed since this unfunded channel was
Expand DownExpand Up@@ -1270,7 +1343,7 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
/// the future when the signer indicates it may have a signature for us.
///
/// This flag is set in such a case. Note that we don't need to persist this as we'll end up
/// setting it again as a side-effect of [`Channel::channel_reestablish`].
/// setting it again as a side-effect of [`FundedChannel::channel_reestablish`].
signer_pending_commitment_update: bool,
/// Similar to [`Self::signer_pending_commitment_update`] but we're waiting to send either a
/// [`msgs::FundingCreated`] or [`msgs::FundingSigned`] depending on if this channel is
Expand DownExpand Up@@ -1661,7 +1734,7 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for InboundV1Channel<SP> whe
}
}

impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for FundedChannel<SP> where SP::Target: SignerProvider {
fn context(&self) -> &ChannelContext<SP> {
&self.context
}
Expand DownExpand Up@@ -1928,7 +2001,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
if open_channel_fields.htlc_minimum_msat >= full_channel_value_msat {
return Err(ChannelError::close(format!("Minimum htlc value ({}) was larger than full channel value ({})", open_channel_fields.htlc_minimum_msat, full_channel_value_msat)));
}
Channel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;
FundedChannel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;

let max_counterparty_selected_contest_delay = u16::min(config.channel_handshake_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
if open_channel_fields.to_self_delay > max_counterparty_selected_contest_delay {
Expand DownExpand Up@@ -4211,7 +4284,7 @@ pub(super) struct DualFundingChannelContext {

// Holder designates channel data owned for the benefit of the user client.
// Counterparty designates channel data owned by the another channel participant entity.
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
pub context: ChannelContext<SP>,
pub interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
}
Expand DownExpand Up@@ -4281,7 +4354,7 @@ impl FailHTLCMessageName for msgs::UpdateFailMalformedHTLC {
}
}

impl<SP: Deref> Channel<SP> where
impl<SP: Deref> FundedChannel<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: EcdsaChannelSigner
{
Expand DownExpand Up@@ -6073,7 +6146,7 @@ impl<SP: Deref> Channel<SP> where
if self.context.channel_state.is_peer_disconnected() {
return Err(ChannelError::close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
}
Channel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;
FundedChannel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;

self.context.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced));
self.context.update_time_counter += 1;
Expand DownExpand Up@@ -8465,7 +8538,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
/// If this call is successful, broadcast the funding transaction (and not before!)
pub fn funding_signed<L: Deref>(
mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
) -> Result<(FundedChannel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
where
L::Target: Logger
{
Expand All@@ -8488,7 +8561,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {

log_info!(logger, "Received funding_signed from peer for channel {}", &self.context.channel_id());

let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8673,7 +8746,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

pub fn funding_created<L: Deref>(
mut self, msg: &msgs::FundingCreated, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
) -> Result<(FundedChannel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
where
L::Target: Logger
{
Expand DownExpand Up@@ -8713,7 +8786,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

// Promote the channel to a full-fledged one now that we have updated the state and have a
// `ChannelMonitor`.
let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8857,8 +8930,8 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
}
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9051,8 +9124,8 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
self.generate_accept_channel_v2_message()
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9143,7 +9216,7 @@ impl Readable for AnnouncementSigsState {
}
}

impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
// Note that we write out as if remove_uncommitted_htlcs_and_mark_paused had just been
// called.
Expand DownExpand Up@@ -9522,7 +9595,7 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
}

const MAX_ALLOC_SIZE: usize = 64*1024;
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for Channel<SP>
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for FundedChannel<SP>
where
ES::Target: EntropySource,
SP::Target: SignerProvider
Expand DownExpand Up@@ -9994,7 +10067,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
},
};

Ok(Channel {
Ok(FundedChannel {
context: ChannelContext {
user_id,

Expand DownExpand Up@@ -10151,7 +10224,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, Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_sat};
use crate::ln::channel::{AwaitingChannelReadyFlags, FundedChannel, ChannelState, 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 DownExpand Up@@ -10817,7 +10890,7 @@ mod tests {
let mut s = crate::io::Cursor::new(&encoded_chan);
let mut reader = crate::util::ser::FixedLengthReader::new(&mut s, encoded_chan.len() as u64);
let features = channelmanager::provided_channel_type_features(&config);
let decoded_chan = Channel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
let decoded_chan = FundedChannel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
assert_eq!(decoded_chan.context.pending_outbound_htlcs, pending_outbound_htlcs);
assert_eq!(decoded_chan.context.holding_cell_htlc_updates, holding_cell_htlc_updates);
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
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
117 changes: 95 additions & 22 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1132,14 +1132,15 @@ pub(super) enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
#[allow(dead_code)] // TODO(dual_funding): Remove once creating V2 channels is enabled.
UnfundedOutboundV2(OutboundV2Channel<SP>),
UnfundedInboundV2(InboundV2Channel<SP>),
Funded(Channel<SP>),
Funded(FundedChannel<SP>),
}

impl<'a, SP: Deref> ChannelPhase<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: ChannelSigner,
{
pub fn context(&'a self) -> &'a ChannelContext<SP> {
#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
match self {
ChannelPhase::Funded(chan) => &chan.context,
ChannelPhase::UnfundedOutboundV1(chan) => &chan.context,
Expand All@@ -1149,7 +1150,8 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

pub fn context_mut(&'a mut self) -> &'a mut ChannelContext<SP> {
#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
match self {
ChannelPhase::Funded(ref mut chan) => &mut chan.context,
ChannelPhase::UnfundedOutboundV1(ref mut chan) => &mut chan.context,
Expand All@@ -1160,6 +1162,77 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

/// A top-level channel struct, containing a channel phase
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
/// The inner channel phase
/// Option is used to facilitate in-place replacement (see e.g. move_v2_to_funded),
/// but it is never None, ensured in new() and set_phase()
phase: Option<ChannelPhase<SP>>,
Comment on lines +1167 to +1170

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment about moving ChannelContext here. Seems we shouldn't need to use an Option.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that logically it should not be Option, but I found no other way to transport the context from one phase to another. This may be Rust technicality. Option can be taken out and left empty, which is needed as I was not able to make the transfer in one atomic operation. Maybe another solution would be if ChannelContext had a default().

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would swap work?

}

impl<'a, SP: Deref> Channel<SP> where SP::Target: SignerProvider {
pub fn new(phase: ChannelPhase<SP>) -> Self {
Self {
phase: Some(phase),
}
}

#[inline]
pub fn phase(&self) -> &ChannelPhase<SP> {
self.phase.as_ref().unwrap()
}

#[inline]
pub fn phase_mut(&mut self) -> &mut ChannelPhase<SP> {
self.phase.as_mut().unwrap()
}

pub fn phase_take(self) -> ChannelPhase<SP> {
match self.phase {
Some(phase) => phase,
None => panic!("None phase"),
}
}

pub fn funded_channel(&self) -> Option<&FundedChannel<SP>> {
if let ChannelPhase::Funded(chan) = &self.phase.as_ref().unwrap() {
Some(chan)
} else {
None
}
}

/// Change the internal phase
#[inline]
pub fn set_phase(&mut self, new_phase: ChannelPhase<SP>) {
self.phase = Some(new_phase);
}

pub fn move_v2_to_funded(&mut self, signing_session: InteractiveTxSigningSession) -> Result<(), ChannelError> {
// We need a borrow to the phase field, but self is only a mut ref
let phase_inline = self.phase.take().unwrap();
let new_phase = match phase_inline {
ChannelPhase::UnfundedOutboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
ChannelPhase::UnfundedInboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
_ => phase_inline,
};
self.set_phase(new_phase);
Ok(())
}

#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
self.phase().context()
}

#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
self.phase_mut().context_mut()
}
}

/// Contains all state common to unfunded inbound/outbound channels.
pub(super) struct UnfundedChannelContext {
/// A counter tracking how many ticks have elapsed since this unfunded channel was
Expand DownExpand Up@@ -1270,7 +1343,7 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
/// the future when the signer indicates it may have a signature for us.
///
/// This flag is set in such a case. Note that we don't need to persist this as we'll end up
/// setting it again as a side-effect of [`Channel::channel_reestablish`].
/// setting it again as a side-effect of [`FundedChannel::channel_reestablish`].
signer_pending_commitment_update: bool,
/// Similar to [`Self::signer_pending_commitment_update`] but we're waiting to send either a
/// [`msgs::FundingCreated`] or [`msgs::FundingSigned`] depending on if this channel is
Expand DownExpand Up@@ -1661,7 +1734,7 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for InboundV1Channel<SP> whe
}
}

impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for FundedChannel<SP> where SP::Target: SignerProvider {
fn context(&self) -> &ChannelContext<SP> {
&self.context
}
Expand DownExpand Up@@ -1928,7 +2001,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
if open_channel_fields.htlc_minimum_msat >= full_channel_value_msat {
return Err(ChannelError::close(format!("Minimum htlc value ({}) was larger than full channel value ({})", open_channel_fields.htlc_minimum_msat, full_channel_value_msat)));
}
Channel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;
FundedChannel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;

let max_counterparty_selected_contest_delay = u16::min(config.channel_handshake_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
if open_channel_fields.to_self_delay > max_counterparty_selected_contest_delay {
Expand DownExpand Up@@ -4211,7 +4284,7 @@ pub(super) struct DualFundingChannelContext {

// Holder designates channel data owned for the benefit of the user client.
// Counterparty designates channel data owned by the another channel participant entity.
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
pub context: ChannelContext<SP>,
pub interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
}
Expand DownExpand Up@@ -4281,7 +4354,7 @@ impl FailHTLCMessageName for msgs::UpdateFailMalformedHTLC {
}
}

impl<SP: Deref> Channel<SP> where
impl<SP: Deref> FundedChannel<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: EcdsaChannelSigner
{
Expand DownExpand Up@@ -6073,7 +6146,7 @@ impl<SP: Deref> Channel<SP> where
if self.context.channel_state.is_peer_disconnected() {
return Err(ChannelError::close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
}
Channel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;
FundedChannel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;

self.context.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced));
self.context.update_time_counter += 1;
Expand DownExpand Up@@ -8465,7 +8538,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
/// If this call is successful, broadcast the funding transaction (and not before!)
pub fn funding_signed<L: Deref>(
mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
) -> Result<(FundedChannel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
where
L::Target: Logger
{
Expand All@@ -8488,7 +8561,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {

log_info!(logger, "Received funding_signed from peer for channel {}", &self.context.channel_id());

let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8673,7 +8746,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

pub fn funding_created<L: Deref>(
mut self, msg: &msgs::FundingCreated, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
) -> Result<(FundedChannel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
where
L::Target: Logger
{
Expand DownExpand Up@@ -8713,7 +8786,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

// Promote the channel to a full-fledged one now that we have updated the state and have a
// `ChannelMonitor`.
let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8857,8 +8930,8 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
}
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9051,8 +9124,8 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
self.generate_accept_channel_v2_message()
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9143,7 +9216,7 @@ impl Readable for AnnouncementSigsState {
}
}

impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
// Note that we write out as if remove_uncommitted_htlcs_and_mark_paused had just been
// called.
Expand DownExpand Up@@ -9522,7 +9595,7 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
}

const MAX_ALLOC_SIZE: usize = 64*1024;
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for Channel<SP>
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for FundedChannel<SP>
where
ES::Target: EntropySource,
SP::Target: SignerProvider
Expand DownExpand Up@@ -9994,7 +10067,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
},
};

Ok(Channel {
Ok(FundedChannel {
context: ChannelContext {
user_id,

Expand DownExpand Up@@ -10151,7 +10224,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, Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_sat};
use crate::ln::channel::{AwaitingChannelReadyFlags, FundedChannel, ChannelState, 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 DownExpand Up@@ -10817,7 +10890,7 @@ mod tests {
let mut s = crate::io::Cursor::new(&encoded_chan);
let mut reader = crate::util::ser::FixedLengthReader::new(&mut s, encoded_chan.len() as u64);
let features = channelmanager::provided_channel_type_features(&config);
let decoded_chan = Channel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
let decoded_chan = FundedChannel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
assert_eq!(decoded_chan.context.pending_outbound_htlcs, pending_outbound_htlcs);
assert_eq!(decoded_chan.context.holding_cell_htlc_updates, holding_cell_htlc_updates);
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
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
117 changes: 95 additions & 22 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1132,14 +1132,15 @@ pub(super) enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
#[allow(dead_code)] // TODO(dual_funding): Remove once creating V2 channels is enabled.
UnfundedOutboundV2(OutboundV2Channel<SP>),
UnfundedInboundV2(InboundV2Channel<SP>),
Funded(Channel<SP>),
Funded(FundedChannel<SP>),
}

impl<'a, SP: Deref> ChannelPhase<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: ChannelSigner,
{
pub fn context(&'a self) -> &'a ChannelContext<SP> {
#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
match self {
ChannelPhase::Funded(chan) => &chan.context,
ChannelPhase::UnfundedOutboundV1(chan) => &chan.context,
Expand All@@ -1149,7 +1150,8 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

pub fn context_mut(&'a mut self) -> &'a mut ChannelContext<SP> {
#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
match self {
ChannelPhase::Funded(ref mut chan) => &mut chan.context,
ChannelPhase::UnfundedOutboundV1(ref mut chan) => &mut chan.context,
Expand All@@ -1160,6 +1162,77 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
}
}

/// A top-level channel struct, containing a channel phase
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
/// The inner channel phase
/// Option is used to facilitate in-place replacement (see e.g. move_v2_to_funded),
/// but it is never None, ensured in new() and set_phase()
phase: Option<ChannelPhase<SP>>,
Comment on lines +1167 to +1170

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment about moving ChannelContext here. Seems we shouldn't need to use an Option.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that logically it should not be Option, but I found no other way to transport the context from one phase to another. This may be Rust technicality. Option can be taken out and left empty, which is needed as I was not able to make the transfer in one atomic operation. Maybe another solution would be if ChannelContext had a default().

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would swap work?

}

impl<'a, SP: Deref> Channel<SP> where SP::Target: SignerProvider {
pub fn new(phase: ChannelPhase<SP>) -> Self {
Self {
phase: Some(phase),
}
}

#[inline]
pub fn phase(&self) -> &ChannelPhase<SP> {
self.phase.as_ref().unwrap()
}

#[inline]
pub fn phase_mut(&mut self) -> &mut ChannelPhase<SP> {
self.phase.as_mut().unwrap()
}

pub fn phase_take(self) -> ChannelPhase<SP> {
match self.phase {
Some(phase) => phase,
None => panic!("None phase"),
}
}

pub fn funded_channel(&self) -> Option<&FundedChannel<SP>> {
if let ChannelPhase::Funded(chan) = &self.phase.as_ref().unwrap() {
Some(chan)
} else {
None
}
}

/// Change the internal phase
#[inline]
pub fn set_phase(&mut self, new_phase: ChannelPhase<SP>) {
self.phase = Some(new_phase);
}

pub fn move_v2_to_funded(&mut self, signing_session: InteractiveTxSigningSession) -> Result<(), ChannelError> {
// We need a borrow to the phase field, but self is only a mut ref
let phase_inline = self.phase.take().unwrap();
let new_phase = match phase_inline {
ChannelPhase::UnfundedOutboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
ChannelPhase::UnfundedInboundV2(chan) =>
ChannelPhase::Funded(chan.into_funded_channel(signing_session)?),
_ => phase_inline,
};
self.set_phase(new_phase);
Ok(())
}

#[inline]
pub fn context(&self) -> &ChannelContext<SP> {
self.phase().context()
}

#[inline]
pub fn context_mut(&mut self) -> &mut ChannelContext<SP> {
self.phase_mut().context_mut()
}
}

/// Contains all state common to unfunded inbound/outbound channels.
pub(super) struct UnfundedChannelContext {
/// A counter tracking how many ticks have elapsed since this unfunded channel was
Expand DownExpand Up@@ -1270,7 +1343,7 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
/// the future when the signer indicates it may have a signature for us.
///
/// This flag is set in such a case. Note that we don't need to persist this as we'll end up
/// setting it again as a side-effect of [`Channel::channel_reestablish`].
/// setting it again as a side-effect of [`FundedChannel::channel_reestablish`].
signer_pending_commitment_update: bool,
/// Similar to [`Self::signer_pending_commitment_update`] but we're waiting to send either a
/// [`msgs::FundingCreated`] or [`msgs::FundingSigned`] depending on if this channel is
Expand DownExpand Up@@ -1661,7 +1734,7 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for InboundV1Channel<SP> whe
}
}

impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for FundedChannel<SP> where SP::Target: SignerProvider {
fn context(&self) -> &ChannelContext<SP> {
&self.context
}
Expand DownExpand Up@@ -1928,7 +2001,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
if open_channel_fields.htlc_minimum_msat >= full_channel_value_msat {
return Err(ChannelError::close(format!("Minimum htlc value ({}) was larger than full channel value ({})", open_channel_fields.htlc_minimum_msat, full_channel_value_msat)));
}
Channel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;
FundedChannel::<SP>::check_remote_fee(&channel_type, fee_estimator, open_channel_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;

let max_counterparty_selected_contest_delay = u16::min(config.channel_handshake_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
if open_channel_fields.to_self_delay > max_counterparty_selected_contest_delay {
Expand DownExpand Up@@ -4211,7 +4284,7 @@ pub(super) struct DualFundingChannelContext {

// Holder designates channel data owned for the benefit of the user client.
// Counterparty designates channel data owned by the another channel participant entity.
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
pub context: ChannelContext<SP>,
pub interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
}
Expand DownExpand Up@@ -4281,7 +4354,7 @@ impl FailHTLCMessageName for msgs::UpdateFailMalformedHTLC {
}
}

impl<SP: Deref> Channel<SP> where
impl<SP: Deref> FundedChannel<SP> where
SP::Target: SignerProvider,
<SP::Target as SignerProvider>::EcdsaSigner: EcdsaChannelSigner
{
Expand DownExpand Up@@ -6073,7 +6146,7 @@ impl<SP: Deref> Channel<SP> where
if self.context.channel_state.is_peer_disconnected() {
return Err(ChannelError::close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
}
Channel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;
FundedChannel::<SP>::check_remote_fee(&self.context.channel_type, fee_estimator, msg.feerate_per_kw, Some(self.context.feerate_per_kw), logger)?;

self.context.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced));
self.context.update_time_counter += 1;
Expand DownExpand Up@@ -8465,7 +8538,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
/// If this call is successful, broadcast the funding transaction (and not before!)
pub fn funding_signed<L: Deref>(
mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
) -> Result<(FundedChannel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (OutboundV1Channel<SP>, ChannelError)>
where
L::Target: Logger
{
Expand All@@ -8488,7 +8561,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {

log_info!(logger, "Received funding_signed from peer for channel {}", &self.context.channel_id());

let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8673,7 +8746,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

pub fn funding_created<L: Deref>(
mut self, msg: &msgs::FundingCreated, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(Channel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
) -> Result<(FundedChannel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), (Self, ChannelError)>
where
L::Target: Logger
{
Expand DownExpand Up@@ -8713,7 +8786,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {

// Promote the channel to a full-fledged one now that we have updated the state and have a
// `ChannelMonitor`.
let mut channel = Channel {
let mut channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: None,
};
Expand DownExpand Up@@ -8857,8 +8930,8 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
}
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9051,8 +9124,8 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
self.generate_accept_channel_v2_message()
}

pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
let channel = Channel {
pub fn into_funded_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
let channel = FundedChannel {
context: self.context,
interactive_tx_signing_session: Some(signing_session),
};
Expand DownExpand Up@@ -9143,7 +9216,7 @@ impl Readable for AnnouncementSigsState {
}
}

impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
// Note that we write out as if remove_uncommitted_htlcs_and_mark_paused had just been
// called.
Expand DownExpand Up@@ -9522,7 +9595,7 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
}

const MAX_ALLOC_SIZE: usize = 64*1024;
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for Channel<SP>
impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for FundedChannel<SP>
where
ES::Target: EntropySource,
SP::Target: SignerProvider
Expand DownExpand Up@@ -9994,7 +10067,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
},
};

Ok(Channel {
Ok(FundedChannel {
context: ChannelContext {
user_id,

Expand DownExpand Up@@ -10151,7 +10224,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, Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_sat};
use crate::ln::channel::{AwaitingChannelReadyFlags, FundedChannel, ChannelState, 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 DownExpand Up@@ -10817,7 +10890,7 @@ mod tests {
let mut s = crate::io::Cursor::new(&encoded_chan);
let mut reader = crate::util::ser::FixedLengthReader::new(&mut s, encoded_chan.len() as u64);
let features = channelmanager::provided_channel_type_features(&config);
let decoded_chan = Channel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
let decoded_chan = FundedChannel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
assert_eq!(decoded_chan.context.pending_outbound_htlcs, pending_outbound_htlcs);
assert_eq!(decoded_chan.context.holding_cell_htlc_updates, holding_cell_htlc_updates);
}
Expand Down
Loading