use crate::ln::onion_utils::HTLCFailReason;
use crate::chain::BestBlock;
use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator};
-use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, WithChannelMonitor, LATENCY_GRACE_PERIOD_BLOCKS, CLOSED_CHANNEL_UPDATE_ID};
+use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS, CLOSED_CHANNEL_UPDATE_ID};
use crate::chain::transaction::{OutPoint, TransactionData};
use crate::sign::ecdsa::{EcdsaChannelSigner, WriteableEcdsaChannelSigner};
use crate::sign::{EntropySource, ChannelSigner, SignerProvider, NodeSigner, Recipient};
mod state_flags {
pub const OUR_INIT_SENT: u32 = 1 << 0;
pub const THEIR_INIT_SENT: u32 = 1 << 1;
- pub const FUNDING_CREATED: u32 = 1 << 2;
- pub const FUNDING_SENT: u32 = 1 << 3;
+ pub const FUNDING_NEGOTIATED: u32 = 1 << 2;
+ pub const AWAITING_CHANNEL_READY: u32 = 1 << 3;
pub const THEIR_CHANNEL_READY: u32 = 1 << 4;
pub const OUR_CHANNEL_READY: u32 = 1 << 5;
pub const CHANNEL_READY: u32 = 1 << 6;
);
define_state_flags!(
- "Flags that only apply to [`ChannelState::FundingSent`].",
- FUNDED_STATE, FundingSentFlags, [
+ "Flags that only apply to [`ChannelState::AwaitingChannelReady`].",
+ FUNDED_STATE, AwaitingChannelReadyFlags, [
("Indicates they sent us a `channel_ready` message. Once both `THEIR_CHANNEL_READY` and \
`OUR_CHANNEL_READY` are set, our state moves on to `ChannelReady`.",
THEIR_CHANNEL_READY, state_flags::THEIR_CHANNEL_READY),
/// We are negotiating the parameters required for the channel prior to funding it.
NegotiatingFunding(NegotiatingFundingFlags),
/// We have sent `funding_created` and are awaiting a `funding_signed` to advance to
- /// `FundingSent`. Note that this is nonsense for an inbound channel as we immediately generate
+ /// `AwaitingChannelReady`. Note that this is nonsense for an inbound channel as we immediately generate
/// `funding_signed` upon receipt of `funding_created`, so simply skip this state.
- FundingCreated,
+ FundingNegotiated,
/// We've received/sent `funding_created` and `funding_signed` and are thus now waiting on the
/// funding transaction to confirm.
- FundingSent(FundingSentFlags),
+ AwaitingChannelReady(AwaitingChannelReadyFlags),
/// Both we and our counterparty consider the funding transaction confirmed and the channel is
/// now operational.
ChannelReady(ChannelReadyFlags),
}
};
($get: ident, $set: ident, $clear: ident, $state_flag: expr, FUNDED_STATES) => {
- impl_state_flag!($get, $set, $clear, $state_flag, [FundingSent, ChannelReady]);
+ impl_state_flag!($get, $set, $clear, $state_flag, [AwaitingChannelReady, ChannelReady]);
};
($get: ident, $set: ident, $clear: ident, $state_flag: expr, $state: ident) => {
impl_state_flag!($get, $set, $clear, $state_flag, [$state]);
impl ChannelState {
fn from_u32(state: u32) -> Result<Self, ()> {
match state {
- state_flags::FUNDING_CREATED => Ok(ChannelState::FundingCreated),
+ state_flags::FUNDING_NEGOTIATED => Ok(ChannelState::FundingNegotiated),
state_flags::SHUTDOWN_COMPLETE => Ok(ChannelState::ShutdownComplete),
val => {
- if val & state_flags::FUNDING_SENT == state_flags::FUNDING_SENT {
- FundingSentFlags::from_u32(val & !state_flags::FUNDING_SENT)
- .map(|flags| ChannelState::FundingSent(flags))
+ if val & state_flags::AWAITING_CHANNEL_READY == state_flags::AWAITING_CHANNEL_READY {
+ AwaitingChannelReadyFlags::from_u32(val & !state_flags::AWAITING_CHANNEL_READY)
+ .map(|flags| ChannelState::AwaitingChannelReady(flags))
} else if val & state_flags::CHANNEL_READY == state_flags::CHANNEL_READY {
ChannelReadyFlags::from_u32(val & !state_flags::CHANNEL_READY)
.map(|flags| ChannelState::ChannelReady(flags))
fn to_u32(&self) -> u32 {
match self {
ChannelState::NegotiatingFunding(flags) => flags.0,
- ChannelState::FundingCreated => state_flags::FUNDING_CREATED,
- ChannelState::FundingSent(flags) => state_flags::FUNDING_SENT | flags.0,
+ ChannelState::FundingNegotiated => state_flags::FUNDING_NEGOTIATED,
+ ChannelState::AwaitingChannelReady(flags) => state_flags::AWAITING_CHANNEL_READY | flags.0,
ChannelState::ChannelReady(flags) => state_flags::CHANNEL_READY | flags.0,
ChannelState::ShutdownComplete => state_flags::SHUTDOWN_COMPLETE,
}
}
fn is_pre_funded_state(&self) -> bool {
- matches!(self, ChannelState::NegotiatingFunding(_)|ChannelState::FundingCreated)
+ matches!(self, ChannelState::NegotiatingFunding(_)|ChannelState::FundingNegotiated)
}
fn is_both_sides_shutdown(&self) -> bool {
fn with_funded_state_flags_mask(&self) -> FundedStateFlags {
match self {
- ChannelState::FundingSent(flags) => FundedStateFlags((*flags & FundedStateFlags::ALL).0),
+ ChannelState::AwaitingChannelReady(flags) => FundedStateFlags((*flags & FundedStateFlags::ALL).0),
ChannelState::ChannelReady(flags) => FundedStateFlags((*flags & FundedStateFlags::ALL).0),
_ => FundedStateFlags::new(),
}
impl_state_flag!(is_remote_shutdown_sent, set_remote_shutdown_sent, clear_remote_shutdown_sent,
FundedStateFlags::REMOTE_SHUTDOWN_SENT, FUNDED_STATES);
impl_state_flag!(is_our_channel_ready, set_our_channel_ready, clear_our_channel_ready,
- FundingSentFlags::OUR_CHANNEL_READY, FundingSent);
+ AwaitingChannelReadyFlags::OUR_CHANNEL_READY, AwaitingChannelReady);
impl_state_flag!(is_their_channel_ready, set_their_channel_ready, clear_their_channel_ready,
- FundingSentFlags::THEIR_CHANNEL_READY, FundingSent);
+ AwaitingChannelReadyFlags::THEIR_CHANNEL_READY, AwaitingChannelReady);
impl_state_flag!(is_waiting_for_batch, set_waiting_for_batch, clear_waiting_for_batch,
- FundingSentFlags::WAITING_FOR_BATCH, FundingSent);
+ AwaitingChannelReadyFlags::WAITING_FOR_BATCH, AwaitingChannelReady);
impl_state_flag!(is_awaiting_remote_revoke, set_awaiting_remote_revoke, clear_awaiting_remote_revoke,
ChannelReadyFlags::AWAITING_REMOTE_REVOKE, ChannelReady);
}
pub(super) struct SignerResumeUpdates {
pub commitment_update: Option<msgs::CommitmentUpdate>,
pub funding_signed: Option<msgs::FundingSigned>,
- pub funding_created: Option<msgs::FundingCreated>,
pub channel_ready: Option<msgs::ChannelReady>,
}
/// shutdown state returns the state of the channel in its various stages of shutdown
pub fn shutdown_state(&self) -> ChannelShutdownState {
match self.channel_state {
- ChannelState::FundingSent(_)|ChannelState::ChannelReady(_) =>
+ ChannelState::AwaitingChannelReady(_)|ChannelState::ChannelReady(_) =>
if self.channel_state.is_local_shutdown_sent() && !self.channel_state.is_remote_shutdown_sent() {
ChannelShutdownState::ShutdownInitiated
} else if (self.channel_state.is_local_shutdown_sent() || self.channel_state.is_remote_shutdown_sent()) && !self.closing_negotiation_ready() {
fn closing_negotiation_ready(&self) -> bool {
let is_ready_to_close = match self.channel_state {
- ChannelState::FundingSent(flags) =>
+ ChannelState::AwaitingChannelReady(flags) =>
flags & FundedStateFlags::ALL == FundedStateFlags::LOCAL_SHUTDOWN_SENT | FundedStateFlags::REMOTE_SHUTDOWN_SENT,
ChannelState::ChannelReady(flags) =>
flags == FundedStateFlags::LOCAL_SHUTDOWN_SENT | FundedStateFlags::REMOTE_SHUTDOWN_SENT,
/// funding transaction has been broadcast if necessary.
pub fn is_funding_broadcast(&self) -> bool {
!self.channel_state.is_pre_funded_state() &&
- !matches!(self.channel_state, ChannelState::FundingSent(flags) if flags.is_set(FundingSentFlags::WAITING_FOR_BATCH))
+ !matches!(self.channel_state, ChannelState::AwaitingChannelReady(flags) if flags.is_set(AwaitingChannelReadyFlags::WAITING_FOR_BATCH))
}
/// Transaction nomenclature is somewhat confusing here as there are many different cases - a
fn if_unbroadcasted_funding<F, O>(&self, f: F) -> Option<O>
where F: Fn() -> Option<O> {
match self.channel_state {
- ChannelState::FundingCreated => f(),
- ChannelState::FundingSent(flags) => if flags.is_set(FundingSentFlags::WAITING_FOR_BATCH) {
+ ChannelState::FundingNegotiated => f(),
+ ChannelState::AwaitingChannelReady(flags) => if flags.is_set(AwaitingChannelReadyFlags::WAITING_FOR_BATCH) {
f()
} else {
None
}
}
let monitor_update = if let Some(funding_txo) = self.get_funding_txo() {
- // If we haven't yet exchanged funding signatures (ie channel_state < FundingSent),
+ // If we haven't yet exchanged funding signatures (ie channel_state < AwaitingChannelReady),
// returning a channel monitor update here would imply a channel monitor update before
// we even registered the channel monitor to begin with, which is invalid.
// Thus, if we aren't actually at a point where we could conceivably broadcast the
// monitor update to the user, even if we return one).
// See test_duplicate_chan_id and test_pre_lockin_no_chan_closed_update for more.
let generate_monitor_update = match self.channel_state {
- ChannelState::FundingSent(_)|ChannelState::ChannelReady(_)|ChannelState::ShutdownComplete => true,
+ ChannelState::AwaitingChannelReady(_)|ChannelState::ChannelReady(_)|ChannelState::ShutdownComplete => true,
_ => false,
};
if generate_monitor_update {
}
}
- /// Only allowed after [`Self::channel_transaction_parameters`] is set.
- fn get_funding_created_msg<L: Deref>(&mut self, logger: &L) -> Option<msgs::FundingCreated> where L::Target: Logger {
- let counterparty_keys = self.build_remote_transaction_keys();
- let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
- let signature = match &self.holder_signer {
- // TODO (taproot|arik): move match into calling method for Taproot
- ChannelSignerType::Ecdsa(ecdsa) => {
- ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), Vec::new(), &self.secp_ctx)
- .map(|(sig, _)| sig).ok()?
- },
- // TODO (taproot|arik)
- #[cfg(taproot)]
- _ => todo!()
- };
-
- if self.signer_pending_funding {
- log_trace!(logger, "Counterparty commitment signature ready for funding_created message: clearing signer_pending_funding");
- self.signer_pending_funding = false;
- }
-
- Some(msgs::FundingCreated {
- temporary_channel_id: self.temporary_channel_id.unwrap(),
- funding_txid: self.channel_transaction_parameters.funding_outpoint.as_ref().unwrap().txid,
- funding_output_index: self.channel_transaction_parameters.funding_outpoint.as_ref().unwrap().index,
- signature,
- #[cfg(taproot)]
- partial_signature_with_nonce: None,
- #[cfg(taproot)]
- next_local_nonce: None,
- })
- }
-
/// Only allowed after [`Self::channel_transaction_parameters`] is set.
fn get_funding_signed_msg<L: Deref>(&mut self, logger: &L) -> (CommitmentTransaction, Option<msgs::FundingSigned>) where L::Target: Logger {
let counterparty_keys = self.build_remote_transaction_keys();
}
// Message handlers:
-
- /// Handles a funding_signed message from the remote end.
- /// 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<ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>, ChannelError>
- where
- L::Target: Logger
- {
- if !self.context.is_outbound() {
- return Err(ChannelError::Close("Received funding_signed for an inbound channel?".to_owned()));
- }
- if !matches!(self.context.channel_state, ChannelState::FundingCreated) {
- return Err(ChannelError::Close("Received funding_signed in strange state!".to_owned()));
- }
- 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 {
- panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
- }
-
- let funding_script = self.context.get_funding_redeemscript();
-
- let counterparty_keys = self.context.build_remote_transaction_keys();
- let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
- let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
- let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
-
- 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 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);
- // They sign our commitment transaction, allowing us to broadcast the tx if we wish.
- if let Err(_) = self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.context.get_counterparty_pubkeys().funding_pubkey) {
- return Err(ChannelError::Close("Invalid funding_signed signature from peer".to_owned()));
- }
- }
-
- let holder_commitment_tx = HolderCommitmentTransaction::new(
- initial_commitment_tx,
- msg.signature,
- Vec::new(),
- &self.context.get_holder_pubkeys().funding_pubkey,
- self.context.counterparty_funding_pubkey()
- );
-
- self.context.holder_signer.as_ref().validate_holder_commitment(&holder_commitment_tx, Vec::new())
- .map_err(|_| ChannelError::Close("Failed to validate our commitment".to_owned()))?;
-
-
- let funding_redeemscript = self.context.get_funding_redeemscript();
- let funding_txo = self.context.get_funding_txo().unwrap();
- let funding_txo_script = funding_redeemscript.to_v0_p2wsh();
- let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.context.get_holder_pubkeys().payment_point, &self.context.get_counterparty_pubkeys().payment_point, self.context.is_outbound());
- let shutdown_script = self.context.shutdown_scriptpubkey.clone().map(|script| script.into_inner());
- let mut monitor_signer = signer_provider.derive_channel_signer(self.context.channel_value_satoshis, self.context.channel_keys_id);
- monitor_signer.provide_channel_parameters(&self.context.channel_transaction_parameters);
- let channel_monitor = ChannelMonitor::new(self.context.secp_ctx.clone(), monitor_signer,
- shutdown_script, self.context.get_holder_selected_contest_delay(),
- &self.context.destination_script, (funding_txo, funding_txo_script),
- &self.context.channel_transaction_parameters,
- funding_redeemscript.clone(), self.context.channel_value_satoshis,
- obscure_factor,
- holder_commitment_tx, best_block, self.context.counterparty_node_id);
- let logger_with_chan_monitor = WithChannelMonitor::from(logger, &channel_monitor);
- channel_monitor.provide_initial_counterparty_commitment_tx(
- counterparty_initial_bitcoin_tx.txid, Vec::new(),
- self.context.cur_counterparty_commitment_transaction_number,
- self.context.counterparty_cur_commitment_point.unwrap(),
- counterparty_initial_commitment_tx.feerate_per_kw(),
- counterparty_initial_commitment_tx.to_broadcaster_value_sat(),
- counterparty_initial_commitment_tx.to_countersignatory_value_sat(), &&logger_with_chan_monitor);
-
- assert!(!self.context.channel_state.is_monitor_update_in_progress()); // We have no had any monitor(s) yet to fail update!
- if self.context.is_batch_funding() {
- self.context.channel_state = ChannelState::FundingSent(FundingSentFlags::WAITING_FOR_BATCH);
- } else {
- self.context.channel_state = ChannelState::FundingSent(FundingSentFlags::new());
- }
- self.context.cur_holder_commitment_transaction_number -= 1;
- self.context.cur_counterparty_commitment_transaction_number -= 1;
-
- log_info!(logger, "Received funding_signed from peer for channel {}", &self.context.channel_id());
-
- let need_channel_ready = self.check_get_channel_ready(0).is_some();
- self.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
- Ok(channel_monitor)
- }
-
/// Updates the state of the channel to indicate that all channels in the batch have received
/// funding_signed and persisted their monitors.
/// The funding transaction is consequently allowed to be broadcast, and the channel can be
// batch, but we can receive channel_ready messages.
let mut check_reconnection = false;
match &self.context.channel_state {
- ChannelState::FundingSent(flags) => {
+ ChannelState::AwaitingChannelReady(flags) => {
let flags = *flags & !FundedStateFlags::ALL;
- debug_assert!(!flags.is_set(FundingSentFlags::OUR_CHANNEL_READY) || !flags.is_set(FundingSentFlags::WAITING_FOR_BATCH));
- if flags & !FundingSentFlags::WAITING_FOR_BATCH == FundingSentFlags::THEIR_CHANNEL_READY {
+ debug_assert!(!flags.is_set(AwaitingChannelReadyFlags::OUR_CHANNEL_READY) || !flags.is_set(AwaitingChannelReadyFlags::WAITING_FOR_BATCH));
+ if flags & !AwaitingChannelReadyFlags::WAITING_FOR_BATCH == AwaitingChannelReadyFlags::THEIR_CHANNEL_READY {
// If we reconnected before sending our `channel_ready` they may still resend theirs.
check_reconnection = true;
- } else if (flags & !FundingSentFlags::WAITING_FOR_BATCH).is_empty() {
+ } else if (flags & !AwaitingChannelReadyFlags::WAITING_FOR_BATCH).is_empty() {
self.context.channel_state.set_their_channel_ready();
- } else if flags == FundingSentFlags::OUR_CHANNEL_READY {
+ } else if flags == AwaitingChannelReadyFlags::OUR_CHANNEL_READY {
self.context.channel_state = ChannelState::ChannelReady(self.context.channel_state.with_funded_state_flags_mask().into());
self.context.update_time_counter += 1;
} else {
// We're in `WAITING_FOR_BATCH`, so we should wait until we're ready.
- debug_assert!(flags.is_set(FundingSentFlags::WAITING_FOR_BATCH));
+ debug_assert!(flags.is_set(AwaitingChannelReadyFlags::WAITING_FOR_BATCH));
}
}
// If we reconnected before sending our `channel_ready` they may still resend theirs.
assert!(self.context.channel_state.is_monitor_update_in_progress());
self.context.channel_state.clear_monitor_update_in_progress();
- // If we're past (or at) the FundingSent stage on an outbound channel, try to
+ // If we're past (or at) the AwaitingChannelReady stage on an outbound channel, try to
// (re-)broadcast the funding transaction as we may have declined to broadcast it when we
// first received the funding_signed.
let mut funding_broadcastable =
if self.context.is_outbound() &&
- matches!(self.context.channel_state, ChannelState::FundingSent(flags) if !flags.is_set(FundingSentFlags::WAITING_FOR_BATCH)) ||
+ matches!(self.context.channel_state, ChannelState::AwaitingChannelReady(flags) if !flags.is_set(AwaitingChannelReadyFlags::WAITING_FOR_BATCH)) ||
matches!(self.context.channel_state, ChannelState::ChannelReady(_))
{
self.context.funding_transaction.take()
let channel_ready = if funding_signed.is_some() {
self.check_get_channel_ready(0)
} else { None };
- let funding_created = if self.context.signer_pending_funding && self.context.is_outbound() {
- self.context.get_funding_created_msg(logger)
- } else { None };
- log_trace!(logger, "Signer unblocked with {} commitment_update, {} funding_signed, {} funding_created, and {} channel_ready",
+ log_trace!(logger, "Signer unblocked with {} commitment_update, {} funding_signed and {} channel_ready",
if commitment_update.is_some() { "a" } else { "no" },
if funding_signed.is_some() { "a" } else { "no" },
- if funding_created.is_some() { "a" } else { "no" },
if channel_ready.is_some() { "a" } else { "no" });
SignerResumeUpdates {
commitment_update,
funding_signed,
- funding_created,
channel_ready,
}
}
let announcement_sigs = self.get_announcement_sigs(node_signer, chain_hash, user_config, best_block.height(), logger);
- if matches!(self.context.channel_state, ChannelState::FundingSent(_)) {
+ if matches!(self.context.channel_state, ChannelState::AwaitingChannelReady(_)) {
// If we're waiting on a monitor update, we shouldn't re-send any channel_ready's.
if !self.context.channel_state.is_our_channel_ready() ||
self.context.channel_state.is_monitor_update_in_progress() {
pub fn is_awaiting_initial_mon_persist(&self) -> bool {
if !self.is_awaiting_monitor_update() { return false; }
if matches!(
- self.context.channel_state, ChannelState::FundingSent(flags)
- if (flags & !(FundingSentFlags::THEIR_CHANNEL_READY | FundedStateFlags::PEER_DISCONNECTED | FundedStateFlags::MONITOR_UPDATE_IN_PROGRESS | FundingSentFlags::WAITING_FOR_BATCH)).is_empty()
+ self.context.channel_state, ChannelState::AwaitingChannelReady(flags)
+ if (flags & !(AwaitingChannelReadyFlags::THEIR_CHANNEL_READY | FundedStateFlags::PEER_DISCONNECTED | FundedStateFlags::MONITOR_UPDATE_IN_PROGRESS | AwaitingChannelReadyFlags::WAITING_FOR_BATCH)).is_empty()
) {
// If we're not a 0conf channel, we'll be waiting on a monitor update with only
- // FundingSent set, though our peer could have sent their channel_ready.
+ // AwaitingChannelReady set, though our peer could have sent their channel_ready.
debug_assert!(self.context.minimum_depth.unwrap_or(1) > 0);
return true;
}
if self.context.cur_holder_commitment_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 FundingSent immediately even while
+ // 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
// transaction numbers have both been iterated only exactly once (for the
// funding_signed), and we're awaiting monitor update.
/// Returns true if our channel_ready has been sent
pub fn is_our_channel_ready(&self) -> bool {
- matches!(self.context.channel_state, ChannelState::FundingSent(flags) if flags.is_set(FundingSentFlags::OUR_CHANNEL_READY)) ||
+ matches!(self.context.channel_state, ChannelState::AwaitingChannelReady(flags) if flags.is_set(AwaitingChannelReadyFlags::OUR_CHANNEL_READY)) ||
matches!(self.context.channel_state, ChannelState::ChannelReady(_))
}
// Note that we don't include ChannelState::WaitingForBatch as we don't want to send
// channel_ready until the entire batch is ready.
- let need_commitment_update = if matches!(self.context.channel_state, ChannelState::FundingSent(f) if (f & !FundedStateFlags::ALL).is_empty()) {
+ let need_commitment_update = if matches!(self.context.channel_state, ChannelState::AwaitingChannelReady(f) if (f & !FundedStateFlags::ALL).is_empty()) {
self.context.channel_state.set_our_channel_ready();
true
- } else if matches!(self.context.channel_state, ChannelState::FundingSent(f) if f & !FundedStateFlags::ALL == FundingSentFlags::THEIR_CHANNEL_READY) {
+ } else if matches!(self.context.channel_state, ChannelState::AwaitingChannelReady(f) if f & !FundedStateFlags::ALL == AwaitingChannelReadyFlags::THEIR_CHANNEL_READY) {
self.context.channel_state = ChannelState::ChannelReady(self.context.channel_state.with_funded_state_flags_mask().into());
self.context.update_time_counter += 1;
true
- } else if matches!(self.context.channel_state, ChannelState::FundingSent(f) if f & !FundedStateFlags::ALL == FundingSentFlags::OUR_CHANNEL_READY) {
+ } else if matches!(self.context.channel_state, ChannelState::AwaitingChannelReady(f) if f & !FundedStateFlags::ALL == AwaitingChannelReadyFlags::OUR_CHANNEL_READY) {
// We got a reorg but not enough to trigger a force close, just ignore.
false
} else {
// an inbound channel - before that we have no known funding TXID). The fuzzer,
// however, may do this and we shouldn't treat it as a bug.
#[cfg(not(fuzzing))]
- panic!("Started confirming a channel in a state pre-FundingSent: {}.\n\
+ panic!("Started confirming a channel in a state pre-AwaitingChannelReady: {}.\n\
Do NOT broadcast a funding transaction manually - let LDK do it for you!",
self.context.channel_state.to_u32());
}
// (which is one further, as they always revoke previous commitment transaction, not
// the one we send) so we have to decrement by 1. Note that if
// cur_counterparty_commitment_transaction_number is INITIAL_COMMITMENT_NUMBER we will have
- // dropped this channel on disconnect as it hasn't yet reached FundingSent so we can't
+ // dropped this channel on disconnect as it hasn't yet reached AwaitingChannelReady so we can't
// overflow here.
next_remote_commitment_number: INITIAL_COMMITMENT_NUMBER - self.context.cur_counterparty_commitment_transaction_number - 1,
your_last_per_commitment_secret: remote_last_secret,
/// Begins the shutdown process, getting a message for the remote peer and returning all
/// holding cell HTLCs for payment failure.
- ///
- /// May jump to the channel being fully shutdown (see [`Self::is_shutdown`]) in which case no
- /// [`ChannelMonitorUpdate`] will be returned).
pub fn get_shutdown(&mut self, signer_provider: &SP, their_features: &InitFeatures,
target_feerate_sats_per_kw: Option<u32>, override_shutdown_script: Option<ShutdownScript>)
- -> Result<(msgs::Shutdown, Option<ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>, Option<ShutdownResult>), APIError>
+ -> Result<(msgs::Shutdown, Option<ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>), APIError>
{
for htlc in self.context.pending_outbound_htlcs.iter() {
if let OutboundHTLCState::LocalAnnounced(_) = htlc.state {
return Err(APIError::ChannelUnavailable{err: "Cannot begin shutdown while peer is disconnected or we're waiting on a monitor update, maybe force-close instead?".to_owned()});
}
- // If we haven't funded the channel yet, we don't need to bother ensuring the shutdown
- // script is set, we just force-close and call it a day.
- let mut chan_closed = false;
- if self.context.channel_state.is_pre_funded_state() {
- chan_closed = true;
- }
-
let update_shutdown_script = match self.context.shutdown_scriptpubkey {
Some(_) => false,
- None if !chan_closed => {
+ None => {
// use override shutdown script if provided
let shutdown_scriptpubkey = match override_shutdown_script {
Some(script) => script,
self.context.shutdown_scriptpubkey = Some(shutdown_scriptpubkey);
true
},
- None => false,
};
// From here on out, we may not fail!
self.context.target_closing_feerate_sats_per_kw = target_feerate_sats_per_kw;
- let shutdown_result = if self.context.channel_state.is_pre_funded_state() {
- let shutdown_result = ShutdownResult {
- monitor_update: None,
- dropped_outbound_htlcs: Vec::new(),
- unbroadcasted_batch_funding_txid: self.context.unbroadcasted_batch_funding_txid(),
- channel_id: self.context.channel_id,
- counterparty_node_id: self.context.counterparty_node_id,
- };
- self.context.channel_state = ChannelState::ShutdownComplete;
- Some(shutdown_result)
- } else {
- self.context.channel_state.set_local_shutdown_sent();
- None
- };
+ self.context.channel_state.set_local_shutdown_sent();
self.context.update_time_counter += 1;
let monitor_update = if update_shutdown_script {
debug_assert!(!self.is_shutdown() || monitor_update.is_none(),
"we can't both complete shutdown and return a monitor update");
- Ok((shutdown, monitor_update, dropped_outbound_htlcs, shutdown_result))
+ Ok((shutdown, monitor_update, dropped_outbound_htlcs))
}
pub fn inflight_htlc_sources(&self) -> impl Iterator<Item=(&HTLCSource, &PaymentHash)> {
})
}
+ /// Only allowed after [`ChannelContext::channel_transaction_parameters`] is set.
+ fn get_funding_created_msg<L: Deref>(&mut self, logger: &L) -> Option<msgs::FundingCreated> where L::Target: Logger {
+ let counterparty_keys = self.context.build_remote_transaction_keys();
+ let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
+ let signature = match &self.context.holder_signer {
+ // TODO (taproot|arik): move match into calling method for Taproot
+ ChannelSignerType::Ecdsa(ecdsa) => {
+ ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), Vec::new(), &self.context.secp_ctx)
+ .map(|(sig, _)| sig).ok()?
+ },
+ // TODO (taproot|arik)
+ #[cfg(taproot)]
+ _ => todo!()
+ };
+
+ if self.context.signer_pending_funding {
+ log_trace!(logger, "Counterparty commitment signature ready for funding_created message: clearing signer_pending_funding");
+ self.context.signer_pending_funding = false;
+ }
+
+ Some(msgs::FundingCreated {
+ temporary_channel_id: self.context.temporary_channel_id.unwrap(),
+ funding_txid: self.context.channel_transaction_parameters.funding_outpoint.as_ref().unwrap().txid,
+ funding_output_index: self.context.channel_transaction_parameters.funding_outpoint.as_ref().unwrap().index,
+ signature,
+ #[cfg(taproot)]
+ partial_signature_with_nonce: None,
+ #[cfg(taproot)]
+ next_local_nonce: None,
+ })
+ }
+
/// Updates channel state with knowledge of the funding transaction's txid/index, and generates
/// a funding_created message for the remote peer.
/// Panics if called at some time other than immediately after initial handshake, if called twice,
/// Note that channel_id changes during this call!
/// Do NOT broadcast the funding transaction until after a successful funding_signed call!
/// If an Err is returned, it is a ChannelError::Close.
- pub fn get_funding_created<L: Deref>(mut self, funding_transaction: Transaction, funding_txo: OutPoint, is_batch_funding: bool, logger: &L)
- -> Result<(Channel<SP>, Option<msgs::FundingCreated>), (Self, ChannelError)> where L::Target: Logger {
+ pub fn get_funding_created<L: Deref>(&mut self, funding_transaction: Transaction, funding_txo: OutPoint, is_batch_funding: bool, logger: &L)
+ -> Result<Option<msgs::FundingCreated>, (Self, ChannelError)> where L::Target: Logger {
if !self.context.is_outbound() {
panic!("Tried to create outbound funding_created message on an inbound channel!");
}
// Now that we're past error-generating stuff, update our local state:
- self.context.channel_state = ChannelState::FundingCreated;
+ self.context.channel_state = ChannelState::FundingNegotiated;
self.context.channel_id = funding_txo.to_channel_id();
// If the funding transaction is a coinbase transaction, we need to set the minimum depth to 100.
self.context.funding_transaction = Some(funding_transaction);
self.context.is_batch_funding = Some(()).filter(|_| is_batch_funding);
- let funding_created = self.context.get_funding_created_msg(logger);
+ let funding_created = self.get_funding_created_msg(logger);
if funding_created.is_none() {
if !self.context.signer_pending_funding {
log_trace!(logger, "funding_created awaiting signer; setting signer_pending_funding");
}
}
- let channel = Channel {
- context: self.context,
- };
-
- Ok((channel, funding_created))
+ Ok(funding_created)
}
fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures) -> ChannelTypeFeatures {
Ok(())
}
+
+ /// Handles a funding_signed message from the remote end.
+ /// 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)>
+ where
+ L::Target: Logger
+ {
+ if !self.context.is_outbound() {
+ return Err((self, ChannelError::Close("Received funding_signed for an inbound channel?".to_owned())));
+ }
+ if !matches!(self.context.channel_state, ChannelState::FundingNegotiated) {
+ return Err((self, ChannelError::Close("Received funding_signed in strange state!".to_owned())));
+ }
+ 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 {
+ panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
+ }
+
+ let funding_script = self.context.get_funding_redeemscript();
+
+ let counterparty_keys = self.context.build_remote_transaction_keys();
+ let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
+ let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
+ let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
+
+ 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 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);
+ // They sign our commitment transaction, allowing us to broadcast the tx if we wish.
+ if let Err(_) = self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.context.get_counterparty_pubkeys().funding_pubkey) {
+ return Err((self, ChannelError::Close("Invalid funding_signed signature from peer".to_owned())));
+ }
+ }
+
+ let holder_commitment_tx = HolderCommitmentTransaction::new(
+ initial_commitment_tx,
+ msg.signature,
+ Vec::new(),
+ &self.context.get_holder_pubkeys().funding_pubkey,
+ self.context.counterparty_funding_pubkey()
+ );
+
+ let validated =
+ self.context.holder_signer.as_ref().validate_holder_commitment(&holder_commitment_tx, Vec::new());
+ if validated.is_err() {
+ return Err((self, ChannelError::Close("Failed to validate our commitment".to_owned())));
+ }
+
+ let funding_redeemscript = self.context.get_funding_redeemscript();
+ let funding_txo = self.context.get_funding_txo().unwrap();
+ let funding_txo_script = funding_redeemscript.to_v0_p2wsh();
+ let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.context.get_holder_pubkeys().payment_point, &self.context.get_counterparty_pubkeys().payment_point, self.context.is_outbound());
+ let shutdown_script = self.context.shutdown_scriptpubkey.clone().map(|script| script.into_inner());
+ let mut monitor_signer = signer_provider.derive_channel_signer(self.context.channel_value_satoshis, self.context.channel_keys_id);
+ monitor_signer.provide_channel_parameters(&self.context.channel_transaction_parameters);
+ let channel_monitor = ChannelMonitor::new(self.context.secp_ctx.clone(), monitor_signer,
+ shutdown_script, self.context.get_holder_selected_contest_delay(),
+ &self.context.destination_script, (funding_txo, funding_txo_script),
+ &self.context.channel_transaction_parameters,
+ funding_redeemscript.clone(), self.context.channel_value_satoshis,
+ obscure_factor,
+ holder_commitment_tx, best_block, self.context.counterparty_node_id);
+ channel_monitor.provide_initial_counterparty_commitment_tx(
+ counterparty_initial_bitcoin_tx.txid, Vec::new(),
+ self.context.cur_counterparty_commitment_transaction_number,
+ self.context.counterparty_cur_commitment_point.unwrap(),
+ counterparty_initial_commitment_tx.feerate_per_kw(),
+ counterparty_initial_commitment_tx.to_broadcaster_value_sat(),
+ counterparty_initial_commitment_tx.to_countersignatory_value_sat(), logger);
+
+ assert!(!self.context.channel_state.is_monitor_update_in_progress()); // We have no had any monitor(s) yet to fail update!
+ if self.context.is_batch_funding() {
+ self.context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::WAITING_FOR_BATCH);
+ } else {
+ self.context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
+ }
+ self.context.cur_holder_commitment_transaction_number -= 1;
+ self.context.cur_counterparty_commitment_transaction_number -= 1;
+
+ log_info!(logger, "Received funding_signed from peer for channel {}", &self.context.channel_id());
+
+ let mut channel = Channel { context: self.context };
+
+ let need_channel_ready = channel.check_get_channel_ready(0).is_some();
+ channel.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
+ Ok((channel, channel_monitor))
+ }
+
+ /// Indicates that the signer may have some signatures for us, so we should retry if we're
+ /// blocked.
+ #[allow(unused)]
+ pub fn signer_maybe_unblocked<L: Deref>(&mut self, logger: &L) -> Option<msgs::FundingCreated> where L::Target: Logger {
+ if self.context.signer_pending_funding && self.context.is_outbound() {
+ log_trace!(logger, "Signer unblocked a funding_created");
+ self.get_funding_created_msg(logger)
+ } else { None }
+ }
}
/// A not-yet-funded inbound (from counterparty) channel using V1 channel establishment.
// Now that we're past error-generating stuff, update our local state:
- self.context.channel_state = ChannelState::FundingSent(FundingSentFlags::new());
+ self.context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
self.context.channel_id = funding_txo.to_channel_id();
self.context.cur_counterparty_commitment_transaction_number -= 1;
self.context.cur_holder_commitment_transaction_number -= 1;
funding_redeemscript.clone(), self.context.channel_value_satoshis,
obscure_factor,
holder_commitment_tx, best_block, self.context.counterparty_node_id);
- let logger_with_chan_monitor = WithChannelMonitor::from(logger, &channel_monitor);
channel_monitor.provide_initial_counterparty_commitment_tx(
counterparty_initial_commitment_tx.trust().txid(), Vec::new(),
self.context.cur_counterparty_commitment_transaction_number + 1,
self.context.counterparty_cur_commitment_point.unwrap(), self.context.feerate_per_kw,
counterparty_initial_commitment_tx.to_broadcaster_value_sat(),
- counterparty_initial_commitment_tx.to_countersignatory_value_sat(), &&logger_with_chan_monitor);
+ counterparty_initial_commitment_tx.to_countersignatory_value_sat(), logger);
log_info!(logger, "{} funding_signed for peer for channel {}",
if funding_signed.is_some() { "Generated" } else { "Waiting for signature on" }, &self.context.channel_id());
self.context.channel_id.write(writer)?;
{
let mut channel_state = self.context.channel_state;
- if matches!(channel_state, ChannelState::FundingSent(_)|ChannelState::ChannelReady(_)) {
+ if matches!(channel_state, ChannelState::AwaitingChannelReady(_)|ChannelState::ChannelReady(_)) {
channel_state.set_peer_disconnected();
}
channel_state.to_u32().write(writer)?;
let mut pending_outbound_blinding_points: Vec<Option<PublicKey>> = Vec::new();
(self.context.pending_outbound_htlcs.len() as u64).write(writer)?;
- for (idx, htlc) in self.context.pending_outbound_htlcs.iter().enumerate() {
+ for htlc in self.context.pending_outbound_htlcs.iter() {
htlc.htlc_id.write(writer)?;
htlc.amount_msat.write(writer)?;
htlc.cltv_expiry.write(writer)?;
reason.write(writer)?;
}
}
- if let Some(skimmed_fee) = htlc.skimmed_fee_msat {
- if pending_outbound_skimmed_fees.is_empty() {
- for _ in 0..idx { pending_outbound_skimmed_fees.push(None); }
- }
- pending_outbound_skimmed_fees.push(Some(skimmed_fee));
- } else if !pending_outbound_skimmed_fees.is_empty() {
- pending_outbound_skimmed_fees.push(None);
- }
+ pending_outbound_skimmed_fees.push(htlc.skimmed_fee_msat);
pending_outbound_blinding_points.push(htlc.blinding_point);
}
let mut holding_cell_skimmed_fees: Vec<Option<u64>> = Vec::new();
let mut holding_cell_blinding_points: Vec<Option<PublicKey>> = Vec::new();
(self.context.holding_cell_htlc_updates.len() as u64).write(writer)?;
- for (idx, update) in self.context.holding_cell_htlc_updates.iter().enumerate() {
+ for update in self.context.holding_cell_htlc_updates.iter() {
match update {
&HTLCUpdateAwaitingACK::AddHTLC {
ref amount_msat, ref cltv_expiry, ref payment_hash, ref source, ref onion_routing_packet,
source.write(writer)?;
onion_routing_packet.write(writer)?;
- if let Some(skimmed_fee) = skimmed_fee_msat {
- if holding_cell_skimmed_fees.is_empty() {
- for _ in 0..idx { holding_cell_skimmed_fees.push(None); }
- }
- holding_cell_skimmed_fees.push(Some(skimmed_fee));
- } else if !holding_cell_skimmed_fees.is_empty() { holding_cell_skimmed_fees.push(None); }
-
+ holding_cell_skimmed_fees.push(skimmed_fee_msat);
holding_cell_blinding_points.push(blinding_point);
},
&HTLCUpdateAwaitingACK::ClaimHTLC { ref payment_preimage, ref htlc_id } => {
let mut holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id);
// If we've gotten to the funding stage of the channel, populate the signer with its
// required channel parameters.
- if channel_state >= ChannelState::FundingCreated {
+ if channel_state >= ChannelState::FundingNegotiated {
holder_signer.provide_channel_parameters(&channel_parameters);
}
(channel_keys_id, holder_signer)
use crate::ln::channel_keys::{RevocationKey, RevocationBasepoint};
use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
use crate::ln::channel::InitFeatures;
- use crate::ln::channel::{FundingSentFlags, Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_msat};
+ use crate::ln::channel::{AwaitingChannelReadyFlags, Channel, ChannelState, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, commit_tx_fee_msat};
use crate::ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS};
use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, NodeFeatures};
use crate::ln::msgs;
value: 10000000, script_pubkey: output_script.clone(),
}]};
let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
- let (mut node_a_chan, funding_created_msg) = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, false, &&logger).map_err(|_| ()).unwrap();
+ let funding_created_msg = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, false, &&logger).map_err(|_| ()).unwrap();
let (_, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg.unwrap(), best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap();
// Node B --> Node A: funding signed
- let _ = node_a_chan.funding_signed(&funding_signed_msg.unwrap(), best_block, &&keys_provider, &&logger).unwrap();
+ let res = node_a_chan.funding_signed(&funding_signed_msg.unwrap(), best_block, &&keys_provider, &&logger);
+ let (mut node_a_chan, _) = if let Ok(res) = res { res } else { panic!(); };
// Put some inbound and outbound HTLCs in A's channel.
let htlc_amount_msat = 11_092_000; // put an amount below A's effective dust limit but above B's.
value: 10000000, script_pubkey: output_script.clone(),
}]};
let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
- let (mut node_a_chan, funding_created_msg) = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, false, &&logger).map_err(|_| ()).unwrap();
+ let funding_created_msg = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, false, &&logger).map_err(|_| ()).unwrap();
let (mut node_b_chan, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg.unwrap(), best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap();
// Node B --> Node A: funding signed
- let _ = node_a_chan.funding_signed(&funding_signed_msg.unwrap(), best_block, &&keys_provider, &&logger).unwrap();
+ let res = node_a_chan.funding_signed(&funding_signed_msg.unwrap(), best_block, &&keys_provider, &&logger);
+ let (mut node_a_chan, _) = if let Ok(res) = res { res } else { panic!(); };
// Now disconnect the two nodes and check that the commitment point in
// Node B's channel_reestablish message is sane.
value: 10000000, script_pubkey: output_script.clone(),
}]};
let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
- let (mut node_a_chan, funding_created_msg) = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, false, &&logger).map_err(|_| ()).unwrap();
+ let funding_created_msg = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, false, &&logger).map_err(|_| ()).unwrap();
let (_, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg.unwrap(), best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap();
// Node B --> Node A: funding signed
- let _ = node_a_chan.funding_signed(&funding_signed_msg.unwrap(), best_block, &&keys_provider, &&logger).unwrap();
+ let res = node_a_chan.funding_signed(&funding_signed_msg.unwrap(), best_block, &&keys_provider, &&logger);
+ let (mut node_a_chan, _) = if let Ok(res) = res { res } else { panic!(); };
// Make sure that receiving a channel update will update the Channel as expected.
let update = ChannelUpdate {
}
#[test]
- fn blinding_point_ser() {
- // Ensure that channel blinding points are (de)serialized properly.
+ fn blinding_point_skimmed_fee_ser() {
+ // Ensure that channel blinding points and skimmed fees are (de)serialized properly.
let feeest = LowerBoundedFeeEstimator::new(&TestFeeEstimator{fee_est: 15000});
let secp_ctx = Secp256k1::new();
let seed = [42; 32];
if idx % 2 == 0 {
htlc.blinding_point = Some(test_utils::pubkey(42 + idx as u8));
}
+ if idx % 3 == 0 {
+ htlc.skimmed_fee_msat = Some(1);
+ }
}
chan.context.pending_outbound_htlcs = pending_outbound_htlcs.clone();
holding_cell_htlc_updates.push(dummy_holding_cell_claim_htlc.clone());
} else {
let mut dummy_add = dummy_holding_cell_add_htlc.clone();
- if let HTLCUpdateAwaitingACK::AddHTLC { ref mut blinding_point, .. } = &mut dummy_add {
+ if let HTLCUpdateAwaitingACK::AddHTLC {
+ ref mut blinding_point, ref mut skimmed_fee_msat, ..
+ } = &mut dummy_add {
*blinding_point = Some(test_utils::pubkey(42 + i));
+ *skimmed_fee_msat = Some(42);
} else { panic!() }
holding_cell_htlc_updates.push(dummy_add);
}
},
]};
let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
- let (mut node_a_chan, funding_created_msg) = node_a_chan.get_funding_created(
- tx.clone(),
- funding_outpoint,
- true,
- &&logger,
+ let funding_created_msg = node_a_chan.get_funding_created(
+ tx.clone(), funding_outpoint, true, &&logger,
).map_err(|_| ()).unwrap();
let (mut node_b_chan, funding_signed_msg, _) = node_b_chan.funding_created(
&funding_created_msg.unwrap(),
// Receive funding_signed, but the channel will be configured to hold sending channel_ready and
// broadcasting the funding transaction until the batch is ready.
- let _ = node_a_chan.funding_signed(
- &funding_signed_msg.unwrap(),
- best_block,
- &&keys_provider,
- &&logger,
- ).unwrap();
+ let res = node_a_chan.funding_signed(
+ &funding_signed_msg.unwrap(), best_block, &&keys_provider, &&logger,
+ );
+ let (mut node_a_chan, _) = if let Ok(res) = res { res } else { panic!(); };
let node_a_updates = node_a_chan.monitor_updating_restored(
&&logger,
&&keys_provider,
// as the funding transaction depends on all channels in the batch becoming ready.
assert!(node_a_updates.channel_ready.is_none());
assert!(node_a_updates.funding_broadcastable.is_none());
- assert_eq!(node_a_chan.context.channel_state, ChannelState::FundingSent(FundingSentFlags::WAITING_FOR_BATCH));
+ assert_eq!(node_a_chan.context.channel_state, ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::WAITING_FOR_BATCH));
// It is possible to receive a 0conf channel_ready from the remote node.
node_a_chan.channel_ready(
).unwrap();
assert_eq!(
node_a_chan.context.channel_state,
- ChannelState::FundingSent(FundingSentFlags::WAITING_FOR_BATCH | FundingSentFlags::THEIR_CHANNEL_READY)
+ ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::WAITING_FOR_BATCH | AwaitingChannelReadyFlags::THEIR_CHANNEL_READY)
);
// Clear the ChannelState::WaitingForBatch only when called by ChannelManager.
node_a_chan.set_batch_ready();
- assert_eq!(node_a_chan.context.channel_state, ChannelState::FundingSent(FundingSentFlags::THEIR_CHANNEL_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());
}
}