pub fn is_funding_initiated(&self) -> bool {
self.channel_state >= ChannelState::FundingSent as u32
}
+
+ /// Transaction nomenclature is somewhat confusing here as there are many different cases - a
+ /// transaction is referred to as "a's transaction" implying that a will be able to broadcast
+ /// the transaction. Thus, b will generally be sending a signature over such a transaction to
+ /// a, and a can revoke the transaction by providing b the relevant per_commitment_secret. As
+ /// such, a transaction is generally the result of b increasing the amount paid to a (or adding
+ /// an HTLC to a).
+ /// @local is used only to convert relevant internal structures which refer to remote vs local
+ /// to decide value of outputs and direction of HTLCs.
+ /// @generated_by_local is used to determine *which* HTLCs to include - noting that the HTLC
+ /// state may indicate that one peer has informed the other that they'd like to add an HTLC but
+ /// have not yet committed it. Such HTLCs will only be included in transactions which are being
+ /// generated by the peer which proposed adding the HTLCs, and thus we need to understand both
+ /// which peer generated this transaction and "to whom" this transaction flows.
+ #[inline]
+ fn build_commitment_transaction<L: Deref>(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, logger: &L) -> CommitmentStats
+ where L::Target: Logger
+ {
+ let mut included_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::new();
+ let num_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len();
+ let mut included_non_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(num_htlcs);
+
+ let broadcaster_dust_limit_satoshis = if local { self.holder_dust_limit_satoshis } else { self.counterparty_dust_limit_satoshis };
+ let mut remote_htlc_total_msat = 0;
+ let mut local_htlc_total_msat = 0;
+ let mut value_to_self_msat_offset = 0;
+
+ let mut feerate_per_kw = self.feerate_per_kw;
+ if let Some((feerate, update_state)) = self.pending_update_fee {
+ if match update_state {
+ // Note that these match the inclusion criteria when scanning
+ // pending_inbound_htlcs below.
+ FeeUpdateState::RemoteAnnounced => { debug_assert!(!self.is_outbound()); !generated_by_local },
+ FeeUpdateState::AwaitingRemoteRevokeToAnnounce => { debug_assert!(!self.is_outbound()); !generated_by_local },
+ FeeUpdateState::Outbound => { assert!(self.is_outbound()); generated_by_local },
+ } {
+ feerate_per_kw = feerate;
+ }
+ }
+
+ log_trace!(logger, "Building commitment transaction number {} (really {} xor {}) for channel {} for {}, generated by {} with fee {}...",
+ commitment_number, (INITIAL_COMMITMENT_NUMBER - commitment_number),
+ get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound()),
+ log_bytes!(self.channel_id), if local { "us" } else { "remote" }, if generated_by_local { "us" } else { "remote" }, feerate_per_kw);
+
+ macro_rules! get_htlc_in_commitment {
+ ($htlc: expr, $offered: expr) => {
+ HTLCOutputInCommitment {
+ offered: $offered,
+ amount_msat: $htlc.amount_msat,
+ cltv_expiry: $htlc.cltv_expiry,
+ payment_hash: $htlc.payment_hash,
+ transaction_output_index: None
+ }
+ }
+ }
+
+ macro_rules! add_htlc_output {
+ ($htlc: expr, $outbound: expr, $source: expr, $state_name: expr) => {
+ if $outbound == local { // "offered HTLC output"
+ let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
+ let htlc_tx_fee = if self.opt_anchors() {
+ 0
+ } else {
+ feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000
+ };
+ if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee {
+ log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
+ included_non_dust_htlcs.push((htlc_in_tx, $source));
+ } else {
+ log_trace!(logger, " ...including {} {} dust HTLC {} (hash {}) with value {} due to dust limit", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
+ included_dust_htlcs.push((htlc_in_tx, $source));
+ }
+ } else {
+ let htlc_in_tx = get_htlc_in_commitment!($htlc, false);
+ let htlc_tx_fee = if self.opt_anchors() {
+ 0
+ } else {
+ feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000
+ };
+ if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee {
+ log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
+ included_non_dust_htlcs.push((htlc_in_tx, $source));
+ } else {
+ log_trace!(logger, " ...including {} {} dust HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
+ included_dust_htlcs.push((htlc_in_tx, $source));
+ }
+ }
+ }
+ }
+
+ for ref htlc in self.pending_inbound_htlcs.iter() {
+ let (include, state_name) = match htlc.state {
+ InboundHTLCState::RemoteAnnounced(_) => (!generated_by_local, "RemoteAnnounced"),
+ InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) => (!generated_by_local, "AwaitingRemoteRevokeToAnnounce"),
+ InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) => (true, "AwaitingAnnouncedRemoteRevoke"),
+ InboundHTLCState::Committed => (true, "Committed"),
+ InboundHTLCState::LocalRemoved(_) => (!generated_by_local, "LocalRemoved"),
+ };
+
+ if include {
+ add_htlc_output!(htlc, false, None, state_name);
+ remote_htlc_total_msat += htlc.amount_msat;
+ } else {
+ log_trace!(logger, " ...not including inbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, log_bytes!(htlc.payment_hash.0), htlc.amount_msat, state_name);
+ match &htlc.state {
+ &InboundHTLCState::LocalRemoved(ref reason) => {
+ if generated_by_local {
+ if let &InboundHTLCRemovalReason::Fulfill(_) = reason {
+ value_to_self_msat_offset += htlc.amount_msat as i64;
+ }
+ }
+ },
+ _ => {},
+ }
+ }
+ }
+
+ let mut preimages: Vec<PaymentPreimage> = Vec::new();
+
+ for ref htlc in self.pending_outbound_htlcs.iter() {
+ let (include, state_name) = match htlc.state {
+ OutboundHTLCState::LocalAnnounced(_) => (generated_by_local, "LocalAnnounced"),
+ OutboundHTLCState::Committed => (true, "Committed"),
+ OutboundHTLCState::RemoteRemoved(_) => (generated_by_local, "RemoteRemoved"),
+ OutboundHTLCState::AwaitingRemoteRevokeToRemove(_) => (generated_by_local, "AwaitingRemoteRevokeToRemove"),
+ OutboundHTLCState::AwaitingRemovedRemoteRevoke(_) => (false, "AwaitingRemovedRemoteRevoke"),
+ };
+
+ let preimage_opt = match htlc.state {
+ OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(p)) => p,
+ OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(p)) => p,
+ OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(p)) => p,
+ _ => None,
+ };
+
+ if let Some(preimage) = preimage_opt {
+ preimages.push(preimage);
+ }
+
+ if include {
+ add_htlc_output!(htlc, true, Some(&htlc.source), state_name);
+ local_htlc_total_msat += htlc.amount_msat;
+ } else {
+ log_trace!(logger, " ...not including outbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, log_bytes!(htlc.payment_hash.0), htlc.amount_msat, state_name);
+ match htlc.state {
+ OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_))|OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_)) => {
+ value_to_self_msat_offset -= htlc.amount_msat as i64;
+ },
+ OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(_)) => {
+ if !generated_by_local {
+ value_to_self_msat_offset -= htlc.amount_msat as i64;
+ }
+ },
+ _ => {},
+ }
+ }
+ }
+
+ let mut value_to_self_msat: i64 = (self.value_to_self_msat - local_htlc_total_msat) as i64 + value_to_self_msat_offset;
+ assert!(value_to_self_msat >= 0);
+ // Note that in case they have several just-awaiting-last-RAA fulfills in-progress (ie
+ // AwaitingRemoteRevokeToRemove or AwaitingRemovedRemoteRevoke) we may have allowed them to
+ // "violate" their reserve value by couting those against it. Thus, we have to convert
+ // everything to i64 before subtracting as otherwise we can overflow.
+ let mut value_to_remote_msat: i64 = (self.channel_value_satoshis * 1000) as i64 - (self.value_to_self_msat as i64) - (remote_htlc_total_msat as i64) - value_to_self_msat_offset;
+ assert!(value_to_remote_msat >= 0);
+
+ #[cfg(debug_assertions)]
+ {
+ // Make sure that the to_self/to_remote is always either past the appropriate
+ // channel_reserve *or* it is making progress towards it.
+ let mut broadcaster_max_commitment_tx_output = if generated_by_local {
+ self.holder_max_commitment_tx_output.lock().unwrap()
+ } else {
+ self.counterparty_max_commitment_tx_output.lock().unwrap()
+ };
+ debug_assert!(broadcaster_max_commitment_tx_output.0 <= value_to_self_msat as u64 || value_to_self_msat / 1000 >= self.counterparty_selected_channel_reserve_satoshis.unwrap() as i64);
+ broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, value_to_self_msat as u64);
+ debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat as u64 || value_to_remote_msat / 1000 >= self.holder_selected_channel_reserve_satoshis as i64);
+ broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat as u64);
+ }
+
+ let total_fee_sat = commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len(), self.channel_transaction_parameters.opt_anchors.is_some());
+ let anchors_val = if self.channel_transaction_parameters.opt_anchors.is_some() { ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 } as i64;
+ let (value_to_self, value_to_remote) = if self.is_outbound() {
+ (value_to_self_msat / 1000 - anchors_val - total_fee_sat as i64, value_to_remote_msat / 1000)
+ } else {
+ (value_to_self_msat / 1000, value_to_remote_msat / 1000 - anchors_val - total_fee_sat as i64)
+ };
+
+ let mut value_to_a = if local { value_to_self } else { value_to_remote };
+ let mut value_to_b = if local { value_to_remote } else { value_to_self };
+ let (funding_pubkey_a, funding_pubkey_b) = if local {
+ (self.get_holder_pubkeys().funding_pubkey, self.get_counterparty_pubkeys().funding_pubkey)
+ } else {
+ (self.get_counterparty_pubkeys().funding_pubkey, self.get_holder_pubkeys().funding_pubkey)
+ };
+
+ if value_to_a >= (broadcaster_dust_limit_satoshis as i64) {
+ log_trace!(logger, " ...including {} output with value {}", if local { "to_local" } else { "to_remote" }, value_to_a);
+ } else {
+ value_to_a = 0;
+ }
+
+ if value_to_b >= (broadcaster_dust_limit_satoshis as i64) {
+ log_trace!(logger, " ...including {} output with value {}", if local { "to_remote" } else { "to_local" }, value_to_b);
+ } else {
+ value_to_b = 0;
+ }
+
+ let num_nondust_htlcs = included_non_dust_htlcs.len();
+
+ let channel_parameters =
+ if local { self.channel_transaction_parameters.as_holder_broadcastable() }
+ else { self.channel_transaction_parameters.as_counterparty_broadcastable() };
+ let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number,
+ value_to_a as u64,
+ value_to_b as u64,
+ self.channel_transaction_parameters.opt_anchors.is_some(),
+ funding_pubkey_a,
+ funding_pubkey_b,
+ keys.clone(),
+ feerate_per_kw,
+ &mut included_non_dust_htlcs,
+ &channel_parameters
+ );
+ let mut htlcs_included = included_non_dust_htlcs;
+ // The unwrap is safe, because all non-dust HTLCs have been assigned an output index
+ htlcs_included.sort_unstable_by_key(|h| h.0.transaction_output_index.unwrap());
+ htlcs_included.append(&mut included_dust_htlcs);
+
+ // For the stats, trimmed-to-0 the value in msats accordingly
+ value_to_self_msat = if (value_to_self_msat * 1000) < broadcaster_dust_limit_satoshis as i64 { 0 } else { value_to_self_msat };
+ value_to_remote_msat = if (value_to_remote_msat * 1000) < broadcaster_dust_limit_satoshis as i64 { 0 } else { value_to_remote_msat };
+
+ CommitmentStats {
+ tx,
+ feerate_per_kw,
+ total_fee_sat,
+ num_nondust_htlcs,
+ htlcs_included,
+ local_balance_msat: value_to_self_msat as u64,
+ remote_balance_msat: value_to_remote_msat as u64,
+ preimages
+ }
+ }
+
+ #[inline]
+ /// Creates a set of keys for build_commitment_transaction to generate a transaction which our
+ /// counterparty will sign (ie DO NOT send signatures over a transaction created by this to
+ /// 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.get_per_commitment_point(commitment_number, &self.secp_ctx);
+ 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();
+
+ TxCreationKeys::derive_new(&self.secp_ctx, &per_commitment_point, delayed_payment_base, htlc_basepoint, &counterparty_pubkeys.revocation_basepoint, &counterparty_pubkeys.htlc_basepoint)
+ }
+
+ #[inline]
+ /// Creates a set of keys for build_commitment_transaction to generate a transaction which we
+ /// will sign and send to our counterparty.
+ /// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created)
+ fn build_remote_transaction_keys(&self) -> TxCreationKeys {
+ //TODO: Ensure that the payment_key derived here ends up in the library users' wallet as we
+ //may see payments to it!
+ let revocation_basepoint = &self.get_holder_pubkeys().revocation_basepoint;
+ let htlc_basepoint = &self.get_holder_pubkeys().htlc_basepoint;
+ let counterparty_pubkeys = self.get_counterparty_pubkeys();
+
+ TxCreationKeys::derive_new(&self.secp_ctx, &self.counterparty_cur_commitment_point.unwrap(), &counterparty_pubkeys.delayed_payment_basepoint, &counterparty_pubkeys.htlc_basepoint, revocation_basepoint, htlc_basepoint)
+ }
+
+ /// Gets the redeemscript for the funding transaction output (ie the funding transaction output
+ /// pays to get_funding_redeemscript().to_v0_p2wsh()).
+ /// Panics if called before accept_channel/new_from_req
+ pub fn get_funding_redeemscript(&self) -> Script {
+ make_funding_redeemscript(&self.get_holder_pubkeys().funding_pubkey, self.counterparty_funding_pubkey())
+ }
+
+ fn counterparty_funding_pubkey(&self) -> &PublicKey {
+ &self.get_counterparty_pubkeys().funding_pubkey
+ }
}
// Internal utility functions for channels
cmp::min(channel_value_satoshis, cmp::max(q, 1000))
}
+// Get the fee cost in SATS of a commitment tx with a given number of HTLC outputs.
+// Note that num_htlcs should not include dust HTLCs.
+#[inline]
+fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize, opt_anchors: bool) -> u64 {
+ feerate_per_kw as u64 * (commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000
+}
+
// TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking
// has been completed, and then turn into a Channel to get compiler-time enforcement of things like
// calling channel_id() before we're set up or things like get_outbound_funding_signed on an
Ok(chan)
}
- /// Transaction nomenclature is somewhat confusing here as there are many different cases - a
- /// transaction is referred to as "a's transaction" implying that a will be able to broadcast
- /// the transaction. Thus, b will generally be sending a signature over such a transaction to
- /// a, and a can revoke the transaction by providing b the relevant per_commitment_secret. As
- /// such, a transaction is generally the result of b increasing the amount paid to a (or adding
- /// an HTLC to a).
- /// @local is used only to convert relevant internal structures which refer to remote vs local
- /// to decide value of outputs and direction of HTLCs.
- /// @generated_by_local is used to determine *which* HTLCs to include - noting that the HTLC
- /// state may indicate that one peer has informed the other that they'd like to add an HTLC but
- /// have not yet committed it. Such HTLCs will only be included in transactions which are being
- /// generated by the peer which proposed adding the HTLCs, and thus we need to understand both
- /// which peer generated this transaction and "to whom" this transaction flows.
- #[inline]
- fn build_commitment_transaction<L: Deref>(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, logger: &L) -> CommitmentStats
- where L::Target: Logger
- {
- let mut included_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::new();
- let num_htlcs = self.context.pending_inbound_htlcs.len() + self.context.pending_outbound_htlcs.len();
- let mut included_non_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(num_htlcs);
-
- let broadcaster_dust_limit_satoshis = if local { self.context.holder_dust_limit_satoshis } else { self.context.counterparty_dust_limit_satoshis };
- let mut remote_htlc_total_msat = 0;
- let mut local_htlc_total_msat = 0;
- let mut value_to_self_msat_offset = 0;
-
- let mut feerate_per_kw = self.context.feerate_per_kw;
- if let Some((feerate, update_state)) = self.context.pending_update_fee {
- if match update_state {
- // Note that these match the inclusion criteria when scanning
- // pending_inbound_htlcs below.
- FeeUpdateState::RemoteAnnounced => { debug_assert!(!self.context.is_outbound()); !generated_by_local },
- FeeUpdateState::AwaitingRemoteRevokeToAnnounce => { debug_assert!(!self.context.is_outbound()); !generated_by_local },
- FeeUpdateState::Outbound => { assert!(self.context.is_outbound()); generated_by_local },
- } {
- feerate_per_kw = feerate;
- }
- }
-
- log_trace!(logger, "Building commitment transaction number {} (really {} xor {}) for channel {} for {}, generated by {} with fee {}...",
- commitment_number, (INITIAL_COMMITMENT_NUMBER - commitment_number),
- get_commitment_transaction_number_obscure_factor(&self.context.get_holder_pubkeys().payment_point, &self.context.get_counterparty_pubkeys().payment_point, self.context.is_outbound()),
- log_bytes!(self.context.channel_id), if local { "us" } else { "remote" }, if generated_by_local { "us" } else { "remote" }, feerate_per_kw);
-
- macro_rules! get_htlc_in_commitment {
- ($htlc: expr, $offered: expr) => {
- HTLCOutputInCommitment {
- offered: $offered,
- amount_msat: $htlc.amount_msat,
- cltv_expiry: $htlc.cltv_expiry,
- payment_hash: $htlc.payment_hash,
- transaction_output_index: None
- }
- }
- }
-
- macro_rules! add_htlc_output {
- ($htlc: expr, $outbound: expr, $source: expr, $state_name: expr) => {
- if $outbound == local { // "offered HTLC output"
- let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
- let htlc_tx_fee = if self.context.opt_anchors() {
- 0
- } else {
- feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000
- };
- if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee {
- log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
- included_non_dust_htlcs.push((htlc_in_tx, $source));
- } else {
- log_trace!(logger, " ...including {} {} dust HTLC {} (hash {}) with value {} due to dust limit", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
- included_dust_htlcs.push((htlc_in_tx, $source));
- }
- } else {
- let htlc_in_tx = get_htlc_in_commitment!($htlc, false);
- let htlc_tx_fee = if self.context.opt_anchors() {
- 0
- } else {
- feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000
- };
- if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee {
- log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
- included_non_dust_htlcs.push((htlc_in_tx, $source));
- } else {
- log_trace!(logger, " ...including {} {} dust HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
- included_dust_htlcs.push((htlc_in_tx, $source));
- }
- }
- }
- }
-
- for ref htlc in self.context.pending_inbound_htlcs.iter() {
- let (include, state_name) = match htlc.state {
- InboundHTLCState::RemoteAnnounced(_) => (!generated_by_local, "RemoteAnnounced"),
- InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) => (!generated_by_local, "AwaitingRemoteRevokeToAnnounce"),
- InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) => (true, "AwaitingAnnouncedRemoteRevoke"),
- InboundHTLCState::Committed => (true, "Committed"),
- InboundHTLCState::LocalRemoved(_) => (!generated_by_local, "LocalRemoved"),
- };
-
- if include {
- add_htlc_output!(htlc, false, None, state_name);
- remote_htlc_total_msat += htlc.amount_msat;
- } else {
- log_trace!(logger, " ...not including inbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, log_bytes!(htlc.payment_hash.0), htlc.amount_msat, state_name);
- match &htlc.state {
- &InboundHTLCState::LocalRemoved(ref reason) => {
- if generated_by_local {
- if let &InboundHTLCRemovalReason::Fulfill(_) = reason {
- value_to_self_msat_offset += htlc.amount_msat as i64;
- }
- }
- },
- _ => {},
- }
- }
- }
-
- let mut preimages: Vec<PaymentPreimage> = Vec::new();
-
- for ref htlc in self.context.pending_outbound_htlcs.iter() {
- let (include, state_name) = match htlc.state {
- OutboundHTLCState::LocalAnnounced(_) => (generated_by_local, "LocalAnnounced"),
- OutboundHTLCState::Committed => (true, "Committed"),
- OutboundHTLCState::RemoteRemoved(_) => (generated_by_local, "RemoteRemoved"),
- OutboundHTLCState::AwaitingRemoteRevokeToRemove(_) => (generated_by_local, "AwaitingRemoteRevokeToRemove"),
- OutboundHTLCState::AwaitingRemovedRemoteRevoke(_) => (false, "AwaitingRemovedRemoteRevoke"),
- };
-
- let preimage_opt = match htlc.state {
- OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(p)) => p,
- OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(p)) => p,
- OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(p)) => p,
- _ => None,
- };
-
- if let Some(preimage) = preimage_opt {
- preimages.push(preimage);
- }
-
- if include {
- add_htlc_output!(htlc, true, Some(&htlc.source), state_name);
- local_htlc_total_msat += htlc.amount_msat;
- } else {
- log_trace!(logger, " ...not including outbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, log_bytes!(htlc.payment_hash.0), htlc.amount_msat, state_name);
- match htlc.state {
- OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_))|OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_)) => {
- value_to_self_msat_offset -= htlc.amount_msat as i64;
- },
- OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(_)) => {
- if !generated_by_local {
- value_to_self_msat_offset -= htlc.amount_msat as i64;
- }
- },
- _ => {},
- }
- }
- }
-
- let mut value_to_self_msat: i64 = (self.context.value_to_self_msat - local_htlc_total_msat) as i64 + value_to_self_msat_offset;
- assert!(value_to_self_msat >= 0);
- // Note that in case they have several just-awaiting-last-RAA fulfills in-progress (ie
- // AwaitingRemoteRevokeToRemove or AwaitingRemovedRemoteRevoke) we may have allowed them to
- // "violate" their reserve value by couting those against it. Thus, we have to convert
- // everything to i64 before subtracting as otherwise we can overflow.
- let mut value_to_remote_msat: i64 = (self.context.channel_value_satoshis * 1000) as i64 - (self.context.value_to_self_msat as i64) - (remote_htlc_total_msat as i64) - value_to_self_msat_offset;
- assert!(value_to_remote_msat >= 0);
-
- #[cfg(debug_assertions)]
- {
- // Make sure that the to_self/to_remote is always either past the appropriate
- // channel_reserve *or* it is making progress towards it.
- let mut broadcaster_max_commitment_tx_output = if generated_by_local {
- self.context.holder_max_commitment_tx_output.lock().unwrap()
- } else {
- self.context.counterparty_max_commitment_tx_output.lock().unwrap()
- };
- debug_assert!(broadcaster_max_commitment_tx_output.0 <= value_to_self_msat as u64 || value_to_self_msat / 1000 >= self.context.counterparty_selected_channel_reserve_satoshis.unwrap() as i64);
- broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, value_to_self_msat as u64);
- debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat as u64 || value_to_remote_msat / 1000 >= self.context.holder_selected_channel_reserve_satoshis as i64);
- broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat as u64);
- }
-
- let total_fee_sat = Channel::<Signer>::commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len(), self.context.channel_transaction_parameters.opt_anchors.is_some());
- let anchors_val = if self.context.channel_transaction_parameters.opt_anchors.is_some() { ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 } as i64;
- let (value_to_self, value_to_remote) = if self.context.is_outbound() {
- (value_to_self_msat / 1000 - anchors_val - total_fee_sat as i64, value_to_remote_msat / 1000)
- } else {
- (value_to_self_msat / 1000, value_to_remote_msat / 1000 - anchors_val - total_fee_sat as i64)
- };
-
- let mut value_to_a = if local { value_to_self } else { value_to_remote };
- let mut value_to_b = if local { value_to_remote } else { value_to_self };
- let (funding_pubkey_a, funding_pubkey_b) = if local {
- (self.context.get_holder_pubkeys().funding_pubkey, self.context.get_counterparty_pubkeys().funding_pubkey)
- } else {
- (self.context.get_counterparty_pubkeys().funding_pubkey, self.context.get_holder_pubkeys().funding_pubkey)
- };
-
- if value_to_a >= (broadcaster_dust_limit_satoshis as i64) {
- log_trace!(logger, " ...including {} output with value {}", if local { "to_local" } else { "to_remote" }, value_to_a);
- } else {
- value_to_a = 0;
- }
-
- if value_to_b >= (broadcaster_dust_limit_satoshis as i64) {
- log_trace!(logger, " ...including {} output with value {}", if local { "to_remote" } else { "to_local" }, value_to_b);
- } else {
- value_to_b = 0;
- }
-
- let num_nondust_htlcs = included_non_dust_htlcs.len();
-
- let channel_parameters =
- if local { self.context.channel_transaction_parameters.as_holder_broadcastable() }
- else { self.context.channel_transaction_parameters.as_counterparty_broadcastable() };
- let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number,
- value_to_a as u64,
- value_to_b as u64,
- self.context.channel_transaction_parameters.opt_anchors.is_some(),
- funding_pubkey_a,
- funding_pubkey_b,
- keys.clone(),
- feerate_per_kw,
- &mut included_non_dust_htlcs,
- &channel_parameters
- );
- let mut htlcs_included = included_non_dust_htlcs;
- // The unwrap is safe, because all non-dust HTLCs have been assigned an output index
- htlcs_included.sort_unstable_by_key(|h| h.0.transaction_output_index.unwrap());
- htlcs_included.append(&mut included_dust_htlcs);
-
- // For the stats, trimmed-to-0 the value in msats accordingly
- value_to_self_msat = if (value_to_self_msat * 1000) < broadcaster_dust_limit_satoshis as i64 { 0 } else { value_to_self_msat };
- value_to_remote_msat = if (value_to_remote_msat * 1000) < broadcaster_dust_limit_satoshis as i64 { 0 } else { value_to_remote_msat };
-
- CommitmentStats {
- tx,
- feerate_per_kw,
- total_fee_sat,
- num_nondust_htlcs,
- htlcs_included,
- local_balance_msat: value_to_self_msat as u64,
- remote_balance_msat: value_to_remote_msat as u64,
- preimages
- }
- }
-
#[inline]
fn get_closing_scriptpubkey(&self) -> Script {
// The shutdown scriptpubkey is set on channel opening when option_upfront_shutdown_script
#[inline]
fn get_closing_transaction_weight(&self, a_scriptpubkey: Option<&Script>, b_scriptpubkey: Option<&Script>) -> u64 {
let mut ret =
- (4 + // version
- 1 + // input count
- 36 + // prevout
- 1 + // script length (0)
- 4 + // sequence
- 1 + // output count
- 4 // lock time
- )*4 + // * 4 for non-witness parts
- 2 + // witness marker and flag
- 1 + // witness element count
- 4 + // 4 element lengths (2 sigs, multisig dummy, and witness script)
- self.get_funding_redeemscript().len() as u64 + // funding witness script
- 2*(1 + 71); // two signatures + sighash type flags
+ (4 + // version
+ 1 + // input count
+ 36 + // prevout
+ 1 + // script length (0)
+ 4 + // sequence
+ 1 + // output count
+ 4 // lock time
+ )*4 + // * 4 for non-witness parts
+ 2 + // witness marker and flag
+ 1 + // witness element count
+ 4 + // 4 element lengths (2 sigs, multisig dummy, and witness script)
+ self.context.get_funding_redeemscript().len() as u64 + // funding witness script
+ 2*(1 + 71); // two signatures + sighash type flags
if let Some(spk) = a_scriptpubkey {
- ret += ((8+1) + // output values and script length
- spk.len() as u64) * 4; // scriptpubkey and witness multiplier
+ ret += ((8+1) + // output values and script length
+ spk.len() as u64) * 4; // scriptpubkey and witness multiplier
}
if let Some(spk) = b_scriptpubkey {
- ret += ((8+1) + // output values and script length
- spk.len() as u64) * 4; // scriptpubkey and witness multiplier
+ ret += ((8+1) + // output values and script length
+ spk.len() as u64) * 4; // scriptpubkey and witness multiplier
}
ret
}
self.context.channel_transaction_parameters.funding_outpoint.unwrap()
}
- #[inline]
- /// Creates a set of keys for build_commitment_transaction to generate a transaction which our
- /// counterparty will sign (ie DO NOT send signatures over a transaction created by this to
- /// 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.context.holder_signer.get_per_commitment_point(commitment_number, &self.context.secp_ctx);
- let delayed_payment_base = &self.context.get_holder_pubkeys().delayed_payment_basepoint;
- let htlc_basepoint = &self.context.get_holder_pubkeys().htlc_basepoint;
- let counterparty_pubkeys = self.context.get_counterparty_pubkeys();
-
- TxCreationKeys::derive_new(&self.context.secp_ctx, &per_commitment_point, delayed_payment_base, htlc_basepoint, &counterparty_pubkeys.revocation_basepoint, &counterparty_pubkeys.htlc_basepoint)
- }
-
- #[inline]
- /// Creates a set of keys for build_commitment_transaction to generate a transaction which we
- /// will sign and send to our counterparty.
- /// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created)
- fn build_remote_transaction_keys(&self) -> TxCreationKeys {
- //TODO: Ensure that the payment_key derived here ends up in the library users' wallet as we
- //may see payments to it!
- let revocation_basepoint = &self.context.get_holder_pubkeys().revocation_basepoint;
- let htlc_basepoint = &self.context.get_holder_pubkeys().htlc_basepoint;
- let counterparty_pubkeys = self.context.get_counterparty_pubkeys();
-
- TxCreationKeys::derive_new(&self.context.secp_ctx, &self.context.counterparty_cur_commitment_point.unwrap(), &counterparty_pubkeys.delayed_payment_basepoint, &counterparty_pubkeys.htlc_basepoint, revocation_basepoint, htlc_basepoint)
- }
-
- /// Gets the redeemscript for the funding transaction output (ie the funding transaction output
- /// pays to get_funding_redeemscript().to_v0_p2wsh()).
- /// Panics if called before accept_channel/new_from_req
- pub fn get_funding_redeemscript(&self) -> Script {
- make_funding_redeemscript(&self.context.get_holder_pubkeys().funding_pubkey, self.counterparty_funding_pubkey())
- }
-
/// Claims an HTLC while we're disconnected from a peer, dropping the [`ChannelMonitorUpdate`]
/// entirely.
///
}
fn funding_created_signature<L: Deref>(&mut self, sig: &Signature, logger: &L) -> Result<(Txid, CommitmentTransaction, Signature), ChannelError> where L::Target: Logger {
- let funding_script = self.get_funding_redeemscript();
+ let funding_script = self.context.get_funding_redeemscript();
- let keys = self.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
- let initial_commitment_tx = self.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, false, logger).tx;
+ 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 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 the holder commitment transaction...
log_trace!(logger, "Checking funding_created tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} for channel {}.",
- log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.counterparty_funding_pubkey().serialize()),
+ log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.context.counterparty_funding_pubkey().serialize()),
encode::serialize_hex(&initial_commitment_bitcoin_tx.transaction), log_bytes!(sighash[..]),
encode::serialize_hex(&funding_script), log_bytes!(self.context.channel_id()));
- secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &sig, self.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned());
+ secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &sig, self.context.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned());
}
- let counterparty_keys = self.build_remote_transaction_keys();
- let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
+ 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();
Ok((counterparty_initial_bitcoin_tx.txid, initial_commitment_tx, counterparty_signature))
}
- fn counterparty_funding_pubkey(&self) -> &PublicKey {
- &self.context.get_counterparty_pubkeys().funding_pubkey
- }
-
pub fn funding_created<SP: Deref, L: Deref>(
&mut self, msg: &msgs::FundingCreated, best_block: BestBlock, signer_provider: &SP, logger: &L
) -> Result<(msgs::FundingSigned, ChannelMonitor<Signer>), ChannelError>
msg.signature,
Vec::new(),
&self.context.get_holder_pubkeys().funding_pubkey,
- self.counterparty_funding_pubkey()
+ self.context.counterparty_funding_pubkey()
);
self.context.holder_signer.validate_holder_commitment(&holder_commitment_tx, Vec::new())
.map_err(|_| ChannelError::Close("Failed to validate our commitment".to_owned()))?;
- // Now that we're past error-generating stuff, update our local state:
+ // Now that we're past error-generating stuff, update our local state:
- let funding_redeemscript = self.get_funding_redeemscript();
+ let funding_redeemscript = self.context.get_funding_redeemscript();
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());
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
}
- let funding_script = self.get_funding_redeemscript();
+ let funding_script = self.context.get_funding_redeemscript();
- let counterparty_keys = self.build_remote_transaction_keys();
- let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
+ 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 {}",
log_bytes!(self.context.channel_id()), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
- let holder_signer = self.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
- let initial_commitment_tx = self.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(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();
msg.signature,
Vec::new(),
&self.context.get_holder_pubkeys().funding_pubkey,
- self.counterparty_funding_pubkey()
+ self.context.counterparty_funding_pubkey()
);
self.context.holder_signer.validate_holder_commitment(&holder_commitment_tx, Vec::new())
.map_err(|_| ChannelError::Close("Failed to validate our commitment".to_owned()))?;
- let funding_redeemscript = self.get_funding_redeemscript();
+ 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());
(commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate_per_kw as u64 / 1000 * 1000
}
- // Get the fee cost in SATS of a commitment tx with a given number of HTLC outputs.
- // Note that num_htlcs should not include dust HTLCs.
- #[inline]
- fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize, opt_anchors: bool) -> u64 {
- feerate_per_kw as u64 * (commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000
- }
-
/// Get the commitment tx fee for the local's (i.e. our) next commitment transaction based on the
/// number of pending HTLCs that are on track to be in our next commitment tx.
///
return Err(ChannelError::Close("Peer sent commitment_signed after we'd started exchanging closing_signeds".to_owned()));
}
- let funding_script = self.get_funding_redeemscript();
+ let funding_script = self.context.get_funding_redeemscript();
- let keys = self.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
+ let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
- let commitment_stats = self.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, false, logger);
+ let commitment_stats = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, false, logger);
let commitment_txid = {
let trusted_tx = commitment_stats.tx.trust();
let bitcoin_tx = trusted_tx.built_transaction();
log_trace!(logger, "Checking commitment tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}",
log_bytes!(msg.signature.serialize_compact()[..]),
- log_bytes!(self.counterparty_funding_pubkey().serialize()), encode::serialize_hex(&bitcoin_tx.transaction),
+ log_bytes!(self.context.counterparty_funding_pubkey().serialize()), encode::serialize_hex(&bitcoin_tx.transaction),
log_bytes!(sighash[..]), encode::serialize_hex(&funding_script), log_bytes!(self.context.channel_id()));
- if let Err(_) = self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.counterparty_funding_pubkey()) {
+ if let Err(_) = self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.context.counterparty_funding_pubkey()) {
return Err(ChannelError::Close("Invalid commitment tx signature from peer".to_owned()));
}
bitcoin_tx.txid
msg.signature,
msg.htlc_signatures.clone(),
&self.context.get_holder_pubkeys().funding_pubkey,
- self.counterparty_funding_pubkey()
+ self.context.counterparty_funding_pubkey()
);
self.context.holder_signer.validate_holder_commitment(&holder_commitment_tx, commitment_stats.preimages)
// Before proposing a feerate update, check that we can actually afford the new fee.
let inbound_stats = self.get_inbound_pending_htlc_stats(Some(feerate_per_kw));
let outbound_stats = self.get_outbound_pending_htlc_stats(Some(feerate_per_kw));
- let keys = self.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
- let commitment_stats = self.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, true, logger);
- let buffer_fee_msat = Channel::<Signer>::commit_tx_fee_sat(feerate_per_kw, commitment_stats.num_nondust_htlcs + outbound_stats.on_holder_tx_holding_cell_htlcs_count as usize + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize, self.context.opt_anchors()) * 1000;
+ 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 buffer_fee_msat = commit_tx_fee_sat(feerate_per_kw, commitment_stats.num_nondust_htlcs + outbound_stats.on_holder_tx_holding_cell_htlcs_count as usize + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize, self.context.opt_anchors()) * 1000;
let holder_balance_msat = commitment_stats.local_balance_msat - outbound_stats.holding_cell_msat;
if holder_balance_msat < buffer_fee_msat + self.context.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 {
//TODO: auto-close after a number of failures?
tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
let funding_key = self.context.get_holder_pubkeys().funding_pubkey.serialize();
- let counterparty_funding_key = self.counterparty_funding_pubkey().serialize();
+ let counterparty_funding_key = self.context.counterparty_funding_pubkey().serialize();
let mut holder_sig = sig.serialize_der().to_vec();
holder_sig.push(EcdsaSighashType::All as u8);
let mut cp_sig = counterparty_sig.serialize_der().to_vec();
tx.input[0].witness.push(holder_sig);
}
- tx.input[0].witness.push(self.get_funding_redeemscript().into_bytes());
+ tx.input[0].witness.push(self.context.get_funding_redeemscript().into_bytes());
tx
}
return Ok((None, None));
}
- let funding_redeemscript = self.get_funding_redeemscript();
+ let funding_redeemscript = self.context.get_funding_redeemscript();
let (mut closing_tx, used_total_fee) = self.build_closing_transaction(msg.fee_satoshis, false);
if used_total_fee != msg.fee_satoshis {
return Err(ChannelError::Close(format!("Remote sent us a closing_signed with a fee other than the value they can claim. Fee in message: {}. Actual closing tx fee: {}", msg.fee_satoshis, used_total_fee)));
// limits, so check for that case by re-checking the signature here.
closing_tx = self.build_closing_transaction(msg.fee_satoshis, true).0;
let sighash = closing_tx.trust().get_sighash_all(&funding_redeemscript, self.context.channel_value_satoshis);
- secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, self.counterparty_funding_pubkey()), "Invalid closing tx signature from peer".to_owned());
+ secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, self.context.counterparty_funding_pubkey()), "Invalid closing tx signature from peer".to_owned());
},
};
if self.context.funding_tx_confirmation_height == 0 {
if tx.txid() == funding_txo.txid {
let txo_idx = funding_txo.index as usize;
- if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.get_funding_redeemscript().to_v0_p2wsh() ||
+ if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.context.get_funding_redeemscript().to_v0_p2wsh() ||
tx.output[txo_idx].value != self.context.channel_value_satoshis {
if self.context.is_outbound() {
// If we generated the funding transaction and it doesn't match what it
/// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created)
fn get_outbound_funding_created_signature<L: Deref>(&mut self, logger: &L) -> Result<Signature, ChannelError> where L::Target: Logger {
- let counterparty_keys = self.build_remote_transaction_keys();
- let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
+ 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;
Ok(self.context.holder_signer.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.context.secp_ctx)
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?.0)
}
short_channel_id: self.context.get_short_channel_id().unwrap(),
node_id_1: if were_node_one { node_id } else { counterparty_node_id },
node_id_2: if were_node_one { counterparty_node_id } else { node_id },
- bitcoin_key_1: NodeId::from_pubkey(if were_node_one { &self.context.get_holder_pubkeys().funding_pubkey } else { self.counterparty_funding_pubkey() }),
- bitcoin_key_2: NodeId::from_pubkey(if were_node_one { self.counterparty_funding_pubkey() } else { &self.context.get_holder_pubkeys().funding_pubkey }),
+ bitcoin_key_1: NodeId::from_pubkey(if were_node_one { &self.context.get_holder_pubkeys().funding_pubkey } else { self.context.counterparty_funding_pubkey() }),
+ bitcoin_key_2: NodeId::from_pubkey(if were_node_one { self.context.counterparty_funding_pubkey() } else { &self.context.get_holder_pubkeys().funding_pubkey }),
excess_data: Vec::new(),
};
"Bad announcement_signatures. Failed to verify node_signature. UnsignedChannelAnnouncement used for verification is {:?}. their_node_key is {:?}",
&announcement, self.context.get_counterparty_node_id())));
}
- if self.context.secp_ctx.verify_ecdsa(&msghash, &msg.bitcoin_signature, self.counterparty_funding_pubkey()).is_err() {
+ if self.context.secp_ctx.verify_ecdsa(&msghash, &msg.bitcoin_signature, self.context.counterparty_funding_pubkey()).is_err() {
return Err(ChannelError::Close(format!(
"Bad announcement_signatures. Failed to verify bitcoin_signature. UnsignedChannelAnnouncement used for verification is {:?}. their_bitcoin_key is ({:?})",
- &announcement, self.counterparty_funding_pubkey())));
+ &announcement, self.context.counterparty_funding_pubkey())));
}
self.context.announcement_sigs = Some((msg.node_signature, msg.bitcoin_signature));
}
fn build_commitment_no_state_update<L: Deref>(&self, logger: &L) -> (Txid, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>) where L::Target: Logger {
- let counterparty_keys = self.build_remote_transaction_keys();
- let commitment_stats = self.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, true, logger);
+ let counterparty_keys = self.context.build_remote_transaction_keys();
+ let commitment_stats = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, true, logger);
let counterparty_commitment_txid = commitment_stats.tx.trust().txid();
#[cfg(any(test, fuzzing))]
#[cfg(any(test, fuzzing))]
self.build_commitment_no_state_update(logger);
- let counterparty_keys = self.build_remote_transaction_keys();
- let commitment_stats = self.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, true, logger);
+ let counterparty_keys = self.context.build_remote_transaction_keys();
+ let commitment_stats = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, true, logger);
let counterparty_commitment_txid = commitment_stats.tx.trust().txid();
let (signature, htlc_signatures);
log_trace!(logger, "Signed remote commitment tx {} (txid {}) with redeemscript {} -> {} in channel {}",
encode::serialize_hex(&commitment_stats.tx.trust().built_transaction().transaction),
- &counterparty_commitment_txid, encode::serialize_hex(&self.get_funding_redeemscript()),
+ &counterparty_commitment_txid, encode::serialize_hex(&self.context.get_funding_redeemscript()),
log_bytes!(signature.serialize_compact()[..]), log_bytes!(self.context.channel_id()));
for (ref htlc_sig, ref htlc) in htlc_signatures.iter().zip(htlcs) {
node_a_chan.accept_channel(&accept_channel_msg, &config.channel_handshake_limits, &channelmanager::provided_init_features(&config)).unwrap();
// Node A --> Node B: funding created
- let output_script = node_a_chan.get_funding_redeemscript();
+ let output_script = node_a_chan.context.get_funding_redeemscript();
let tx = Transaction { version: 1, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: vec![TxOut {
value: 10000000, script_pubkey: output_script.clone(),
}]};
$( { $htlc_idx: expr, $counterparty_htlc_sig_hex: expr, $htlc_sig_hex: expr, $htlc_tx_hex: expr } ), *
} ) => { {
let (commitment_tx, htlcs): (_, Vec<HTLCOutputInCommitment>) = {
- let mut commitment_stats = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, &logger);
+ let mut commitment_stats = chan.context.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, &logger);
let htlcs = commitment_stats.htlcs_included.drain(..)
.filter_map(|(htlc, _)| if htlc.transaction_output_index.is_some() { Some(htlc) } else { None })
};
let trusted_tx = commitment_tx.trust();
let unsigned_tx = trusted_tx.built_transaction();
- let redeemscript = chan.get_funding_redeemscript();
+ let redeemscript = chan.context.get_funding_redeemscript();
let counterparty_signature = Signature::from_der(&hex::decode($counterparty_sig_hex).unwrap()[..]).unwrap();
let sighash = unsigned_tx.get_sighash_all(&redeemscript, chan.context.channel_value_satoshis);
log_trace!(logger, "unsigned_tx = {}", hex::encode(serialize(&unsigned_tx.transaction)));
- assert!(secp_ctx.verify_ecdsa(&sighash, &counterparty_signature, chan.counterparty_funding_pubkey()).is_ok(), "verify counterparty commitment sig");
+ assert!(secp_ctx.verify_ecdsa(&sighash, &counterparty_signature, chan.context.counterparty_funding_pubkey()).is_ok(), "verify counterparty commitment sig");
let mut per_htlc: Vec<(HTLCOutputInCommitment, Option<Signature>)> = Vec::new();
per_htlc.clear(); // Don't warn about excess mut for no-HTLC calls
counterparty_signature,
counterparty_htlc_sigs,
&chan.context.holder_signer.pubkeys().funding_pubkey,
- chan.counterparty_funding_pubkey()
+ chan.context.counterparty_funding_pubkey()
);
let (holder_sig, htlc_sigs) = signer.sign_holder_commitment_and_htlcs(&holder_commitment_tx, &secp_ctx).unwrap();
assert_eq!(Signature::from_der(&hex::decode($sig_hex).unwrap()[..]).unwrap(), holder_sig, "holder_sig");
- let funding_redeemscript = chan.get_funding_redeemscript();
+ let funding_redeemscript = chan.context.get_funding_redeemscript();
let tx = holder_commitment_tx.add_holder_sig(&funding_redeemscript, holder_sig);
assert_eq!(serialize(&tx)[..], hex::decode($tx_hex).unwrap()[..], "tx");