Skip to content

Commit af79dac

Browse files
committed
Add holder commitment point to channel and unfunded context
We are choosing to move the `HolderCommitmentPoint` (the struct that tracks commitment points retrieved from the signer + the commitment number) to handle channel establishment, where we have no commitment point at all. Previously we introduced this struct to track when we were pending a commitment point (because of an async signer) during normal channel operation, which assumed we always had a commitment point to start out with. Intiially we tried to add an `Uninitialized` variant that held no points, but that meant that we needed to handle that case everywhere which left a bunch of scary/unnecessary unwraps/expects. Instead, we just hold an optional `HolderCommitmentPoint` struct on our unfunded channels, and a non-optional `HolderCommitmentPoint` for funded channels. This commit starts that transition. A following commit will remove the holder commitment point from the current `ChannelContext`. This also makes small fixups to the comments on the HolderCommitmentPoint variants.
1 parent ba3d4ff commit af79dac

File tree

1 file changed

+117
-82
lines changed

1 file changed

+117
-82
lines changed

lightning/src/ln/channel.rs

Lines changed: 117 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -954,29 +954,27 @@ pub(crate) struct ShutdownResult {
954954
/// commitment points from our signer.
955955
#[derive(Debug, Copy, Clone)]
956956
enum HolderCommitmentPoint {
957-
// TODO: add a variant for before our first commitment point is retrieved
958957
/// We've advanced our commitment number and are waiting on the next commitment point.
959-
/// Until the `get_per_commitment_point` signer method becomes async, this variant
960-
/// will not be used.
958+
///
959+
/// We should retry advancing to `Available` via `try_resolve_pending` once our
960+
/// signer is ready to provide the next commitment point.
961961
PendingNext { transaction_number: u64, current: PublicKey },
962-
/// Our current commitment point is ready, we've cached our next point,
963-
/// and we are not pending a new one.
962+
/// Our current commitment point is ready and we've cached our next point.
964963
Available { transaction_number: u64, current: PublicKey, next: PublicKey },
965964
}
966965

967966
impl HolderCommitmentPoint {
968-
pub fn new<SP: Deref>(signer: &ChannelSignerType<SP>, secp_ctx: &Secp256k1<secp256k1::All>) -> Self
967+
pub fn new<SP: Deref>(signer: &ChannelSignerType<SP>, secp_ctx: &Secp256k1<secp256k1::All>) -> Option<Self>
969968
where SP::Target: SignerProvider
970969
{
971-
HolderCommitmentPoint::Available {
972-
transaction_number: INITIAL_COMMITMENT_NUMBER,
973-
// TODO(async_signing): remove this expect with the Uninitialized variant
974-
current: signer.as_ref().get_per_commitment_point(INITIAL_COMMITMENT_NUMBER, secp_ctx)
975-
.expect("Signer must be able to provide initial commitment point"),
976-
// TODO(async_signing): remove this expect with the Uninitialized variant
977-
next: signer.as_ref().get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - 1, secp_ctx)
978-
.expect("Signer must be able to provide second commitment point"),
979-
}
970+
let current = signer.as_ref().get_per_commitment_point(INITIAL_COMMITMENT_NUMBER, secp_ctx).ok()?;
971+
let next = signer.as_ref().get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - 1, secp_ctx).ok();
972+
let point = if let Some(next) = next {
973+
HolderCommitmentPoint::Available { transaction_number: INITIAL_COMMITMENT_NUMBER, current, next }
974+
} else {
975+
HolderCommitmentPoint::PendingNext { transaction_number: INITIAL_COMMITMENT_NUMBER, current }
976+
};
977+
Some(point)
980978
}
981979

