pub(crate) channel_funding_txo: Option<OutPoint>,
}
+/// Tracks the transaction number, along with current and next commitment points.
+/// This consolidates the logic to advance our commitment number and request new
+/// commitment points from our signer.
+#[derive(Debug, Copy, Clone)]
+enum HolderCommitmentPoint {
+ // TODO: add a variant for before our first commitment point is retrieved
+ /// We've advanced our commitment number and are waiting on the next commitment point.
+ /// Until the `get_per_commitment_point` signer method becomes async, this variant
+ /// will not be used.
+ PendingNext { transaction_number: u64, current: PublicKey },
+ /// Our current commitment point is ready, we've cached our next point,
+ /// and we are not pending a new one.
+ Available { transaction_number: u64, current: PublicKey, next: PublicKey },
+}
+
+impl HolderCommitmentPoint {
+ pub fn new<SP: Deref>(signer: &ChannelSignerType<SP>, secp_ctx: &Secp256k1<secp256k1::All>) -> Self
+ where SP::Target: SignerProvider
+ {
+ HolderCommitmentPoint::Available {
+ transaction_number: INITIAL_COMMITMENT_NUMBER,
+ current: signer.as_ref().get_per_commitment_point(INITIAL_COMMITMENT_NUMBER, secp_ctx),
+ next: signer.as_ref().get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - 1, secp_ctx),
+ }
+ }
+
+ pub fn is_available(&self) -> bool {
+ if let HolderCommitmentPoint::Available { .. } = self { true } else { false }
+ }
+
+ pub fn transaction_number(&self) -> u64 {
+ match self {
+ HolderCommitmentPoint::PendingNext { transaction_number, .. } => *transaction_number,
+ HolderCommitmentPoint::Available { transaction_number, .. } => *transaction_number,
+ }
+ }
+
+ pub fn current_point(&self) -> PublicKey {
+ match self {
+ HolderCommitmentPoint::PendingNext { current, .. } => *current,
+ HolderCommitmentPoint::Available { current, .. } => *current,
+ }
+ }
+
+ pub fn next_point(&self) -> Option<PublicKey> {
+ match self {
+ HolderCommitmentPoint::PendingNext { .. } => None,
+ HolderCommitmentPoint::Available { next, .. } => Some(*next),
+ }
+ }
+
+ pub fn advance<SP: Deref, L: Deref>(&mut self, signer: &ChannelSignerType<SP>, secp_ctx: &Secp256k1<secp256k1::All>, logger: &L)
+ where SP::Target: SignerProvider, L::Target: Logger
+ {
+ if let HolderCommitmentPoint::Available { transaction_number, next, .. } = self {
+ *self = HolderCommitmentPoint::PendingNext {
+ transaction_number: *transaction_number - 1,
+ current: *next,
+ };
+ }
+
+ if let HolderCommitmentPoint::PendingNext { transaction_number, current } = self {
+ let next = signer.as_ref().get_per_commitment_point(*transaction_number - 1, secp_ctx);
+ log_trace!(logger, "Retrieved next per-commitment point {}", *transaction_number - 1);
+ *self = HolderCommitmentPoint::Available { transaction_number: *transaction_number, current: *current, next };
+ }
+ }
+}
+
/// If the majority of the channels funds are to the fundee and the initiator holds only just
/// enough funds to cover their reserve value, channels are at risk of getting "stuck". Because the
/// initiator controls the feerate, if they then go to increase the channel fee, they may have no
// generation start at 0 and count up...this simplifies some parts of implementation at the
// cost of others, but should really just be changed.
- cur_holder_commitment_transaction_number: u64,
+ holder_commitment_point: HolderCommitmentPoint,
cur_counterparty_commitment_transaction_number: u64,
value_to_self_msat: u64, // Excluding all pending_htlcs, fees, and anchor outputs
pending_inbound_htlcs: Vec<InboundHTLCOutput>,
let value_to_self_msat = our_funding_satoshis * 1000 + msg_push_msat;
+ let holder_signer = ChannelSignerType::Ecdsa(holder_signer);
+ let holder_commitment_point = HolderCommitmentPoint::new(&holder_signer, &secp_ctx);
+
// TODO(dual_funding): Checks for `funding_feerate_sat_per_1000_weight`?
let channel_context = ChannelContext {
latest_monitor_update_id: 0,
- holder_signer: ChannelSignerType::Ecdsa(holder_signer),
+ holder_signer,
shutdown_scriptpubkey,
destination_script,
- cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
+ holder_commitment_point,
cur_counterparty_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
value_to_self_msat,
let temporary_channel_id = temporary_channel_id.unwrap_or_else(|| ChannelId::temporary_from_entropy_source(entropy_source));
+ let holder_signer = ChannelSignerType::Ecdsa(holder_signer);
+ let holder_commitment_point = HolderCommitmentPoint::new(&holder_signer, &secp_ctx);
+
Ok(Self {
user_id,
latest_monitor_update_id: 0,
- holder_signer: ChannelSignerType::Ecdsa(holder_signer),
+ holder_signer,
shutdown_scriptpubkey,
destination_script,
- cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
+ holder_commitment_point,
cur_counterparty_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
value_to_self_msat,
}
}
+ /// Performs checks against necessary constraints after receiving either an `accept_channel` or
+ /// `accept_channel2` message.
+ pub fn do_accept_channel_checks(
+ &mut self, default_limits: &ChannelHandshakeLimits, their_features: &InitFeatures,
+ common_fields: &msgs::CommonAcceptChannelFields, channel_reserve_satoshis: u64,
+ ) -> Result<(), ChannelError> {
+ let peer_limits = if let Some(ref limits) = self.inbound_handshake_limits_override { limits } else { default_limits };
+
+ // Check sanity of message fields:
+ if !self.is_outbound() {
+ return Err(ChannelError::close("Got an accept_channel message from an inbound peer".to_owned()));
+ }
+ if !matches!(self.channel_state, ChannelState::NegotiatingFunding(flags) if flags == NegotiatingFundingFlags::OUR_INIT_SENT) {
+ return Err(ChannelError::close("Got an accept_channel message at a strange time".to_owned()));
+ }
+ if common_fields.dust_limit_satoshis > 21000000 * 100000000 {
+ return Err(ChannelError::close(format!("Peer never wants payout outputs? dust_limit_satoshis was {}", common_fields.dust_limit_satoshis)));
+ }
+ if channel_reserve_satoshis > self.channel_value_satoshis {
+ return Err(ChannelError::close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than ({})", channel_reserve_satoshis, self.channel_value_satoshis)));
+ }
+ if common_fields.dust_limit_satoshis > self.holder_selected_channel_reserve_satoshis {
+ return Err(ChannelError::close(format!("Dust limit ({}) is bigger than our channel reserve ({})", common_fields.dust_limit_satoshis, self.holder_selected_channel_reserve_satoshis)));
+ }
+ if channel_reserve_satoshis > self.channel_value_satoshis - self.holder_selected_channel_reserve_satoshis {
+ return Err(ChannelError::close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than channel value minus our reserve ({})",
+ channel_reserve_satoshis, self.channel_value_satoshis - self.holder_selected_channel_reserve_satoshis)));
+ }
+ let full_channel_value_msat = (self.channel_value_satoshis - channel_reserve_satoshis) * 1000;
+ if common_fields.htlc_minimum_msat >= full_channel_value_msat {
+ return Err(ChannelError::close(format!("Minimum htlc value ({}) is full channel value ({})", common_fields.htlc_minimum_msat, full_channel_value_msat)));
+ }
+ let max_delay_acceptable = u16::min(peer_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
+ if common_fields.to_self_delay > max_delay_acceptable {
+ return Err(ChannelError::close(format!("They wanted our payments to be delayed by a needlessly long period. Upper limit: {}. Actual: {}", max_delay_acceptable, common_fields.to_self_delay)));
+ }
+ if common_fields.max_accepted_htlcs < 1 {
+ return Err(ChannelError::close("0 max_accepted_htlcs makes for a useless channel".to_owned()));
+ }
+ if common_fields.max_accepted_htlcs > MAX_HTLCS {
+ return Err(ChannelError::close(format!("max_accepted_htlcs was {}. It must not be larger than {}", common_fields.max_accepted_htlcs, MAX_HTLCS)));
+ }
+
+ // Now check against optional parameters as set by config...
+ if common_fields.htlc_minimum_msat > peer_limits.max_htlc_minimum_msat {
+ return Err(ChannelError::close(format!("htlc_minimum_msat ({}) is higher than the user specified limit ({})", common_fields.htlc_minimum_msat, peer_limits.max_htlc_minimum_msat)));
+ }
+ if common_fields.max_htlc_value_in_flight_msat < peer_limits.min_max_htlc_value_in_flight_msat {
+ return Err(ChannelError::close(format!("max_htlc_value_in_flight_msat ({}) is less than the user specified limit ({})", common_fields.max_htlc_value_in_flight_msat, peer_limits.min_max_htlc_value_in_flight_msat)));
+ }
+ if channel_reserve_satoshis > peer_limits.max_channel_reserve_satoshis {
+ return Err(ChannelError::close(format!("channel_reserve_satoshis ({}) is higher than the user specified limit ({})", channel_reserve_satoshis, peer_limits.max_channel_reserve_satoshis)));
+ }
+ if common_fields.max_accepted_htlcs < peer_limits.min_max_accepted_htlcs {
+ return Err(ChannelError::close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", common_fields.max_accepted_htlcs, peer_limits.min_max_accepted_htlcs)));
+ }
+ if common_fields.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
+ return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", common_fields.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
+ }
+ if common_fields.dust_limit_satoshis > MAX_CHAN_DUST_LIMIT_SATOSHIS {
+ return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is greater than the implementation limit ({})", common_fields.dust_limit_satoshis, MAX_CHAN_DUST_LIMIT_SATOSHIS)));
+ }
+ if common_fields.minimum_depth > peer_limits.max_minimum_depth {
+ return Err(ChannelError::close(format!("We consider the minimum depth to be unreasonably large. Expected minimum: ({}). Actual: ({})", peer_limits.max_minimum_depth, common_fields.minimum_depth)));
+ }
+
+ if let Some(ty) = &common_fields.channel_type {
+ if *ty != self.channel_type {
+ return Err(ChannelError::close("Channel Type in accept_channel didn't match the one sent in open_channel.".to_owned()));
+ }
+ } else if their_features.supports_channel_type() {
+ // Assume they've accepted the channel type as they said they understand it.
+ } else {
+ let channel_type = ChannelTypeFeatures::from_init(&their_features);
+ if channel_type != ChannelTypeFeatures::only_static_remote_key() {
+ return Err(ChannelError::close("Only static_remote_key is supported for non-negotiated channel types".to_owned()));
+ }
+ self.channel_type = channel_type.clone();
+ self.channel_transaction_parameters.channel_type_features = channel_type;
+ }
+
+ let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() {
+ match &common_fields.shutdown_scriptpubkey {
+ &Some(ref script) => {
+ // Peer is signaling upfront_shutdown and has opt-out with a 0-length script. We don't enforce anything
+ if script.len() == 0 {
+ None
+ } else {
+ if !script::is_bolt2_compliant(&script, their_features) {
+ return Err(ChannelError::close(format!("Peer is signaling upfront_shutdown but has provided an unacceptable scriptpubkey format: {}", script)));
+ }
+ Some(script.clone())
+ }
+ },
+ // Peer is signaling upfront shutdown but don't opt-out with correct mechanism (a.k.a 0-length script). Peer looks buggy, we fail the channel
+ &None => {
+ return Err(ChannelError::close("Peer is signaling upfront_shutdown but we don't get any script. Use 0-length script to opt-out".to_owned()));
+ }
+ }
+ } else { None };
+
+ self.counterparty_dust_limit_satoshis = common_fields.dust_limit_satoshis;
+ self.counterparty_max_htlc_value_in_flight_msat = cmp::min(common_fields.max_htlc_value_in_flight_msat, self.channel_value_satoshis * 1000);
+ self.counterparty_selected_channel_reserve_satoshis = Some(channel_reserve_satoshis);
+ self.counterparty_htlc_minimum_msat = common_fields.htlc_minimum_msat;
+ self.counterparty_max_accepted_htlcs = common_fields.max_accepted_htlcs;
+
+ if peer_limits.trust_own_funding_0conf {
+ self.minimum_depth = Some(common_fields.minimum_depth);
+ } else {
+ self.minimum_depth = Some(cmp::max(1, common_fields.minimum_depth));
+ }
+
+ let counterparty_pubkeys = ChannelPublicKeys {
+ funding_pubkey: common_fields.funding_pubkey,
+ revocation_basepoint: RevocationBasepoint::from(common_fields.revocation_basepoint),
+ payment_point: common_fields.payment_basepoint,
+ delayed_payment_basepoint: DelayedPaymentBasepoint::from(common_fields.delayed_payment_basepoint),
+ htlc_basepoint: HtlcBasepoint::from(common_fields.htlc_basepoint)
+ };
+
+ self.channel_transaction_parameters.counterparty_parameters = Some(CounterpartyChannelTransactionParameters {
+ selected_contest_delay: common_fields.to_self_delay,
+ pubkeys: counterparty_pubkeys,
+ });
+
+ self.counterparty_cur_commitment_point = Some(common_fields.first_per_commitment_point);
+ self.counterparty_shutdown_scriptpubkey = counterparty_shutdown_scriptpubkey;
+
+ self.channel_state = ChannelState::NegotiatingFunding(
+ NegotiatingFundingFlags::OUR_INIT_SENT | NegotiatingFundingFlags::THEIR_INIT_SENT
+ );
+ self.inbound_handshake_limits_override = None; // We're done enforcing limits on our peer's handshake now.
+
+ Ok(())
+ }
+
/// Returns the block hash in which our funding transaction was confirmed.
pub fn get_funding_tx_confirmed_in(&self) -> Option<BlockHash> {
self.funding_tx_confirmed_in
/// our counterparty!)
/// The result is a transaction which we can revoke broadcastership of (ie a "local" transaction)
/// TODO Some magic rust shit to compile-time check this?
- fn build_holder_transaction_keys(&self, commitment_number: u64) -> TxCreationKeys {
- let per_commitment_point = self.holder_signer.as_ref().get_per_commitment_point(commitment_number, &self.secp_ctx);
+ fn build_holder_transaction_keys(&self) -> TxCreationKeys {
+ let per_commitment_point = self.holder_commitment_point.current_point();
let delayed_payment_base = &self.get_holder_pubkeys().delayed_payment_basepoint;
let htlc_basepoint = &self.get_holder_pubkeys().htlc_basepoint;
let counterparty_pubkeys = self.get_counterparty_pubkeys();
let funding_script = self.context.get_funding_redeemscript();
- let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
+ let keys = self.context.build_holder_transaction_keys();
- let commitment_stats = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, false, logger);
+ let commitment_stats = self.context.build_commitment_transaction(self.context.holder_commitment_point.transaction_number(), &keys, true, false, logger);
let commitment_txid = {
let trusted_tx = commitment_stats.tx.trust();
let bitcoin_tx = trusted_tx.built_transaction();
channel_id: Some(self.context.channel_id()),
};
- self.context.cur_holder_commitment_transaction_number -= 1;
+ self.context.holder_commitment_point.advance(&self.context.holder_signer, &self.context.secp_ctx, logger);
self.context.expecting_peer_commitment_signed = false;
// Note that if we need_commitment & !AwaitingRemoteRevoke we'll call
// build_commitment_no_status_check() next which will reset this to RAAFirst.
// Before proposing a feerate update, check that we can actually afford the new fee.
let dust_exposure_limiting_feerate = self.context.get_dust_exposure_limiting_feerate(&fee_estimator);
let htlc_stats = self.context.get_pending_htlc_stats(Some(feerate_per_kw), dust_exposure_limiting_feerate);
- let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
- let commitment_stats = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, true, logger);
+ let keys = self.context.build_holder_transaction_keys();
+ let commitment_stats = self.context.build_commitment_transaction(self.context.holder_commitment_point.transaction_number(), &keys, true, true, logger);
let buffer_fee_msat = commit_tx_fee_sat(feerate_per_kw, commitment_stats.num_nondust_htlcs + htlc_stats.on_holder_tx_outbound_holding_cell_htlcs_count as usize + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize, self.context.get_channel_type()) * 1000;
let holder_balance_msat = commitment_stats.local_balance_msat - htlc_stats.outbound_holding_cell_msat;
if holder_balance_msat < buffer_fee_msat + self.context.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 {
assert!(!self.context.is_outbound() || self.context.minimum_depth == Some(0),
"Funding transaction broadcast by the local client before it should have - LDK didn't do it!");
self.context.monitor_pending_channel_ready = false;
- let next_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
- Some(msgs::ChannelReady {
- channel_id: self.context.channel_id(),
- next_per_commitment_point,
- short_channel_id_alias: Some(self.context.outbound_scid_alias),
- })
+ Some(self.get_channel_ready())
} else { None };
let announcement_sigs = self.get_announcement_sigs(node_signer, chain_hash, user_config, best_block_height, logger);
}
}
+ pub fn check_for_stale_feerate<L: Logger>(&mut self, logger: &L, min_feerate: u32) -> Result<(), ClosureReason> {
+ if self.context.is_outbound() {
+ // While its possible our fee is too low for an outbound channel because we've been
+ // unable to increase the fee, we don't try to force-close directly here.
+ return Ok(());
+ }
+ if self.context.feerate_per_kw < min_feerate {
+ log_info!(logger,
+ "Closing channel as feerate of {} is below required {} (the minimum required rate over the past day)",
+ self.context.feerate_per_kw, min_feerate
+ );
+ Err(ClosureReason::PeerFeerateTooLow {
+ peer_feerate_sat_per_kw: self.context.feerate_per_kw,
+ required_feerate_sat_per_kw: min_feerate,
+ })
+ } else {
+ Ok(())
+ }
+ }
+
pub fn update_fee<F: Deref, L: Deref>(&mut self, fee_estimator: &LowerBoundedFeeEstimator<F>, msg: &msgs::UpdateFee, logger: &L) -> Result<(), ChannelError>
where F::Target: FeeEstimator, L::Target: Logger
{
self.context.get_funding_signed_msg(logger).1
} else { None };
let channel_ready = if funding_signed.is_some() {
- self.check_get_channel_ready(0)
+ self.check_get_channel_ready(0, logger)
} else { None };
log_trace!(logger, "Signer unblocked with {} commitment_update, {} funding_signed and {} channel_ready",
}
fn get_last_revoke_and_ack(&self) -> msgs::RevokeAndACK {
- let next_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
- let per_commitment_secret = self.context.holder_signer.as_ref().release_commitment_secret(self.context.cur_holder_commitment_transaction_number + 2);
+ debug_assert!(self.context.holder_commitment_point.transaction_number() <= INITIAL_COMMITMENT_NUMBER + 2);
+ // TODO: handle non-available case when get_per_commitment_point becomes async
+ debug_assert!(self.context.holder_commitment_point.is_available());
+ let next_per_commitment_point = self.context.holder_commitment_point.current_point();
+ let per_commitment_secret = self.context.holder_signer.as_ref().release_commitment_secret(self.context.holder_commitment_point.transaction_number() + 2);
msgs::RevokeAndACK {
channel_id: self.context.channel_id,
per_commitment_secret,
return Err(ChannelError::close("Peer sent an invalid channel_reestablish to force close in a non-standard way".to_owned()));
}
- let our_commitment_transaction = INITIAL_COMMITMENT_NUMBER - self.context.cur_holder_commitment_transaction_number - 1;
+ let our_commitment_transaction = INITIAL_COMMITMENT_NUMBER - self.context.holder_commitment_point.transaction_number() - 1;
if msg.next_remote_commitment_number > 0 {
let expected_point = self.context.holder_signer.as_ref().get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - msg.next_remote_commitment_number + 1, &self.context.secp_ctx);
let given_secret = SecretKey::from_slice(&msg.your_last_per_commitment_secret)
}
// We have OurChannelReady set!
- let next_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
return Ok(ReestablishResponses {
- channel_ready: Some(msgs::ChannelReady {
- channel_id: self.context.channel_id(),
- next_per_commitment_point,
- short_channel_id_alias: Some(self.context.outbound_scid_alias),
- }),
+ channel_ready: Some(self.get_channel_ready()),
raa: None, commitment_update: None,
order: RAACommitmentOrder::CommitmentFirst,
shutdown_msg, announcement_sigs,
}
let next_counterparty_commitment_number = INITIAL_COMMITMENT_NUMBER - self.context.cur_counterparty_commitment_transaction_number + if is_awaiting_remote_revoke { 1 } else { 0 };
- let channel_ready = if msg.next_local_commitment_number == 1 && INITIAL_COMMITMENT_NUMBER - self.context.cur_holder_commitment_transaction_number == 1 {
+ let channel_ready = if msg.next_local_commitment_number == 1 && INITIAL_COMMITMENT_NUMBER - self.context.holder_commitment_point.transaction_number() == 1 {
// We should never have to worry about MonitorUpdateInProgress resending ChannelReady
- let next_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
- Some(msgs::ChannelReady {
- channel_id: self.context.channel_id(),
- next_per_commitment_point,
- short_channel_id_alias: Some(self.context.outbound_scid_alias),
- })
+ Some(self.get_channel_ready())
} else { None };
if msg.next_local_commitment_number == next_counterparty_commitment_number {
}
pub fn get_cur_holder_commitment_transaction_number(&self) -> u64 {
- self.context.cur_holder_commitment_transaction_number + 1
+ self.context.holder_commitment_point.transaction_number() + 1
}
pub fn get_cur_counterparty_commitment_transaction_number(&self) -> u64 {
debug_assert!(self.context.minimum_depth.unwrap_or(1) > 0);
return true;
}
- if self.context.cur_holder_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 &&
+ if self.context.holder_commitment_point.transaction_number() == INITIAL_COMMITMENT_NUMBER - 1 &&
self.context.cur_counterparty_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 {
// If we're a 0-conf channel, we'll move beyond AwaitingChannelReady immediately even while
// waiting for the initial monitor persistence. Thus, we check if our commitment
self.context.channel_update_status = status;
}
- fn check_get_channel_ready(&mut self, height: u32) -> Option<msgs::ChannelReady> {
+ fn check_get_channel_ready<L: Deref>(&mut self, height: u32, logger: &L) -> Option<msgs::ChannelReady>
+ where L::Target: Logger
+ {
// Called:
// * always when a new block/transactions are confirmed with the new height
// * when funding is signed with a height of 0
// If we're still pending the signature on a funding transaction, then we're not ready to send a
// channel_ready yet.
if self.context.signer_pending_funding {
+ // TODO: set signer_pending_channel_ready
+ log_debug!(logger, "Can't produce channel_ready: the signer is pending funding.");
return None;
}
false
};
- if need_commitment_update {
- if !self.context.channel_state.is_monitor_update_in_progress() {
- if !self.context.channel_state.is_peer_disconnected() {
- let next_per_commitment_point =
- self.context.holder_signer.as_ref().get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - 1, &self.context.secp_ctx);
- return Some(msgs::ChannelReady {
- channel_id: self.context.channel_id,
- next_per_commitment_point,
- short_channel_id_alias: Some(self.context.outbound_scid_alias),
- });
- }
- } else {
- self.context.monitor_pending_channel_ready = true;
- }
+ if !need_commitment_update {
+ log_debug!(logger, "Not producing channel_ready: we do not need a commitment update");
+ return None;
+ }
+
+ if self.context.channel_state.is_monitor_update_in_progress() {
+ log_debug!(logger, "Not producing channel_ready: a monitor update is in progress. Setting monitor_pending_channel_ready.");
+ self.context.monitor_pending_channel_ready = true;
+ return None;
+ }
+
+ if self.context.channel_state.is_peer_disconnected() {
+ log_debug!(logger, "Not producing channel_ready: the peer is disconnected.");
+ return None;
+ }
+
+ // TODO: when get_per_commiment_point becomes async, check if the point is
+ // available, if not, set signer_pending_channel_ready and return None
+
+ Some(self.get_channel_ready())
+ }
+
+ fn get_channel_ready(&self) -> msgs::ChannelReady {
+ debug_assert!(self.context.holder_commitment_point.is_available());
+ msgs::ChannelReady {
+ channel_id: self.context.channel_id(),
+ next_per_commitment_point: self.context.holder_commitment_point.current_point(),
+ short_channel_id_alias: Some(self.context.outbound_scid_alias),
}
- None
}
/// When a transaction is confirmed, we check whether it is or spends the funding transaction
// If we allow 1-conf funding, we may need to check for channel_ready here and
// send it immediately instead of waiting for a best_block_updated call (which
// may have already happened for this block).
- if let Some(channel_ready) = self.check_get_channel_ready(height) {
+ if let Some(channel_ready) = self.check_get_channel_ready(height, logger) {
log_info!(logger, "Sending a channel_ready to our peer for channel {}", &self.context.channel_id);
let announcement_sigs = self.get_announcement_sigs(node_signer, chain_hash, user_config, height, logger);
msgs = (Some(channel_ready), announcement_sigs);
self.context.update_time_counter = cmp::max(self.context.update_time_counter, highest_header_time);
- if let Some(channel_ready) = self.check_get_channel_ready(height) {
+ if let Some(channel_ready) = self.check_get_channel_ready(height, logger) {
let announcement_sigs = if let Some((chain_hash, node_signer, user_config)) = chain_node_signer {
self.get_announcement_sigs(node_signer, chain_hash, user_config, height, logger)
} else { None };
// next_local_commitment_number is the next commitment_signed number we expect to
// receive (indicating if they need to resend one that we missed).
- next_local_commitment_number: INITIAL_COMMITMENT_NUMBER - self.context.cur_holder_commitment_transaction_number,
+ next_local_commitment_number: INITIAL_COMMITMENT_NUMBER - self.context.holder_commitment_point.transaction_number(),
// We have to set next_remote_commitment_number to the next revoke_and_ack we expect to
// receive, however we track it by the next commitment number for a remote transaction
// (which is one further, as they always revoke previous commitment transaction, not
}
if self.context.commitment_secrets.get_min_seen_secret() != (1 << 48) ||
self.context.cur_counterparty_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER ||
- self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
+ self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
}
/// Returns true if we can resume the channel by sending the [`msgs::OpenChannel`] again.
pub fn is_resumable(&self) -> bool {
!self.context.have_received_message() &&
- self.context.cur_holder_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER
+ self.context.holder_commitment_point.transaction_number() == INITIAL_COMMITMENT_NUMBER
}
pub fn get_open_channel(&self, chain_hash: ChainHash) -> msgs::OpenChannel {
panic!("Cannot generate an open_channel after we've moved forward");
}
- if self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
+ if self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
panic!("Tried to send an open_channel for a channel that has already advanced");
}
- let first_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
+ debug_assert!(self.context.holder_commitment_point.is_available());
+ let first_per_commitment_point = self.context.holder_commitment_point.current_point();
let keys = self.context.get_holder_pubkeys();
msgs::OpenChannel {
}
// Message handlers
- pub fn accept_channel(&mut self, msg: &msgs::AcceptChannel, default_limits: &ChannelHandshakeLimits, their_features: &InitFeatures) -> Result<(), ChannelError> {
- let peer_limits = if let Some(ref limits) = self.context.inbound_handshake_limits_override { limits } else { default_limits };
-
- // Check sanity of message fields:
- if !self.context.is_outbound() {
- return Err(ChannelError::close("Got an accept_channel message from an inbound peer".to_owned()));
- }
- if !matches!(self.context.channel_state, ChannelState::NegotiatingFunding(flags) if flags == NegotiatingFundingFlags::OUR_INIT_SENT) {
- return Err(ChannelError::close("Got an accept_channel message at a strange time".to_owned()));
- }
- if msg.common_fields.dust_limit_satoshis > 21000000 * 100000000 {
- return Err(ChannelError::close(format!("Peer never wants payout outputs? dust_limit_satoshis was {}", msg.common_fields.dust_limit_satoshis)));
- }
- if msg.channel_reserve_satoshis > self.context.channel_value_satoshis {
- return Err(ChannelError::close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than ({})", msg.channel_reserve_satoshis, self.context.channel_value_satoshis)));
- }
- if msg.common_fields.dust_limit_satoshis > self.context.holder_selected_channel_reserve_satoshis {
- return Err(ChannelError::close(format!("Dust limit ({}) is bigger than our channel reserve ({})", msg.common_fields.dust_limit_satoshis, self.context.holder_selected_channel_reserve_satoshis)));
- }
- if msg.channel_reserve_satoshis > self.context.channel_value_satoshis - self.context.holder_selected_channel_reserve_satoshis {
- return Err(ChannelError::close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than channel value minus our reserve ({})",
- msg.channel_reserve_satoshis, self.context.channel_value_satoshis - self.context.holder_selected_channel_reserve_satoshis)));
- }
- let full_channel_value_msat = (self.context.channel_value_satoshis - msg.channel_reserve_satoshis) * 1000;
- if msg.common_fields.htlc_minimum_msat >= full_channel_value_msat {
- return Err(ChannelError::close(format!("Minimum htlc value ({}) is full channel value ({})", msg.common_fields.htlc_minimum_msat, full_channel_value_msat)));
- }
- let max_delay_acceptable = u16::min(peer_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
- if msg.common_fields.to_self_delay > max_delay_acceptable {
- return Err(ChannelError::close(format!("They wanted our payments to be delayed by a needlessly long period. Upper limit: {}. Actual: {}", max_delay_acceptable, msg.common_fields.to_self_delay)));
- }
- if msg.common_fields.max_accepted_htlcs < 1 {
- return Err(ChannelError::close("0 max_accepted_htlcs makes for a useless channel".to_owned()));
- }
- if msg.common_fields.max_accepted_htlcs > MAX_HTLCS {
- return Err(ChannelError::close(format!("max_accepted_htlcs was {}. It must not be larger than {}", msg.common_fields.max_accepted_htlcs, MAX_HTLCS)));
- }
-
- // Now check against optional parameters as set by config...
- if msg.common_fields.htlc_minimum_msat > peer_limits.max_htlc_minimum_msat {
- return Err(ChannelError::close(format!("htlc_minimum_msat ({}) is higher than the user specified limit ({})", msg.common_fields.htlc_minimum_msat, peer_limits.max_htlc_minimum_msat)));
- }
- if msg.common_fields.max_htlc_value_in_flight_msat < peer_limits.min_max_htlc_value_in_flight_msat {
- return Err(ChannelError::close(format!("max_htlc_value_in_flight_msat ({}) is less than the user specified limit ({})", msg.common_fields.max_htlc_value_in_flight_msat, peer_limits.min_max_htlc_value_in_flight_msat)));
- }
- if msg.channel_reserve_satoshis > peer_limits.max_channel_reserve_satoshis {
- return Err(ChannelError::close(format!("channel_reserve_satoshis ({}) is higher than the user specified limit ({})", msg.channel_reserve_satoshis, peer_limits.max_channel_reserve_satoshis)));
- }
- if msg.common_fields.max_accepted_htlcs < peer_limits.min_max_accepted_htlcs {
- return Err(ChannelError::close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", msg.common_fields.max_accepted_htlcs, peer_limits.min_max_accepted_htlcs)));
- }
- if msg.common_fields.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
- return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", msg.common_fields.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
- }
- if msg.common_fields.dust_limit_satoshis > MAX_CHAN_DUST_LIMIT_SATOSHIS {
- return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is greater than the implementation limit ({})", msg.common_fields.dust_limit_satoshis, MAX_CHAN_DUST_LIMIT_SATOSHIS)));
- }
- if msg.common_fields.minimum_depth > peer_limits.max_minimum_depth {
- return Err(ChannelError::close(format!("We consider the minimum depth to be unreasonably large. Expected minimum: ({}). Actual: ({})", peer_limits.max_minimum_depth, msg.common_fields.minimum_depth)));
- }
-
- if let Some(ty) = &msg.common_fields.channel_type {
- if *ty != self.context.channel_type {
- return Err(ChannelError::close("Channel Type in accept_channel didn't match the one sent in open_channel.".to_owned()));
- }
- } else if their_features.supports_channel_type() {
- // Assume they've accepted the channel type as they said they understand it.
- } else {
- let channel_type = ChannelTypeFeatures::from_init(&their_features);
- if channel_type != ChannelTypeFeatures::only_static_remote_key() {
- return Err(ChannelError::close("Only static_remote_key is supported for non-negotiated channel types".to_owned()));
- }
- self.context.channel_type = channel_type.clone();
- self.context.channel_transaction_parameters.channel_type_features = channel_type;
- }
-
- let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() {
- match &msg.common_fields.shutdown_scriptpubkey {
- &Some(ref script) => {
- // Peer is signaling upfront_shutdown and has opt-out with a 0-length script. We don't enforce anything
- if script.len() == 0 {
- None
- } else {
- if !script::is_bolt2_compliant(&script, their_features) {
- return Err(ChannelError::close(format!("Peer is signaling upfront_shutdown but has provided an unacceptable scriptpubkey format: {}", script)));
- }
- Some(script.clone())
- }
- },
- // Peer is signaling upfront shutdown but don't opt-out with correct mechanism (a.k.a 0-length script). Peer looks buggy, we fail the channel
- &None => {
- return Err(ChannelError::close("Peer is signaling upfront_shutdown but we don't get any script. Use 0-length script to opt-out".to_owned()));
- }
- }
- } else { None };
-
- self.context.counterparty_dust_limit_satoshis = msg.common_fields.dust_limit_satoshis;
- self.context.counterparty_max_htlc_value_in_flight_msat = cmp::min(msg.common_fields.max_htlc_value_in_flight_msat, self.context.channel_value_satoshis * 1000);
- self.context.counterparty_selected_channel_reserve_satoshis = Some(msg.channel_reserve_satoshis);
- self.context.counterparty_htlc_minimum_msat = msg.common_fields.htlc_minimum_msat;
- self.context.counterparty_max_accepted_htlcs = msg.common_fields.max_accepted_htlcs;
-
- if peer_limits.trust_own_funding_0conf {
- self.context.minimum_depth = Some(msg.common_fields.minimum_depth);
- } else {
- self.context.minimum_depth = Some(cmp::max(1, msg.common_fields.minimum_depth));
- }
-
- let counterparty_pubkeys = ChannelPublicKeys {
- funding_pubkey: msg.common_fields.funding_pubkey,
- revocation_basepoint: RevocationBasepoint::from(msg.common_fields.revocation_basepoint),
- payment_point: msg.common_fields.payment_basepoint,
- delayed_payment_basepoint: DelayedPaymentBasepoint::from(msg.common_fields.delayed_payment_basepoint),
- htlc_basepoint: HtlcBasepoint::from(msg.common_fields.htlc_basepoint)
- };
-
- self.context.channel_transaction_parameters.counterparty_parameters = Some(CounterpartyChannelTransactionParameters {
- selected_contest_delay: msg.common_fields.to_self_delay,
- pubkeys: counterparty_pubkeys,
- });
-
- self.context.counterparty_cur_commitment_point = Some(msg.common_fields.first_per_commitment_point);
- self.context.counterparty_shutdown_scriptpubkey = counterparty_shutdown_scriptpubkey;
-
- self.context.channel_state = ChannelState::NegotiatingFunding(
- NegotiatingFundingFlags::OUR_INIT_SENT | NegotiatingFundingFlags::THEIR_INIT_SENT
- );
- self.context.inbound_handshake_limits_override = None; // We're done enforcing limits on our peer's handshake now.
-
- Ok(())
+ pub fn accept_channel(
+ &mut self, msg: &msgs::AcceptChannel, default_limits: &ChannelHandshakeLimits,
+ their_features: &InitFeatures
+ ) -> Result<(), ChannelError> {
+ self.context.do_accept_channel_checks(default_limits, their_features, &msg.common_fields, msg.channel_reserve_satoshis)
}
/// Handles a funding_signed message from the remote end.
}
if self.context.commitment_secrets.get_min_seen_secret() != (1 << 48) ||
self.context.cur_counterparty_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER ||
- self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
+ self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
}
log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
&self.context.channel_id(), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
- let holder_signer = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
- let initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &holder_signer, true, false, logger).tx;
+ let holder_signer = self.context.build_holder_transaction_keys();
+ let initial_commitment_tx = self.context.build_commitment_transaction(self.context.holder_commitment_point.transaction_number(), &holder_signer, true, false, logger).tx;
{
let trusted_tx = initial_commitment_tx.trust();
let initial_commitment_bitcoin_tx = trusted_tx.built_transaction();
} else {
self.context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
}
- self.context.cur_holder_commitment_transaction_number -= 1;
+ self.context.holder_commitment_point.advance(&self.context.holder_signer, &self.context.secp_ctx, logger);
self.context.cur_counterparty_commitment_transaction_number -= 1;
log_info!(logger, "Received funding_signed from peer for channel {}", &self.context.channel_id());
dual_funding_channel_context: None,
};
- let need_channel_ready = channel.check_get_channel_ready(0).is_some();
+ let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some();
channel.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
Ok((channel, channel_monitor))
}
) {
panic!("Tried to send accept_channel after channel had moved forward");
}
- if self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
+ if self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
panic!("Tried to send an accept_channel for a channel that has already advanced");
}
///
/// [`msgs::AcceptChannel`]: crate::ln::msgs::AcceptChannel
fn generate_accept_channel_message(&self) -> msgs::AcceptChannel {
- let first_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
+ debug_assert!(self.context.holder_commitment_point.is_available());
+ let first_per_commitment_point = self.context.holder_commitment_point.current_point();
let keys = self.context.get_holder_pubkeys();
msgs::AcceptChannel {
fn check_funding_created_signature<L: Deref>(&mut self, sig: &Signature, logger: &L) -> Result<CommitmentTransaction, ChannelError> where L::Target: Logger {
let funding_script = self.context.get_funding_redeemscript();
- let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
- let initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, false, logger).tx;
+ let keys = self.context.build_holder_transaction_keys();
+ let initial_commitment_tx = self.context.build_commitment_transaction(self.context.holder_commitment_point.transaction_number(), &keys, true, false, logger).tx;
let trusted_tx = initial_commitment_tx.trust();
let initial_commitment_bitcoin_tx = trusted_tx.built_transaction();
let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis);
}
if self.context.commitment_secrets.get_min_seen_secret() != (1 << 48) ||
self.context.cur_counterparty_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER ||
- self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
+ self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
}
self.context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
self.context.channel_id = ChannelId::v1_from_funding_outpoint(funding_txo);
self.context.cur_counterparty_commitment_transaction_number -= 1;
- self.context.cur_holder_commitment_transaction_number -= 1;
+ self.context.holder_commitment_point.advance(&self.context.holder_signer, &self.context.secp_ctx, logger);
let (counterparty_initial_commitment_tx, funding_signed) = self.context.get_funding_signed_msg(logger);
#[cfg(any(dual_funding, splicing))]
dual_funding_channel_context: None,
};
- let need_channel_ready = channel.check_get_channel_ready(0).is_some();
+ let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some();
channel.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
Ok((channel, funding_signed, channel_monitor))
debug_assert!(false, "Cannot generate an open_channel2 after we've moved forward");
}
- if self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
+ if self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
debug_assert!(false, "Tried to send an open_channel2 for a channel that has already advanced");
}
let first_per_commitment_point = self.context.holder_signer.as_ref()
- .get_per_commitment_point(self.context.cur_holder_commitment_transaction_number,
+ .get_per_commitment_point(self.context.holder_commitment_point.transaction_number(),
&self.context.secp_ctx);
let second_per_commitment_point = self.context.holder_signer.as_ref()
- .get_per_commitment_point(self.context.cur_holder_commitment_transaction_number - 1,
+ .get_per_commitment_point(self.context.holder_commitment_point.transaction_number() - 1,
&self.context.secp_ctx);
let keys = self.context.get_holder_pubkeys();
) {
debug_assert!(false, "Tried to send accept_channel2 after channel had moved forward");
}
- if self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
+ if self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
debug_assert!(false, "Tried to send an accept_channel2 for a channel that has already advanced");
}
/// [`msgs::AcceptChannelV2`]: crate::ln::msgs::AcceptChannelV2
fn generate_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
let first_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(
- self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
+ self.context.holder_commitment_point.transaction_number(), &self.context.secp_ctx);
let second_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(
- self.context.cur_holder_commitment_transaction_number - 1, &self.context.secp_ctx);
+ self.context.holder_commitment_point.transaction_number() - 1, &self.context.secp_ctx);
let keys = self.context.get_holder_pubkeys();
msgs::AcceptChannelV2 {
}
self.context.destination_script.write(writer)?;
- self.context.cur_holder_commitment_transaction_number.write(writer)?;
+ self.context.holder_commitment_point.transaction_number().write(writer)?;
self.context.cur_counterparty_commitment_transaction_number.write(writer)?;
self.context.value_to_self_msat.write(writer)?;
monitor_pending_update_adds = Some(&self.context.monitor_pending_update_adds);
}
+ // `current_point` will become optional when async signing is implemented.
+ let cur_holder_commitment_point = Some(self.context.holder_commitment_point.current_point());
+ let next_holder_commitment_point = self.context.holder_commitment_point.next_point();
+
write_tlv_fields!(writer, {
(0, self.context.announcement_sigs, option),
// minimum_depth and counterparty_selected_channel_reserve_satoshis used to have a
(39, pending_outbound_blinding_points, optional_vec),
(41, holding_cell_blinding_points, optional_vec),
(43, malformed_htlcs, optional_vec), // Added in 0.0.119
- // 45 and 47 are reserved for async signing
+ (45, cur_holder_commitment_point, option),
+ (47, next_holder_commitment_point, option),
(49, self.context.local_initiated_shutdown, option), // Added in 0.0.122
});
let mut malformed_htlcs: Option<Vec<(u64, u16, [u8; 32])>> = None;
let mut monitor_pending_update_adds: Option<Vec<msgs::UpdateAddHTLC>> = None;
+ let mut cur_holder_commitment_point_opt: Option<PublicKey> = None;
+ let mut next_holder_commitment_point_opt: Option<PublicKey> = None;
+
read_tlv_fields!(reader, {
(0, announcement_sigs, option),
(1, minimum_depth, option),
(39, pending_outbound_blinding_points_opt, optional_vec),
(41, holding_cell_blinding_points_opt, optional_vec),
(43, malformed_htlcs, optional_vec), // Added in 0.0.119
- // 45 and 47 are reserved for async signing
+ (45, cur_holder_commitment_point_opt, option),
+ (47, next_holder_commitment_point_opt, option),
(49, local_initiated_shutdown, option),
});
}
}
+ // If we're restoring this channel for the first time after an upgrade, then we require that the
+ // signer be available so that we can immediately populate the current commitment point. Channel
+ // restoration will fail if this is not possible.
+ let holder_commitment_point = match (cur_holder_commitment_point_opt, next_holder_commitment_point_opt) {
+ (Some(current), Some(next)) => HolderCommitmentPoint::Available {
+ transaction_number: cur_holder_commitment_transaction_number, current, next
+ },
+ (Some(current), _) => HolderCommitmentPoint::Available {
+ transaction_number: cur_holder_commitment_transaction_number, current,
+ next: holder_signer.get_per_commitment_point(cur_holder_commitment_transaction_number - 1, &secp_ctx),
+ },
+ (_, _) => HolderCommitmentPoint::Available {
+ transaction_number: cur_holder_commitment_transaction_number,
+ current: holder_signer.get_per_commitment_point(cur_holder_commitment_transaction_number, &secp_ctx),
+ next: holder_signer.get_per_commitment_point(cur_holder_commitment_transaction_number - 1, &secp_ctx),
+ },
+ };
+
Ok(Channel {
context: ChannelContext {
user_id,
shutdown_scriptpubkey,
destination_script,
- cur_holder_commitment_transaction_number,
+ holder_commitment_point,
cur_counterparty_commitment_transaction_number,
value_to_self_msat,
// Clear the ChannelState::WaitingForBatch only when called by ChannelManager.
node_a_chan.set_batch_ready();
assert_eq!(node_a_chan.context.channel_state, ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::THEIR_CHANNEL_READY));
- assert!(node_a_chan.check_get_channel_ready(0).is_some());
+ assert!(node_a_chan.check_get_channel_ready(0, &&logger).is_some());
}
}