// You may not use this file except in accordance with one or both of these
// licenses.
+use bitcoin::amount::Amount;
use bitcoin::blockdata::constants::ChainHash;
use bitcoin::blockdata::script::{Script, ScriptBuf, Builder};
use bitcoin::blockdata::transaction::Transaction;
use crate::ln::msgs;
use crate::ln::msgs::DecodeError;
use crate::ln::script::{self, ShutdownScript};
-use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, SentHTLCId, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT, ChannelShutdownState};
+use crate::ln::channel_state::{ChannelShutdownState, CounterpartyForwardingInfo, InboundHTLCDetails, InboundHTLCStateDetails, OutboundHTLCDetails, OutboundHTLCStateDetails};
+use crate::ln::channelmanager::{self, PendingHTLCStatus, HTLCSource, SentHTLCId, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction};
use crate::ln::chan_utils;
use crate::ln::onion_utils::HTLCFailReason;
LocalRemoved(InboundHTLCRemovalReason),
}
-/// Exposes the state of pending inbound HTLCs.
-///
-/// At a high level, an HTLC being forwarded from one Lightning node to another Lightning node goes
-/// through the following states in the state machine:
-/// - Announced for addition by the originating node through the update_add_htlc message.
-/// - Added to the commitment transaction of the receiving node and originating node in turn
-/// through the exchange of commitment_signed and revoke_and_ack messages.
-/// - Announced for resolution (fulfillment or failure) by the receiving node through either one of
-/// the update_fulfill_htlc, update_fail_htlc, and update_fail_malformed_htlc messages.
-/// - Removed from the commitment transaction of the originating node and receiving node in turn
-/// through the exchange of commitment_signed and revoke_and_ack messages.
-///
-/// This can be used to inspect what next message an HTLC is waiting for to advance its state.
-#[derive(Clone, Debug, PartialEq)]
-pub enum InboundHTLCStateDetails {
- /// We have added this HTLC in our commitment transaction by receiving commitment_signed and
- /// returning revoke_and_ack. We are awaiting the appropriate revoke_and_ack's from the remote
- /// before this HTLC is included on the remote commitment transaction.
- AwaitingRemoteRevokeToAdd,
- /// This HTLC has been included in the commitment_signed and revoke_and_ack messages on both sides
- /// and is included in both commitment transactions.
- ///
- /// This HTLC is now safe to either forward or be claimed as a payment by us. The HTLC will
- /// remain in this state until the forwarded upstream HTLC has been resolved and we resolve this
- /// HTLC correspondingly, or until we claim it as a payment. If it is part of a multipart
- /// payment, it will only be claimed together with other required parts.
- Committed,
- /// We have received the preimage for this HTLC and it is being removed by fulfilling it with
- /// update_fulfill_htlc. This HTLC is still on both commitment transactions, but we are awaiting
- /// the appropriate revoke_and_ack's from the remote before this HTLC is removed from the remote
- /// commitment transaction after update_fulfill_htlc.
- AwaitingRemoteRevokeToRemoveFulfill,
- /// The HTLC is being removed by failing it with update_fail_htlc or update_fail_malformed_htlc.
- /// This HTLC is still on both commitment transactions, but we are awaiting the appropriate
- /// revoke_and_ack's from the remote before this HTLC is removed from the remote commitment
- /// transaction.
- AwaitingRemoteRevokeToRemoveFail,
-}
-
impl From<&InboundHTLCState> for Option<InboundHTLCStateDetails> {
fn from(state: &InboundHTLCState) -> Option<InboundHTLCStateDetails> {
match state {
}
}
-impl_writeable_tlv_based_enum_upgradable!(InboundHTLCStateDetails,
- (0, AwaitingRemoteRevokeToAdd) => {},
- (2, Committed) => {},
- (4, AwaitingRemoteRevokeToRemoveFulfill) => {},
- (6, AwaitingRemoteRevokeToRemoveFail) => {};
-);
-
struct InboundHTLCOutput {
htlc_id: u64,
amount_msat: u64,
state: InboundHTLCState,
}
-/// Exposes details around pending inbound HTLCs.
-#[derive(Clone, Debug, PartialEq)]
-pub struct InboundHTLCDetails {
- /// The HTLC ID.
- /// The IDs are incremented by 1 starting from 0 for each offered HTLC.
- /// They are unique per channel and inbound/outbound direction, unless an HTLC was only announced
- /// and not part of any commitment transaction.
- pub htlc_id: u64,
- /// The amount in msat.
- pub amount_msat: u64,
- /// The block height at which this HTLC expires.
- pub cltv_expiry: u32,
- /// The payment hash.
- pub payment_hash: PaymentHash,
- /// The state of the HTLC in the state machine.
- ///
- /// Determines on which commitment transactions the HTLC is included and what message the HTLC is
- /// waiting for to advance to the next state.
- ///
- /// See [`InboundHTLCStateDetails`] for information on the specific states.
- ///
- /// LDK will always fill this field in, but when downgrading to prior versions of LDK, new
- /// states may result in `None` here.
- pub state: Option<InboundHTLCStateDetails>,
- /// Whether the HTLC has an output below the local dust limit. If so, the output will be trimmed
- /// from the local commitment transaction and added to the commitment transaction fee.
- /// For non-anchor channels, this takes into account the cost of the second-stage HTLC
- /// transactions as well.
- ///
- /// When the local commitment transaction is broadcasted as part of a unilateral closure,
- /// the value of this HTLC will therefore not be claimable but instead burned as a transaction
- /// fee.
- ///
- /// Note that dust limits are specific to each party. An HTLC can be dust for the local
- /// commitment transaction but not for the counterparty's commitment transaction and vice versa.
- pub is_dust: bool,
-}
-
-impl_writeable_tlv_based!(InboundHTLCDetails, {
- (0, htlc_id, required),
- (2, amount_msat, required),
- (4, cltv_expiry, required),
- (6, payment_hash, required),
- (7, state, upgradable_option),
- (8, is_dust, required),
-});
-
#[cfg_attr(test, derive(Clone, Debug, PartialEq))]
enum OutboundHTLCState {
/// Added by us and included in a commitment_signed (if we were AwaitingRemoteRevoke when we
AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome),
}
-/// Exposes the state of pending outbound HTLCs.
-///
-/// At a high level, an HTLC being forwarded from one Lightning node to another Lightning node goes
-/// through the following states in the state machine:
-/// - Announced for addition by the originating node through the update_add_htlc message.
-/// - Added to the commitment transaction of the receiving node and originating node in turn
-/// through the exchange of commitment_signed and revoke_and_ack messages.
-/// - Announced for resolution (fulfillment or failure) by the receiving node through either one of
-/// the update_fulfill_htlc, update_fail_htlc, and update_fail_malformed_htlc messages.
-/// - Removed from the commitment transaction of the originating node and receiving node in turn
-/// through the exchange of commitment_signed and revoke_and_ack messages.
-///
-/// This can be used to inspect what next message an HTLC is waiting for to advance its state.
-#[derive(Clone, Debug, PartialEq)]
-pub enum OutboundHTLCStateDetails {
- /// We are awaiting the appropriate revoke_and_ack's from the remote before the HTLC is added
- /// on the remote's commitment transaction after update_add_htlc.
- AwaitingRemoteRevokeToAdd,
- /// The HTLC has been added to the remote's commitment transaction by sending commitment_signed
- /// and receiving revoke_and_ack in return.
- ///
- /// The HTLC will remain in this state until the remote node resolves the HTLC, or until we
- /// unilaterally close the channel due to a timeout with an uncooperative remote node.
- Committed,
- /// The HTLC has been fulfilled successfully by the remote with a preimage in update_fulfill_htlc,
- /// and we removed the HTLC from our commitment transaction by receiving commitment_signed and
- /// returning revoke_and_ack. We are awaiting the appropriate revoke_and_ack's from the remote
- /// for the removal from its commitment transaction.
- AwaitingRemoteRevokeToRemoveSuccess,
- /// The HTLC has been failed by the remote with update_fail_htlc or update_fail_malformed_htlc,
- /// and we removed the HTLC from our commitment transaction by receiving commitment_signed and
- /// returning revoke_and_ack. We are awaiting the appropriate revoke_and_ack's from the remote
- /// for the removal from its commitment transaction.
- AwaitingRemoteRevokeToRemoveFailure,
-}
-
impl From<&OutboundHTLCState> for OutboundHTLCStateDetails {
fn from(state: &OutboundHTLCState) -> OutboundHTLCStateDetails {
match state {
}
}
-impl_writeable_tlv_based_enum_upgradable!(OutboundHTLCStateDetails,
- (0, AwaitingRemoteRevokeToAdd) => {},
- (2, Committed) => {},
- (4, AwaitingRemoteRevokeToRemoveSuccess) => {},
- (6, AwaitingRemoteRevokeToRemoveFailure) => {};
-);
-
#[derive(Clone)]
#[cfg_attr(test, derive(Debug, PartialEq))]
enum OutboundHTLCOutcome {
skimmed_fee_msat: Option<u64>,
}
-/// Exposes details around pending outbound HTLCs.
-#[derive(Clone, Debug, PartialEq)]
-pub struct OutboundHTLCDetails {
- /// The HTLC ID.
- /// The IDs are incremented by 1 starting from 0 for each offered HTLC.
- /// They are unique per channel and inbound/outbound direction, unless an HTLC was only announced
- /// and not part of any commitment transaction.
- ///
- /// Not present when we are awaiting a remote revocation and the HTLC is not added yet.
- pub htlc_id: Option<u64>,
- /// The amount in msat.
- pub amount_msat: u64,
- /// The block height at which this HTLC expires.
- pub cltv_expiry: u32,
- /// The payment hash.
- pub payment_hash: PaymentHash,
- /// The state of the HTLC in the state machine.
- ///
- /// Determines on which commitment transactions the HTLC is included and what message the HTLC is
- /// waiting for to advance to the next state.
- ///
- /// See [`OutboundHTLCStateDetails`] for information on the specific states.
- ///
- /// LDK will always fill this field in, but when downgrading to prior versions of LDK, new
- /// states may result in `None` here.
- pub state: Option<OutboundHTLCStateDetails>,
- /// The extra fee being skimmed off the top of this HTLC.
- pub skimmed_fee_msat: Option<u64>,
- /// Whether the HTLC has an output below the local dust limit. If so, the output will be trimmed
- /// from the local commitment transaction and added to the commitment transaction fee.
- /// For non-anchor channels, this takes into account the cost of the second-stage HTLC
- /// transactions as well.
- ///
- /// When the local commitment transaction is broadcasted as part of a unilateral closure,
- /// the value of this HTLC will therefore not be claimable but instead burned as a transaction
- /// fee.
- ///
- /// Note that dust limits are specific to each party. An HTLC can be dust for the local
- /// commitment transaction but not for the counterparty's commitment transaction and vice versa.
- pub is_dust: bool,
-}
-
-impl_writeable_tlv_based!(OutboundHTLCDetails, {
- (0, htlc_id, required),
- (2, amount_msat, required),
- (4, cltv_expiry, required),
- (6, payment_hash, required),
- (7, state, upgradable_option),
- (8, skimmed_fee_msat, required),
- (10, is_dust, required),
-});
-
/// See AwaitingRemoteRevoke ChannelState for more info
#[cfg_attr(test, derive(Clone, Debug, PartialEq))]
enum HTLCUpdateAwaitingACK {
pub(crate) channel_funding_txo: Option<OutPoint>,
}
+/// Tracks the transaction number, along with current and next commitment points.
+/// This consolidates the logic to advance our commitment number and request new
+/// commitment points from our signer.
+#[derive(Debug, Copy, Clone)]
+enum HolderCommitmentPoint {
+ // TODO: add a variant for before our first commitment point is retrieved
+ /// We've advanced our commitment number and are waiting on the next commitment point.
+ /// Until the `get_per_commitment_point` signer method becomes async, this variant
+ /// will not be used.
+ PendingNext { transaction_number: u64, current: PublicKey },
+ /// Our current commitment point is ready, we've cached our next point,
+ /// and we are not pending a new one.
+ Available { transaction_number: u64, current: PublicKey, next: PublicKey },
+}
+
+impl HolderCommitmentPoint {
+ pub fn new<SP: Deref>(signer: &ChannelSignerType<SP>, secp_ctx: &Secp256k1<secp256k1::All>) -> Self
+ where SP::Target: SignerProvider
+ {
+ HolderCommitmentPoint::Available {
+ transaction_number: INITIAL_COMMITMENT_NUMBER,
+ current: signer.as_ref().get_per_commitment_point(INITIAL_COMMITMENT_NUMBER, secp_ctx),
+ next: signer.as_ref().get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - 1, secp_ctx),
+ }
+ }
+
+ pub fn is_available(&self) -> bool {
+ if let HolderCommitmentPoint::Available { .. } = self { true } else { false }
+ }
+
+ pub fn transaction_number(&self) -> u64 {
+ match self {
+ HolderCommitmentPoint::PendingNext { transaction_number, .. } => *transaction_number,
+ HolderCommitmentPoint::Available { transaction_number, .. } => *transaction_number,
+ }
+ }
+
+ pub fn current_point(&self) -> PublicKey {
+ match self {
+ HolderCommitmentPoint::PendingNext { current, .. } => *current,
+ HolderCommitmentPoint::Available { current, .. } => *current,
+ }
+ }
+
+ pub fn next_point(&self) -> Option<PublicKey> {
+ match self {
+ HolderCommitmentPoint::PendingNext { .. } => None,
+ HolderCommitmentPoint::Available { next, .. } => Some(*next),
+ }
+ }
+
+ pub fn advance<SP: Deref, L: Deref>(&mut self, signer: &ChannelSignerType<SP>, secp_ctx: &Secp256k1<secp256k1::All>, logger: &L)
+ where SP::Target: SignerProvider, L::Target: Logger
+ {
+ if let HolderCommitmentPoint::Available { transaction_number, next, .. } = self {
+ *self = HolderCommitmentPoint::PendingNext {
+ transaction_number: *transaction_number - 1,
+ current: *next,
+ };
+ }
+
+ if let HolderCommitmentPoint::PendingNext { transaction_number, current } = self {
+ let next = signer.as_ref().get_per_commitment_point(*transaction_number - 1, secp_ctx);
+ log_trace!(logger, "Retrieved next per-commitment point {}", *transaction_number - 1);
+ *self = HolderCommitmentPoint::Available { transaction_number: *transaction_number, current: *current, next };
+ }
+ }
+}
+
/// If the majority of the channels funds are to the fundee and the initiator holds only just
/// enough funds to cover their reserve value, channels are at risk of getting "stuck". Because the
/// initiator controls the feerate, if they then go to increase the channel fee, they may have no
// generation start at 0 and count up...this simplifies some parts of implementation at the
// cost of others, but should really just be changed.
- cur_holder_commitment_transaction_number: u64,
+ holder_commitment_point: HolderCommitmentPoint,
cur_counterparty_commitment_transaction_number: u64,
value_to_self_msat: u64, // Excluding all pending_htlcs, fees, and anchor outputs
pending_inbound_htlcs: Vec<InboundHTLCOutput>,
/// Either the height at which this channel was created or the height at which it was last
/// serialized if it was serialized by versions prior to 0.0.103.
/// We use this to close if funding is never broadcasted.
- channel_creation_height: u32,
+ pub(super) channel_creation_height: u32,
counterparty_dust_limit_satoshis: u64,
let value_to_self_msat = our_funding_satoshis * 1000 + msg_push_msat;
+ let holder_signer = ChannelSignerType::Ecdsa(holder_signer);
+ let holder_commitment_point = HolderCommitmentPoint::new(&holder_signer, &secp_ctx);
+
// TODO(dual_funding): Checks for `funding_feerate_sat_per_1000_weight`?
let channel_context = ChannelContext {
latest_monitor_update_id: 0,
- holder_signer: ChannelSignerType::Ecdsa(holder_signer),
+ holder_signer,
shutdown_scriptpubkey,
destination_script,
- cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
+ holder_commitment_point,
cur_counterparty_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
value_to_self_msat,
let temporary_channel_id = temporary_channel_id.unwrap_or_else(|| ChannelId::temporary_from_entropy_source(entropy_source));
+ let holder_signer = ChannelSignerType::Ecdsa(holder_signer);
+ let holder_commitment_point = HolderCommitmentPoint::new(&holder_signer, &secp_ctx);
+
Ok(Self {
user_id,
latest_monitor_update_id: 0,
- holder_signer: ChannelSignerType::Ecdsa(holder_signer),
+ holder_signer,
shutdown_scriptpubkey,
destination_script,
- cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
+ holder_commitment_point,
cur_counterparty_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
value_to_self_msat,
/// our counterparty!)
/// The result is a transaction which we can revoke broadcastership of (ie a "local" transaction)
/// TODO Some magic rust shit to compile-time check this?
- fn build_holder_transaction_keys(&self, commitment_number: u64) -> TxCreationKeys {
- let per_commitment_point = self.holder_signer.as_ref().get_per_commitment_point(commitment_number, &self.secp_ctx);
+ fn build_holder_transaction_keys(&self) -> TxCreationKeys {
+ let per_commitment_point = self.holder_commitment_point.current_point();
let delayed_payment_base = &self.get_holder_pubkeys().delayed_payment_basepoint;
let htlc_basepoint = &self.get_holder_pubkeys().htlc_basepoint;
let counterparty_pubkeys = self.get_counterparty_pubkeys();
let funding_script = self.context.get_funding_redeemscript();
- let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
+ let keys = self.context.build_holder_transaction_keys();
- let commitment_stats = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, false, logger);
+ let commitment_stats = self.context.build_commitment_transaction(self.context.holder_commitment_point.transaction_number(), &keys, true, false, logger);
let commitment_txid = {
let trusted_tx = commitment_stats.tx.trust();
let bitcoin_tx = trusted_tx.built_transaction();
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &self.context.channel_type, &keys);
let htlc_sighashtype = if self.context.channel_type.supports_anchors_zero_fee_htlc_tx() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
- let htlc_sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]);
+ let htlc_sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).p2wsh_signature_hash(0, &htlc_redeemscript, htlc.to_bitcoin_amount(), htlc_sighashtype).unwrap()[..]);
log_trace!(logger, "Checking HTLC tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}.",
log_bytes!(msg.htlc_signatures[idx].serialize_compact()[..]), log_bytes!(keys.countersignatory_htlc_key.to_public_key().serialize()),
encode::serialize_hex(&htlc_tx), log_bytes!(htlc_sighash[..]), encode::serialize_hex(&htlc_redeemscript), &self.context.channel_id());
channel_id: Some(self.context.channel_id()),
};
- self.context.cur_holder_commitment_transaction_number -= 1;
+ self.context.holder_commitment_point.advance(&self.context.holder_signer, &self.context.secp_ctx, logger);
self.context.expecting_peer_commitment_signed = false;
// Note that if we need_commitment & !AwaitingRemoteRevoke we'll call
// build_commitment_no_status_check() next which will reset this to RAAFirst.
// Before proposing a feerate update, check that we can actually afford the new fee.
let dust_exposure_limiting_feerate = self.context.get_dust_exposure_limiting_feerate(&fee_estimator);
let htlc_stats = self.context.get_pending_htlc_stats(Some(feerate_per_kw), dust_exposure_limiting_feerate);
- let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
- let commitment_stats = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, true, logger);
+ let keys = self.context.build_holder_transaction_keys();
+ let commitment_stats = self.context.build_commitment_transaction(self.context.holder_commitment_point.transaction_number(), &keys, true, true, logger);
let buffer_fee_msat = commit_tx_fee_sat(feerate_per_kw, commitment_stats.num_nondust_htlcs + htlc_stats.on_holder_tx_outbound_holding_cell_htlcs_count as usize + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize, self.context.get_channel_type()) * 1000;
let holder_balance_msat = commitment_stats.local_balance_msat - htlc_stats.outbound_holding_cell_msat;
if holder_balance_msat < buffer_fee_msat + self.context.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 {
assert!(!self.context.is_outbound() || self.context.minimum_depth == Some(0),
"Funding transaction broadcast by the local client before it should have - LDK didn't do it!");
self.context.monitor_pending_channel_ready = false;
- let next_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
- Some(msgs::ChannelReady {
- channel_id: self.context.channel_id(),
- next_per_commitment_point,
- short_channel_id_alias: Some(self.context.outbound_scid_alias),
- })
+ Some(self.get_channel_ready())
} else { None };
let announcement_sigs = self.get_announcement_sigs(node_signer, chain_hash, user_config, best_block_height, logger);
self.context.get_funding_signed_msg(logger).1
} else { None };
let channel_ready = if funding_signed.is_some() {
- self.check_get_channel_ready(0)
+ self.check_get_channel_ready(0, logger)
} else { None };
log_trace!(logger, "Signer unblocked with {} commitment_update, {} funding_signed and {} channel_ready",
}
fn get_last_revoke_and_ack(&self) -> msgs::RevokeAndACK {
- let next_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
- let per_commitment_secret = self.context.holder_signer.as_ref().release_commitment_secret(self.context.cur_holder_commitment_transaction_number + 2);
+ debug_assert!(self.context.holder_commitment_point.transaction_number() <= INITIAL_COMMITMENT_NUMBER + 2);
+ // TODO: handle non-available case when get_per_commitment_point becomes async
+ debug_assert!(self.context.holder_commitment_point.is_available());
+ let next_per_commitment_point = self.context.holder_commitment_point.current_point();
+ let per_commitment_secret = self.context.holder_signer.as_ref().release_commitment_secret(self.context.holder_commitment_point.transaction_number() + 2);
msgs::RevokeAndACK {
channel_id: self.context.channel_id,
per_commitment_secret,
return Err(ChannelError::Close("Peer sent an invalid channel_reestablish to force close in a non-standard way".to_owned()));
}
- let our_commitment_transaction = INITIAL_COMMITMENT_NUMBER - self.context.cur_holder_commitment_transaction_number - 1;
+ let our_commitment_transaction = INITIAL_COMMITMENT_NUMBER - self.context.holder_commitment_point.transaction_number() - 1;
if msg.next_remote_commitment_number > 0 {
let expected_point = self.context.holder_signer.as_ref().get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - msg.next_remote_commitment_number + 1, &self.context.secp_ctx);
let given_secret = SecretKey::from_slice(&msg.your_last_per_commitment_secret)
}
// We have OurChannelReady set!
- let next_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
return Ok(ReestablishResponses {
- channel_ready: Some(msgs::ChannelReady {
- channel_id: self.context.channel_id(),
- next_per_commitment_point,
- short_channel_id_alias: Some(self.context.outbound_scid_alias),
- }),
+ channel_ready: Some(self.get_channel_ready()),
raa: None, commitment_update: None,
order: RAACommitmentOrder::CommitmentFirst,
shutdown_msg, announcement_sigs,
}
let next_counterparty_commitment_number = INITIAL_COMMITMENT_NUMBER - self.context.cur_counterparty_commitment_transaction_number + if is_awaiting_remote_revoke { 1 } else { 0 };
- let channel_ready = if msg.next_local_commitment_number == 1 && INITIAL_COMMITMENT_NUMBER - self.context.cur_holder_commitment_transaction_number == 1 {
+ let channel_ready = if msg.next_local_commitment_number == 1 && INITIAL_COMMITMENT_NUMBER - self.context.holder_commitment_point.transaction_number() == 1 {
// We should never have to worry about MonitorUpdateInProgress resending ChannelReady
- let next_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
- Some(msgs::ChannelReady {
- channel_id: self.context.channel_id(),
- next_per_commitment_point,
- short_channel_id_alias: Some(self.context.outbound_scid_alias),
- })
+ Some(self.get_channel_ready())
} else { None };
if msg.next_local_commitment_number == next_counterparty_commitment_number {
};
for outp in closing_tx.trust().built_transaction().output.iter() {
- if !outp.script_pubkey.is_witness_program() && outp.value < MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS {
+ if !outp.script_pubkey.is_witness_program() && outp.value < Amount::from_sat(MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS) {
return Err(ChannelError::Close("Remote sent us a closing_signed with a dust output. Always use segwit closing scripts!".to_owned()));
}
}
}
pub fn get_cur_holder_commitment_transaction_number(&self) -> u64 {
- self.context.cur_holder_commitment_transaction_number + 1
+ self.context.holder_commitment_point.transaction_number() + 1
}
pub fn get_cur_counterparty_commitment_transaction_number(&self) -> u64 {
debug_assert!(self.context.minimum_depth.unwrap_or(1) > 0);
return true;
}
- if self.context.cur_holder_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 &&
+ if self.context.holder_commitment_point.transaction_number() == INITIAL_COMMITMENT_NUMBER - 1 &&
self.context.cur_counterparty_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 {
// If we're a 0-conf channel, we'll move beyond AwaitingChannelReady immediately even while
// waiting for the initial monitor persistence. Thus, we check if our commitment
self.context.channel_update_status = status;
}
- fn check_get_channel_ready(&mut self, height: u32) -> Option<msgs::ChannelReady> {
+ fn check_get_channel_ready<L: Deref>(&mut self, height: u32, logger: &L) -> Option<msgs::ChannelReady>
+ where L::Target: Logger
+ {
// Called:
// * always when a new block/transactions are confirmed with the new height
// * when funding is signed with a height of 0
// If we're still pending the signature on a funding transaction, then we're not ready to send a
// channel_ready yet.
if self.context.signer_pending_funding {
+ // TODO: set signer_pending_channel_ready
+ log_debug!(logger, "Can't produce channel_ready: the signer is pending funding.");
return None;
}
false
};
- if need_commitment_update {
- if !self.context.channel_state.is_monitor_update_in_progress() {
- if !self.context.channel_state.is_peer_disconnected() {
- let next_per_commitment_point =
- self.context.holder_signer.as_ref().get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - 1, &self.context.secp_ctx);
- return Some(msgs::ChannelReady {
- channel_id: self.context.channel_id,
- next_per_commitment_point,
- short_channel_id_alias: Some(self.context.outbound_scid_alias),
- });
- }
- } else {
- self.context.monitor_pending_channel_ready = true;
- }
+ if !need_commitment_update {
+ log_debug!(logger, "Not producing channel_ready: we do not need a commitment update");
+ return None;
+ }
+
+ if self.context.channel_state.is_monitor_update_in_progress() {
+ log_debug!(logger, "Not producing channel_ready: a monitor update is in progress. Setting monitor_pending_channel_ready.");
+ self.context.monitor_pending_channel_ready = true;
+ return None;
+ }
+
+ if self.context.channel_state.is_peer_disconnected() {
+ log_debug!(logger, "Not producing channel_ready: the peer is disconnected.");
+ return None;
+ }
+
+ // TODO: when get_per_commiment_point becomes async, check if the point is
+ // available, if not, set signer_pending_channel_ready and return None
+
+ Some(self.get_channel_ready())
+ }
+
+ fn get_channel_ready(&self) -> msgs::ChannelReady {
+ debug_assert!(self.context.holder_commitment_point.is_available());
+ msgs::ChannelReady {
+ channel_id: self.context.channel_id(),
+ next_per_commitment_point: self.context.holder_commitment_point.current_point(),
+ short_channel_id_alias: Some(self.context.outbound_scid_alias),
}
- None
}
/// When a transaction is confirmed, we check whether it is or spends the funding transaction
if 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.context.get_funding_redeemscript().to_v0_p2wsh() ||
- tx.output[txo_idx].value != self.context.channel_value_satoshis {
+ if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.context.get_funding_redeemscript().to_p2wsh() ||
+ tx.output[txo_idx].value.to_sat() != self.context.channel_value_satoshis {
if self.context.is_outbound() {
// If we generated the funding transaction and it doesn't match what it
// should, the client is really broken and we should just panic and
return Err(ClosureReason::ProcessingError { err: err_reason.to_owned() });
} else {
if self.context.is_outbound() {
- if !tx.is_coin_base() {
+ if !tx.is_coinbase() {
for input in tx.input.iter() {
if input.witness.is_empty() {
// We generated a malleable funding transaction, implying we've
}
// If this is a coinbase transaction and not a 0-conf channel
// we should update our min_depth to 100 to handle coinbase maturity
- if tx.is_coin_base() &&
+ if tx.is_coinbase() &&
self.context.minimum_depth.unwrap_or(0) > 0 &&
self.context.minimum_depth.unwrap_or(0) < COINBASE_MATURITY {
self.context.minimum_depth = Some(COINBASE_MATURITY);
// If we allow 1-conf funding, we may need to check for channel_ready here and
// send it immediately instead of waiting for a best_block_updated call (which
// may have already happened for this block).
- if let Some(channel_ready) = self.check_get_channel_ready(height) {
+ if let Some(channel_ready) = self.check_get_channel_ready(height, logger) {
log_info!(logger, "Sending a channel_ready to our peer for channel {}", &self.context.channel_id);
let announcement_sigs = self.get_announcement_sigs(node_signer, chain_hash, user_config, height, logger);
msgs = (Some(channel_ready), announcement_sigs);
self.context.update_time_counter = cmp::max(self.context.update_time_counter, highest_header_time);
- if let Some(channel_ready) = self.check_get_channel_ready(height) {
+ if let Some(channel_ready) = self.check_get_channel_ready(height, logger) {
let announcement_sigs = if let Some((chain_hash, node_signer, user_config)) = chain_node_signer {
self.get_announcement_sigs(node_signer, chain_hash, user_config, height, logger)
} else { None };
// next_local_commitment_number is the next commitment_signed number we expect to
// receive (indicating if they need to resend one that we missed).
- next_local_commitment_number: INITIAL_COMMITMENT_NUMBER - self.context.cur_holder_commitment_transaction_number,
+ next_local_commitment_number: INITIAL_COMMITMENT_NUMBER - self.context.holder_commitment_point.transaction_number(),
// We have to set next_remote_commitment_number to the next revoke_and_ack we expect to
// receive, however we track it by the next commitment number for a remote transaction
// (which is one further, as they always revoke previous commitment transaction, not
}
if self.context.commitment_secrets.get_min_seen_secret() != (1 << 48) ||
self.context.cur_counterparty_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER ||
- self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
+ self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
}
// If the funding transaction is a coinbase transaction, we need to set the minimum depth to 100.
// We can skip this if it is a zero-conf channel.
- if funding_transaction.is_coin_base() &&
+ if funding_transaction.is_coinbase() &&
self.context.minimum_depth.unwrap_or(0) > 0 &&
self.context.minimum_depth.unwrap_or(0) < COINBASE_MATURITY {
self.context.minimum_depth = Some(COINBASE_MATURITY);
Ok(self.get_open_channel(chain_hash))
}
+ /// Returns true if we can resume the channel by sending the [`msgs::OpenChannel`] again.
+ pub fn is_resumable(&self) -> bool {
+ !self.context.have_received_message() &&
+ self.context.holder_commitment_point.transaction_number() == INITIAL_COMMITMENT_NUMBER
+ }
+
pub fn get_open_channel(&self, chain_hash: ChainHash) -> msgs::OpenChannel {
if !self.context.is_outbound() {
panic!("Tried to open a channel for an inbound channel?");
panic!("Cannot generate an open_channel after we've moved forward");
}
- if self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
+ if self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
panic!("Tried to send an open_channel for a channel that has already advanced");
}
- let first_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
+ debug_assert!(self.context.holder_commitment_point.is_available());
+ let first_per_commitment_point = self.context.holder_commitment_point.current_point();
let keys = self.context.get_holder_pubkeys();
msgs::OpenChannel {
}
if self.context.commitment_secrets.get_min_seen_secret() != (1 << 48) ||
self.context.cur_counterparty_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER ||
- self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
+ self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
}
log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
&self.context.channel_id(), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
- let holder_signer = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
- let initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &holder_signer, true, false, logger).tx;
+ let holder_signer = self.context.build_holder_transaction_keys();
+ let initial_commitment_tx = self.context.build_commitment_transaction(self.context.holder_commitment_point.transaction_number(), &holder_signer, true, false, logger).tx;
{
let trusted_tx = initial_commitment_tx.trust();
let initial_commitment_bitcoin_tx = trusted_tx.built_transaction();
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 funding_txo_script = funding_redeemscript.to_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);
} else {
self.context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
}
- self.context.cur_holder_commitment_transaction_number -= 1;
+ self.context.holder_commitment_point.advance(&self.context.holder_signer, &self.context.secp_ctx, logger);
self.context.cur_counterparty_commitment_transaction_number -= 1;
log_info!(logger, "Received funding_signed from peer for channel {}", &self.context.channel_id());
dual_funding_channel_context: None,
};
- let need_channel_ready = channel.check_get_channel_ready(0).is_some();
+ let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some();
channel.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
Ok((channel, channel_monitor))
}
) {
panic!("Tried to send accept_channel after channel had moved forward");
}
- if self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
+ if self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
panic!("Tried to send an accept_channel for a channel that has already advanced");
}
///
/// [`msgs::AcceptChannel`]: crate::ln::msgs::AcceptChannel
fn generate_accept_channel_message(&self) -> msgs::AcceptChannel {
- let first_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
+ debug_assert!(self.context.holder_commitment_point.is_available());
+ let first_per_commitment_point = self.context.holder_commitment_point.current_point();
let keys = self.context.get_holder_pubkeys();
msgs::AcceptChannel {
fn check_funding_created_signature<L: Deref>(&mut self, sig: &Signature, logger: &L) -> Result<CommitmentTransaction, ChannelError> where L::Target: Logger {
let funding_script = self.context.get_funding_redeemscript();
- let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
- let initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, false, logger).tx;
+ let keys = self.context.build_holder_transaction_keys();
+ let initial_commitment_tx = self.context.build_commitment_transaction(self.context.holder_commitment_point.transaction_number(), &keys, true, false, logger).tx;
let trusted_tx = initial_commitment_tx.trust();
let initial_commitment_bitcoin_tx = trusted_tx.built_transaction();
let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis);
}
if self.context.commitment_secrets.get_min_seen_secret() != (1 << 48) ||
self.context.cur_counterparty_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER ||
- self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
+ self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
}
self.context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
self.context.channel_id = ChannelId::v1_from_funding_outpoint(funding_txo);
self.context.cur_counterparty_commitment_transaction_number -= 1;
- self.context.cur_holder_commitment_transaction_number -= 1;
+ self.context.holder_commitment_point.advance(&self.context.holder_signer, &self.context.secp_ctx, logger);
let (counterparty_initial_commitment_tx, funding_signed) = self.context.get_funding_signed_msg(logger);
let funding_redeemscript = self.context.get_funding_redeemscript();
- let funding_txo_script = funding_redeemscript.to_v0_p2wsh();
+ let funding_txo_script = funding_redeemscript.to_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);
#[cfg(any(dual_funding, splicing))]
dual_funding_channel_context: None,
};
- let need_channel_ready = channel.check_get_channel_ready(0).is_some();
+ let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some();
channel.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
Ok((channel, funding_signed, channel_monitor))
debug_assert!(false, "Cannot generate an open_channel2 after we've moved forward");
}
- if self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
+ if self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
debug_assert!(false, "Tried to send an open_channel2 for a channel that has already advanced");
}
let first_per_commitment_point = self.context.holder_signer.as_ref()
- .get_per_commitment_point(self.context.cur_holder_commitment_transaction_number,
+ .get_per_commitment_point(self.context.holder_commitment_point.transaction_number(),
&self.context.secp_ctx);
let second_per_commitment_point = self.context.holder_signer.as_ref()
- .get_per_commitment_point(self.context.cur_holder_commitment_transaction_number - 1,
+ .get_per_commitment_point(self.context.holder_commitment_point.transaction_number() - 1,
&self.context.secp_ctx);
let keys = self.context.get_holder_pubkeys();
) {
debug_assert!(false, "Tried to send accept_channel2 after channel had moved forward");
}
- if self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
+ if self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
debug_assert!(false, "Tried to send an accept_channel2 for a channel that has already advanced");
}
/// [`msgs::AcceptChannelV2`]: crate::ln::msgs::AcceptChannelV2
fn generate_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
let first_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(
- self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
+ self.context.holder_commitment_point.transaction_number(), &self.context.secp_ctx);
let second_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(
- self.context.cur_holder_commitment_transaction_number - 1, &self.context.secp_ctx);
+ self.context.holder_commitment_point.transaction_number() - 1, &self.context.secp_ctx);
let keys = self.context.get_holder_pubkeys();
msgs::AcceptChannelV2 {
}
self.context.destination_script.write(writer)?;
- self.context.cur_holder_commitment_transaction_number.write(writer)?;
+ self.context.holder_commitment_point.transaction_number().write(writer)?;
self.context.cur_counterparty_commitment_transaction_number.write(writer)?;
self.context.value_to_self_msat.write(writer)?;
monitor_pending_update_adds = Some(&self.context.monitor_pending_update_adds);
}
+ // `current_point` will become optional when async signing is implemented.
+ let cur_holder_commitment_point = Some(self.context.holder_commitment_point.current_point());
+ let next_holder_commitment_point = self.context.holder_commitment_point.next_point();
+
write_tlv_fields!(writer, {
(0, self.context.announcement_sigs, option),
// minimum_depth and counterparty_selected_channel_reserve_satoshis used to have a
(39, pending_outbound_blinding_points, optional_vec),
(41, holding_cell_blinding_points, optional_vec),
(43, malformed_htlcs, optional_vec), // Added in 0.0.119
- // 45 and 47 are reserved for async signing
+ (45, cur_holder_commitment_point, option),
+ (47, next_holder_commitment_point, option),
(49, self.context.local_initiated_shutdown, option), // Added in 0.0.122
});
let mut malformed_htlcs: Option<Vec<(u64, u16, [u8; 32])>> = None;
let mut monitor_pending_update_adds: Option<Vec<msgs::UpdateAddHTLC>> = None;
+ let mut cur_holder_commitment_point_opt: Option<PublicKey> = None;
+ let mut next_holder_commitment_point_opt: Option<PublicKey> = None;
+
read_tlv_fields!(reader, {
(0, announcement_sigs, option),
(1, minimum_depth, option),
(39, pending_outbound_blinding_points_opt, optional_vec),
(41, holding_cell_blinding_points_opt, optional_vec),
(43, malformed_htlcs, optional_vec), // Added in 0.0.119
- // 45 and 47 are reserved for async signing
+ (45, cur_holder_commitment_point_opt, option),
+ (47, next_holder_commitment_point_opt, option),
(49, local_initiated_shutdown, option),
});
}
}
+ // If we're restoring this channel for the first time after an upgrade, then we require that the
+ // signer be available so that we can immediately populate the current commitment point. Channel
+ // restoration will fail if this is not possible.
+ let holder_commitment_point = match (cur_holder_commitment_point_opt, next_holder_commitment_point_opt) {
+ (Some(current), Some(next)) => HolderCommitmentPoint::Available {
+ transaction_number: cur_holder_commitment_transaction_number, current, next
+ },
+ (Some(current), _) => HolderCommitmentPoint::Available {
+ transaction_number: cur_holder_commitment_transaction_number, current,
+ next: holder_signer.get_per_commitment_point(cur_holder_commitment_transaction_number - 1, &secp_ctx),
+ },
+ (_, _) => HolderCommitmentPoint::Available {
+ transaction_number: cur_holder_commitment_transaction_number,
+ current: holder_signer.get_per_commitment_point(cur_holder_commitment_transaction_number, &secp_ctx),
+ next: holder_signer.get_per_commitment_point(cur_holder_commitment_transaction_number - 1, &secp_ctx),
+ },
+ };
+
Ok(Channel {
context: ChannelContext {
user_id,
shutdown_scriptpubkey,
destination_script,
- cur_holder_commitment_transaction_number,
+ holder_commitment_point,
cur_counterparty_commitment_transaction_number,
value_to_self_msat,
#[cfg(test)]
mod tests {
use std::cmp;
+ use bitcoin::amount::Amount;
use bitcoin::blockdata::constants::ChainHash;
use bitcoin::blockdata::script::{ScriptBuf, Builder};
- use bitcoin::blockdata::transaction::{Transaction, TxOut};
+ use bitcoin::blockdata::transaction::{Transaction, TxOut, Version};
use bitcoin::blockdata::opcodes;
- use bitcoin::network::constants::Network;
+ use bitcoin::network::Network;
use crate::ln::onion_utils::INVALID_ONION_BLINDING;
use crate::ln::types::{PaymentHash, PaymentPreimage};
use crate::ln::channel_keys::{RevocationKey, RevocationBasepoint};
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hashes::Hash;
use bitcoin::hashes::hex::FromHex;
- use bitcoin::hash_types::WPubkeyHash;
use bitcoin::blockdata::locktime::absolute::LockTime;
- use bitcoin::address::{WitnessProgram, WitnessVersion};
+ use bitcoin::{WitnessProgram, WitnessVersion, WPubkeyHash};
use crate::prelude::*;
#[test]
// Node A --> Node B: funding created
let output_script = node_a_chan.context.get_funding_redeemscript();
- let tx = Transaction { version: 1, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut {
- value: 10000000, script_pubkey: output_script.clone(),
+ let tx = Transaction { version: Version::ONE, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut {
+ value: Amount::from_sat(10000000), script_pubkey: output_script.clone(),
}]};
let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
let funding_created_msg = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, false, &&logger).map_err(|_| ()).unwrap();
// Node A --> Node B: funding created
let output_script = node_a_chan.context.get_funding_redeemscript();
- let tx = Transaction { version: 1, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut {
- value: 10000000, script_pubkey: output_script.clone(),
+ let tx = Transaction { version: Version::ONE, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut {
+ value: Amount::from_sat(10000000), script_pubkey: output_script.clone(),
}]};
let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
let funding_created_msg = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, false, &&logger).map_err(|_| ()).unwrap();
// Node A --> Node B: funding created
let output_script = node_a_chan.context.get_funding_redeemscript();
- let tx = Transaction { version: 1, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut {
- value: 10000000, script_pubkey: output_script.clone(),
+ let tx = Transaction { version: Version::ONE, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut {
+ value: Amount::from_sat(10000000), script_pubkey: output_script.clone(),
}]};
let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
let funding_created_msg = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, false, &&logger).map_err(|_| ()).unwrap();
&features, &outbound_chan.get_open_channel(ChainHash::using_genesis_block(network)), 7, &config, 0, &&logger, false
).unwrap();
outbound_chan.accept_channel(&inbound_chan.get_accept_channel_message(), &config.channel_handshake_limits, &features).unwrap();
- let tx = Transaction { version: 1, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut {
- value: 10000000, script_pubkey: outbound_chan.context.get_funding_redeemscript(),
+ let tx = Transaction { version: Version::ONE, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut {
+ value: Amount::from_sat(10000000), script_pubkey: outbound_chan.context.get_funding_redeemscript(),
}]};
let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
let funding_created = outbound_chan.get_funding_created(tx.clone(), funding_outpoint, false, &&logger).map_err(|_| ()).unwrap().unwrap();
&htlc, $opt_anchors, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, $opt_anchors, &keys);
let htlc_sighashtype = if $opt_anchors.supports_anchors_zero_fee_htlc_tx() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
- let htlc_sighash = Message::from_slice(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]).unwrap();
+ let htlc_sighash = Message::from_digest(sighash::SighashCache::new(&htlc_tx).p2wsh_signature_hash(0, &htlc_redeemscript, htlc.to_bitcoin_amount(), htlc_sighashtype).unwrap().as_raw_hash().to_byte_array());
assert!(secp_ctx.verify_ecdsa(&htlc_sighash, &remote_signature, &keys.countersignatory_htlc_key.to_public_key()).is_ok(), "verify counterparty htlc sig");
let mut preimage: Option<PaymentPreimage> = None;
// Fund the channel with a batch funding transaction.
let output_script = node_a_chan.context.get_funding_redeemscript();
let tx = Transaction {
- version: 1,
+ version: Version::ONE,
lock_time: LockTime::ZERO,
input: Vec::new(),
output: vec![
TxOut {
- value: 10000000, script_pubkey: output_script.clone(),
+ value: Amount::from_sat(10000000), script_pubkey: output_script.clone(),
},
TxOut {
- value: 10000000, script_pubkey: Builder::new().into_script(),
+ value: Amount::from_sat(10000000), script_pubkey: Builder::new().into_script(),
},
]};
let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
// Clear the ChannelState::WaitingForBatch only when called by ChannelManager.
node_a_chan.set_batch_ready();
assert_eq!(node_a_chan.context.channel_state, ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::THEIR_CHANNEL_READY));
- assert!(node_a_chan.check_get_channel_ready(0).is_some());
+ assert!(node_a_chan.check_get_channel_ready(0, &&logger).is_some());
}
}