982980
pub fn is_available(&self) -> bool {
@@ -1169,6 +1167,8 @@ pub(super) struct UnfundedChannelContext {
11691167
/// This is so that we don't keep channels around that haven't progressed to a funded state
11701168
/// in a timely manner.
11711169
unfunded_channel_age_ticks: usize,
1170+
/// Tracks the commitment number and commitment point before the channel is funded.
1171+
holder_commitment_point: Option<HolderCommitmentPoint>,
11721172
}
11731173

11741174
impl UnfundedChannelContext {
@@ -1180,6 +1180,11 @@ impl UnfundedChannelContext {
11801180
self.unfunded_channel_age_ticks += 1;
11811181
self.unfunded_channel_age_ticks >= UNFUNDED_CHANNEL_AGE_LIMIT_TICKS
11821182
}
1183+
1184+
fn transaction_number(&self) -> u64 {
1185+
self.holder_commitment_point.as_ref().map(|point| point.transaction_number())
1186+
.unwrap_or(INITIAL_COMMITMENT_NUMBER)
1187+
}
11831188
}
11841189

11851190
/// Contains everything about the channel including state, and various flags.
@@ -1501,7 +1506,7 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
15011506
// The `next_funding_txid` field allows peers to finalize the signing steps of an interactive
15021507
// transaction construction, or safely abort that transaction if it was not signed by one of the
15031508
// peers, who has thus already removed it from its state.
1504-
//
1509+
//
15051510
// If we've sent `commtiment_signed` for an interactively constructed transaction
15061511
// during a signing session, but have not received `tx_signatures` we MUST set `next_funding_txid`
15071512
// to the txid of that interactive transaction, else we MUST NOT set it.
@@ -2058,7 +2063,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
20582063
let value_to_self_msat = our_funding_satoshis * 1000 + msg_push_msat;
20592064

20602065
let holder_signer = ChannelSignerType::Ecdsa(holder_signer);
2061-
let holder_commitment_point = HolderCommitmentPoint::new(&holder_signer, &secp_ctx);
2066+
// Unwrap here since it gets removed in the next commit
2067+
let holder_commitment_point = HolderCommitmentPoint::new(&holder_signer, &secp_ctx).unwrap();
20622068

20632069
// TODO(dual_funding): Checks for `funding_feerate_sat_per_1000_weight`?
20642070

@@ -2297,7 +2303,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
22972303
let temporary_channel_id = temporary_channel_id.unwrap_or_else(|| ChannelId::temporary_from_entropy_source(entropy_source));
22982304

22992305
let holder_signer = ChannelSignerType::Ecdsa(holder_signer);
2300-
let holder_commitment_point = HolderCommitmentPoint::new(&holder_signer, &secp_ctx);
2306+
// Unwrap here since it gets removed in the next commit
2307+
let holder_commitment_point = HolderCommitmentPoint::new(&holder_signer, &secp_ctx).unwrap();
23012308

23022309
Ok(Self {
23032310
user_id,
@@ -4206,6 +4213,7 @@ pub(super) struct DualFundingChannelContext {
42064213
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
42074214
pub context: ChannelContext<SP>,
42084215
pub interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
4216+
holder_commitment_point: HolderCommitmentPoint,
42094217
}
42104218

42114219
#[cfg(any(test, fuzzing))]
@@ -8267,28 +8275,31 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
82678275
let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id);
82688276
let pubkeys = holder_signer.pubkeys().clone();
82698277

8270-
let chan = Self {
8271-
context: ChannelContext::new_for_outbound_channel(
8272-
fee_estimator,
8273-
entropy_source,
8274-
signer_provider,
8275-
counterparty_node_id,
8276-
their_features,
8277-
channel_value_satoshis,
8278-
push_msat,
8279-
user_id,
8280-
config,
8281-
current_chain_height,
8282-
outbound_scid_alias,
8283-
temporary_channel_id,
8284-
holder_selected_channel_reserve_satoshis,
8285-
channel_keys_id,
8286-
holder_signer,
8287-
pubkeys,
8288-
logger,
8289-
)?,
8290-
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
8278+
let context = ChannelContext::new_for_outbound_channel(
8279+
fee_estimator,
8280+
entropy_source,
8281+
signer_provider,
8282+
counterparty_node_id,
8283+
their_features,
8284+
channel_value_satoshis,
8285+
push_msat,
8286+
user_id,
8287+
config,
8288+
current_chain_height,
8289+
outbound_scid_alias,
8290+
temporary_channel_id,
8291+
holder_selected_channel_reserve_satoshis,
8292+
channel_keys_id,
8293+
holder_signer,
8294+
pubkeys,
8295+
logger,
8296+
)?;
8297+
let unfunded_context = UnfundedChannelContext {
8298+
unfunded_channel_age_ticks: 0,
8299+
holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
82918300
};
8301+
8302+
let chan = Self { context, unfunded_context };
82928303
Ok(chan)
82938304
}
82948305

@@ -8480,9 +8491,11 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
84808491

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

8494+
let holder_commitment_point = self.context.holder_commitment_point;
84838495
let mut channel = Channel {
84848496
context: self.context,
84858497
interactive_tx_signing_session: None,
8498+
holder_commitment_point,
84868499
};
84878500

84888501
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some();
@@ -8570,29 +8583,31 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
85708583
htlc_basepoint: HtlcBasepoint::from(msg.common_fields.htlc_basepoint)
85718584
};
85728585

8573-
let chan = Self {
8574-
context: ChannelContext::new_for_inbound_channel(
8575-
fee_estimator,
8576-
entropy_source,
8577-
signer_provider,
8578-
counterparty_node_id,
8579-
their_features,
8580-
user_id,
8581-
config,
8582-
current_chain_height,
8583-
&&logger,
8584-
is_0conf,
8585-
0,
8586-
8587-
counterparty_pubkeys,
8588-
channel_type,
8589-
holder_selected_channel_reserve_satoshis,
8590-
msg.channel_reserve_satoshis,
8591-
msg.push_msat,
8592-
msg.common_fields.clone(),
8593-
)?,
8594-
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
8586+
let context = ChannelContext::new_for_inbound_channel(
8587+
fee_estimator,
8588+
entropy_source,
8589+
signer_provider,
8590+
counterparty_node_id,
8591+
their_features,
8592+
user_id,
8593+
config,
8594+
current_chain_height,
8595+
&&logger,
8596+
is_0conf,
8597+
0,
8598+
8599+
counterparty_pubkeys,
8600+
channel_type,
8601+
holder_selected_channel_reserve_satoshis,
8602+
msg.channel_reserve_satoshis,
8603+
msg.push_msat,
8604+
msg.common_fields.clone(),
8605+
)?;
8606+
let unfunded_context = UnfundedChannelContext {
8607+
unfunded_channel_age_ticks: 0,
8608+
holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
85958609
};
8610+
let chan = Self { context, unfunded_context };
85968611
Ok(chan)
85978612
}
85988613

@@ -8705,9 +8720,11 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
87058720

87068721
// Promote the channel to a full-fledged one now that we have updated the state and have a
87078722
// `ChannelMonitor`.
8723+
let holder_commitment_point = self.context.holder_commitment_point;
87088724
let mut channel = Channel {
87098725
context: self.context,
87108726
interactive_tx_signing_session: None,
8727+
holder_commitment_point,
87118728
};
87128729
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some();
87138730
channel.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
@@ -8754,27 +8771,32 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
87548771
"Provided current chain height of {} doesn't make sense for a height-based timelock for the funding transaction",
87558772
current_chain_height) })?;
87568773

8774+
let context = ChannelContext::new_for_outbound_channel(
8775+
fee_estimator,
8776+
entropy_source,
8777+
signer_provider,
8778+
counterparty_node_id,
8779+
their_features,
8780+
funding_satoshis,
8781+
0,
8782+
user_id,
8783+
config,
8784+
current_chain_height,
8785+
outbound_scid_alias,
8786+
temporary_channel_id,
8787+
holder_selected_channel_reserve_satoshis,
8788+
channel_keys_id,
8789+
holder_signer,
8790+
pubkeys,
8791+
logger,
8792+
)?;
8793+
let unfunded_context = UnfundedChannelContext {
8794+
unfunded_channel_age_ticks: 0,
8795+
holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
8796+
};
87578797
let chan = Self {
8758-
context: ChannelContext::new_for_outbound_channel(
8759-
fee_estimator,
8760-
entropy_source,
8761-
signer_provider,
8762-
counterparty_node_id,
8763-
their_features,
8764-
funding_satoshis,
8765-
0,
8766-
user_id,
8767-
config,
8768-
current_chain_height,
8769-
outbound_scid_alias,
8770-
temporary_channel_id,
8771-
holder_selected_channel_reserve_satoshis,
8772-
channel_keys_id,
8773-
holder_signer,
8774-
pubkeys,
8775-
logger,
8776-
)?,
8777-
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
8798+
context,
8799+
unfunded_context,
87788800
dual_funding_context: DualFundingChannelContext {
87798801
our_funding_satoshis: funding_satoshis,
87808802
funding_tx_locktime,
@@ -8850,9 +8872,13 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
88508872
}
88518873

88528874
pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
8875+
let holder_commitment_point = self.unfunded_context.holder_commitment_point.ok_or(ChannelError::close(
8876+
format!("Expected to have holder commitment points available upon finishing interactive tx construction for channel {}",
8877+
self.context.channel_id())))?;
88538878
let channel = Channel {
88548879
context: self.context,
88558880
interactive_tx_signing_session: Some(signing_session),
8881+
holder_commitment_point,
88568882
};
88578883

88588884
Ok(channel)
@@ -8963,11 +8989,15 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
89638989
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) }
89648990
)))?);
89658991

8992+
let unfunded_context = UnfundedChannelContext {
8993+
unfunded_channel_age_ticks: 0,
8994+
holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
8995+
};
89668996
Ok(Self {
89678997
context,
89688998
dual_funding_context,
89698999
interactive_tx_constructor,
8970-
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
9000+
unfunded_context,
89719001
})
89729002
}
89739003

@@ -9044,9 +9074,13 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
90449074
}
90459075

90469076
pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<Channel<SP>, ChannelError>{
9077+
let holder_commitment_point = self.unfunded_context.holder_commitment_point.ok_or(ChannelError::close(
9078+
format!("Expected to have holder commitment points available upon finishing interactive tx construction for channel {}",
9079+
self.context.channel_id())))?;
90479080
let channel = Channel {
90489081
context: self.context,
90499082
interactive_tx_signing_session: Some(signing_session),
9083+
holder_commitment_point,
90509084
};
90519085

90529086
Ok(channel)
@@ -10125,6 +10159,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
1012510159
next_funding_txid,
1012610160
},
1012710161
interactive_tx_signing_session: None,
10162+
holder_commitment_point,
1012810163
})
1012910164
}
1013010165
}

0 commit comments

Comments
 (0)