use bitcoin::secp256k1;
use ln::{PaymentPreimage, PaymentHash};
-use ln::features::{ChannelFeatures, InitFeatures};
+use ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures};
use ln::msgs;
use ln::msgs::{DecodeError, OptionalField, DataLossProtect};
use ln::script::{self, ShutdownScript};
use ln::chan_utils;
use chain::BestBlock;
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
-use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, HTLC_FAIL_BACK_BUFFER};
+use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS};
use chain::transaction::{OutPoint, TransactionData};
use chain::keysinterface::{Sign, KeysInterface};
+use util::events::ClosureReason;
use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
use util::logger::Logger;
use util::errors::APIError;
pub counterparty_dust_limit_msat: u64,
}
-#[derive(Clone, Copy, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq)]
enum FeeUpdateState {
// Inbound states mirroring InboundHTLCState
RemoteAnnounced,
pending_htlcs_value_msat: u64,
on_counterparty_tx_dust_exposure_msat: u64,
on_holder_tx_dust_exposure_msat: u64,
+ holding_cell_msat: u64,
+ on_holder_tx_holding_cell_htlcs_count: u32, // dust HTLCs *non*-included
+}
+
+/// An enum gathering stats on commitment transaction, either local or remote.
+struct CommitmentStats<'a> {
+ tx: CommitmentTransaction, // the transaction info
+ feerate_per_kw: u32, // the feerate included to build the transaction
+ total_fee_sat: u64, // the total fee included in the transaction
+ num_nondust_htlcs: usize, // the number of HTLC outputs (dust HTLCs *non*-included)
+ htlcs_included: Vec<(HTLCOutputInCommitment, Option<&'a HTLCSource>)>, // the list of HTLCs (dust HTLCs *included*) which were not ignored when building the transaction
+ local_balance_msat: u64, // local balance before fees but considering dust limits
+ remote_balance_msat: u64, // remote balance before fees but considering dust limits
}
/// Used when calculating whether we or the remote can afford an additional HTLC.
DuplicateClaim {},
}
+/// The return value of `revoke_and_ack` on success, primarily updates to other channels or HTLC
+/// state.
+pub(super) struct RAAUpdates {
+ pub commitment_update: Option<msgs::CommitmentUpdate>,
+ pub accepted_htlcs: Vec<(PendingHTLCInfo, u64)>,
+ pub failed_htlcs: Vec<(HTLCSource, PaymentHash, HTLCFailReason)>,
+ pub finalized_claimed_htlcs: Vec<HTLCSource>,
+ pub monitor_update: ChannelMonitorUpdate,
+ pub holding_cell_failed_htlcs: Vec<(HTLCSource, PaymentHash)>,
+}
+
+/// The return value of `monitor_updating_restored`
+pub(super) struct MonitorRestoreUpdates {
+ pub raa: Option<msgs::RevokeAndACK>,
+ pub commitment_update: Option<msgs::CommitmentUpdate>,
+ pub order: RAACommitmentOrder,
+ pub accepted_htlcs: Vec<(PendingHTLCInfo, u64)>,
+ pub failed_htlcs: Vec<(HTLCSource, PaymentHash, HTLCFailReason)>,
+ pub finalized_claimed_htlcs: Vec<HTLCSource>,
+ pub funding_broadcastable: Option<Transaction>,
+ pub funding_locked: Option<msgs::FundingLocked>,
+}
+
/// 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
/// the channel. Sadly, there isn't really a good number for this - if we expect to have no new
/// HTLCs for days we may need this to suffice for feerate increases across days, but that may
/// leave the channel less usable as we hold a bigger reserve.
-#[cfg(fuzzing)]
+#[cfg(any(fuzzing, test))]
pub const FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE: u64 = 2;
-#[cfg(not(fuzzing))]
+#[cfg(not(any(fuzzing, test)))]
const FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE: u64 = 2;
+/// If we fail to see a funding transaction confirmed on-chain within this many blocks after the
+/// channel creation on an inbound channel, we simply force-close and move on.
+/// This constant is the one suggested in BOLT 2.
+pub(crate) const FUNDING_CONF_DEADLINE_BLOCKS: u32 = 2016;
+
+/// In case of a concurrent update_add_htlc proposed by our counterparty, we might
+/// not have enough balance value remaining to cover the onchain cost of this new
+/// HTLC weight. If this happens, our counterparty fails the reception of our
+/// commitment_signed including this new HTLC due to infringement on the channel
+/// reserve.
+/// To prevent this case, we compute our outbound update_fee with an HTLC buffer of
+/// size 2. However, if the number of concurrent update_add_htlc is higher, this still
+/// leads to a channel force-close. Ultimately, this is an issue coming from the
+/// design of LN state machines, allowing asynchronous updates.
+pub(crate) const CONCURRENT_INBOUND_HTLC_FEE_BUFFER: u32 = 2;
+
+/// When a channel is opened, we check that the funding amount is enough to pay for relevant
+/// commitment transaction fees, with at least this many HTLCs present on the commitment
+/// transaction (not counting the value of the HTLCs themselves).
+pub(crate) const MIN_AFFORDABLE_HTLC_COUNT: usize = 4;
+
// 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
monitor_pending_commitment_signed: bool,
monitor_pending_forwards: Vec<(PendingHTLCInfo, u64)>,
monitor_pending_failures: Vec<(HTLCSource, PaymentHash, HTLCFailReason)>,
+ monitor_pending_finalized_fulfills: Vec<HTLCSource>,
// pending_update_fee is filled when sending and receiving update_fee.
//
funding_tx_confirmed_in: Option<BlockHash>,
funding_tx_confirmation_height: u32,
short_channel_id: Option<u64>,
+ /// 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,
counterparty_dust_limit_satoshis: u64,
+
#[cfg(test)]
pub(super) holder_dust_limit_satoshis: u64,
#[cfg(not(test))]
holder_dust_limit_satoshis: u64,
+
#[cfg(test)]
pub(super) counterparty_max_htlc_value_in_flight_msat: u64,
#[cfg(not(test))]
counterparty_max_htlc_value_in_flight_msat: u64,
- //get_holder_max_htlc_value_in_flight_msat(): u64,
+
+ #[cfg(test)]
+ pub(super) holder_max_htlc_value_in_flight_msat: u64,
+ #[cfg(not(test))]
+ holder_max_htlc_value_in_flight_msat: u64,
+
/// minimum channel reserve for self to maintain - set by them.
counterparty_selected_channel_reserve_satoshis: Option<u64>,
- // get_holder_selected_channel_reserve_satoshis(channel_value_sats: u64): u64
+
+ #[cfg(test)]
+ pub(super) holder_selected_channel_reserve_satoshis: u64,
+ #[cfg(not(test))]
+ holder_selected_channel_reserve_satoshis: u64,
+
counterparty_htlc_minimum_msat: u64,
holder_htlc_minimum_msat: u64,
#[cfg(test)]
// is fine, but as a sanity check in our failure to generate the second claim, we check here
// that the original was a claim, and that we aren't now trying to fulfill a failed HTLC.
historical_inbound_htlc_fulfills: HashSet<u64>,
+
+ /// This channel's type, as negotiated during channel open
+ channel_type: ChannelTypeFeatures,
}
#[cfg(any(test, feature = "fuzztarget"))]
/// required by us.
///
/// Guaranteed to return a value no larger than channel_value_satoshis
+ ///
+ /// This is used both for new channels and to figure out what reserve value we sent to peers
+ /// for channels serialized before we included our selected reserve value in the serialized
+ /// data explicitly.
pub(crate) fn get_holder_selected_channel_reserve_satoshis(channel_value_satoshis: u64) -> u64 {
let (q, _) = channel_value_satoshis.overflowing_div(100);
cmp::min(channel_value_satoshis, cmp::max(q, 1000)) //TODO
}
+ pub(crate) fn opt_anchors(&self) -> bool {
+ self.channel_transaction_parameters.opt_anchors.is_some()
+ }
+
// Constructors:
- pub fn new_outbound<K: Deref, F: Deref>(fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures, channel_value_satoshis: u64, push_msat: u64, user_id: u64, config: &UserConfig) -> Result<Channel<Signer>, APIError>
+ pub fn new_outbound<K: Deref, F: Deref>(
+ fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures,
+ channel_value_satoshis: u64, push_msat: u64, user_id: u64, config: &UserConfig, current_chain_height: u32
+ ) -> Result<Channel<Signer>, APIError>
where K::Target: KeysInterface<Signer = Signer>,
F::Target: FeeEstimator,
{
let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
+ let value_to_self_msat = channel_value_satoshis * 1000 - push_msat;
+ let commitment_tx_fee = Self::commit_tx_fee_msat(feerate, MIN_AFFORDABLE_HTLC_COUNT);
+ if value_to_self_msat < commitment_tx_fee {
+ return Err(APIError::APIMisuseError{ err: format!("Funding amount ({}) can't even pay fee for initial commitment transaction fee of {}.", value_to_self_msat / 1000, commitment_tx_fee / 1000) });
+ }
+
let mut secp_ctx = Secp256k1::new();
secp_ctx.seeded_randomize(&keys_provider.get_secure_random_bytes());
cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
cur_counterparty_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
- value_to_self_msat: channel_value_satoshis * 1000 - push_msat,
+ value_to_self_msat,
pending_inbound_htlcs: Vec::new(),
pending_outbound_htlcs: Vec::new(),
monitor_pending_commitment_signed: false,
monitor_pending_forwards: Vec::new(),
monitor_pending_failures: Vec::new(),
+ monitor_pending_finalized_fulfills: Vec::new(),
#[cfg(debug_assertions)]
holder_max_commitment_tx_output: Mutex::new((channel_value_satoshis * 1000 - push_msat, push_msat)),
funding_tx_confirmed_in: None,
funding_tx_confirmation_height: 0,
short_channel_id: None,
+ channel_creation_height: current_chain_height,
feerate_per_kw: feerate,
counterparty_dust_limit_satoshis: 0,
holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
counterparty_max_htlc_value_in_flight_msat: 0,
+ holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis),
counterparty_selected_channel_reserve_satoshis: None, // Filled in in accept_channel
+ holder_selected_channel_reserve_satoshis,
counterparty_htlc_minimum_msat: 0,
holder_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat },
counterparty_max_accepted_htlcs: 0,
holder_selected_contest_delay: config.own_channel_config.our_to_self_delay,
is_outbound_from_holder: true,
counterparty_parameters: None,
- funding_outpoint: None
+ funding_outpoint: None,
+ opt_anchors: None,
},
funding_transaction: None,
#[cfg(any(test, feature = "fuzztarget"))]
historical_inbound_htlc_fulfills: HashSet::new(),
+
+ // We currently only actually support one channel type, so don't retry with new types
+ // on error messages. When we support more we'll need fallback support (assuming we
+ // want to support old types).
+ channel_type: ChannelTypeFeatures::only_static_remote_key(),
})
}
where F::Target: FeeEstimator
{
let lower_limit = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
- if feerate_per_kw < lower_limit {
- return Err(ChannelError::Close(format!("Peer's feerate much too low. Actual: {}. Our expected lower limit: {}", feerate_per_kw, lower_limit)));
+ // Some fee estimators round up to the next full sat/vbyte (ie 250 sats per kw), causing
+ // occasional issues with feerate disagreements between an initiator that wants a feerate
+ // of 1.1 sat/vbyte and a receiver that wants 1.1 rounded up to 2. Thus, we always add 250
+ // sat/kw before the comparison here.
+ if feerate_per_kw + 250 < lower_limit {
+ return Err(ChannelError::Close(format!("Peer's feerate much too low. Actual: {}. Our expected lower limit: {} (- 250)", feerate_per_kw, lower_limit)));
}
// We only bound the fee updates on the upper side to prevent completely absurd feerates,
// always accepting up to 25 sat/vByte or 10x our fee estimator's "High Priority" fee.
/// Creates a new channel from a remote sides' request for one.
/// Assumes chain_hash has already been checked and corresponds with what we expect!
- pub fn new_from_req<K: Deref, F: Deref>(fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures, msg: &msgs::OpenChannel, user_id: u64, config: &UserConfig) -> Result<Channel<Signer>, ChannelError>
+ pub fn new_from_req<K: Deref, F: Deref, L: Deref>(
+ fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures,
+ msg: &msgs::OpenChannel, user_id: u64, config: &UserConfig, current_chain_height: u32, logger: &L
+ ) -> Result<Channel<Signer>, ChannelError>
where K::Target: KeysInterface<Signer = Signer>,
- F::Target: FeeEstimator
+ F::Target: FeeEstimator,
+ L::Target: Logger,
{
+ // First check the channel type is known, failing before we do anything else if we don't
+ // support this channel type.
+ let channel_type = if let Some(channel_type) = &msg.channel_type {
+ if channel_type.supports_any_optional_bits() {
+ return Err(ChannelError::Close("Channel Type field contained optional bits - this is not allowed".to_owned()));
+ }
+ if *channel_type != ChannelTypeFeatures::only_static_remote_key() {
+ return Err(ChannelError::Close("Channel Type was not understood".to_owned()));
+ }
+ channel_type.clone()
+ } else {
+ ChannelTypeFeatures::from_counterparty_init(&their_features)
+ };
+ if !channel_type.supports_static_remote_key() {
+ return Err(ChannelError::Close("Channel Type was not understood - we require static remote key".to_owned()));
+ }
+
let holder_signer = keys_provider.get_channel_signer(true, msg.funding_satoshis);
let pubkeys = holder_signer.pubkeys().clone();
let counterparty_pubkeys = ChannelPublicKeys {
if msg.dust_limit_satoshis > msg.funding_satoshis {
return Err(ChannelError::Close(format!("dust_limit_satoshis {} was larger than funding_satoshis {}. Peer never wants payout outputs?", msg.dust_limit_satoshis, msg.funding_satoshis)));
}
- if msg.dust_limit_satoshis > msg.channel_reserve_satoshis {
- return Err(ChannelError::Close(format!("Bogus; channel reserve ({}) is less than dust limit ({})", msg.channel_reserve_satoshis, msg.dust_limit_satoshis)));
- }
let full_channel_value_msat = (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000;
if msg.htlc_minimum_msat >= full_channel_value_msat {
return Err(ChannelError::Close(format!("Minimum htlc value ({}) was larger than full channel value ({})", msg.htlc_minimum_msat, full_channel_value_msat)));
// we either accept their preference or the preferences match
local_config.announced_channel = announce;
- let background_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
-
let holder_selected_channel_reserve_satoshis = Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(msg.funding_satoshis);
if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
return Err(ChannelError::Close(format!("Suitable channel reserve not found. remote_channel_reserve was ({}). dust_limit_satoshis is ({}).", holder_selected_channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
}
if msg.channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
- return Err(ChannelError::Close(format!("channel_reserve_satoshis ({}) is smaller than our dust limit ({})", msg.channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
+ log_debug!(logger, "channel_reserve_satoshis ({}) is smaller than our dust limit ({}). We can broadcast stale states without any risk, implying this channel is very insecure for our counterparty.",
+ msg.channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);
}
if holder_selected_channel_reserve_satoshis < msg.dust_limit_satoshis {
return Err(ChannelError::Close(format!("Dust limit ({}) too high for the channel reserve we require the remote to keep ({})", msg.dust_limit_satoshis, holder_selected_channel_reserve_satoshis)));
}
// check if the funder's amount for the initial commitment tx is sufficient
- // for full fee payment
+ // for full fee payment plus a few HTLCs to ensure the channel will be useful.
let funders_amount_msat = msg.funding_satoshis * 1000 - msg.push_msat;
- let lower_limit = background_feerate as u64 * COMMITMENT_TX_BASE_WEIGHT;
- if funders_amount_msat < lower_limit {
- return Err(ChannelError::Close(format!("Insufficient funding amount ({}) for initial commitment. Must be at least {}", funders_amount_msat, lower_limit)));
+ let commitment_tx_fee = Self::commit_tx_fee_msat(msg.feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT) / 1000;
+ if funders_amount_msat / 1000 < commitment_tx_fee {
+ return Err(ChannelError::Close(format!("Funding amount ({} sats) can't even pay fee for initial commitment transaction fee of {} sats.", funders_amount_msat / 1000, commitment_tx_fee)));
}
- let to_local_msat = msg.push_msat;
- let to_remote_msat = funders_amount_msat - background_feerate as u64 * COMMITMENT_TX_BASE_WEIGHT;
- if to_local_msat <= msg.channel_reserve_satoshis * 1000 && to_remote_msat <= holder_selected_channel_reserve_satoshis * 1000 {
- return Err(ChannelError::Close("Insufficient funding amount for initial commitment".to_owned()));
+ let to_remote_satoshis = funders_amount_msat / 1000 - commitment_tx_fee;
+ // While it's reasonable for us to not meet the channel reserve initially (if they don't
+ // want to push much to us), our counterparty should always have more than our reserve.
+ if to_remote_satoshis < holder_selected_channel_reserve_satoshis {
+ return Err(ChannelError::Close("Insufficient funding amount for initial reserve".to_owned()));
}
let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() {
monitor_pending_commitment_signed: false,
monitor_pending_forwards: Vec::new(),
monitor_pending_failures: Vec::new(),
+ monitor_pending_finalized_fulfills: Vec::new(),
#[cfg(debug_assertions)]
holder_max_commitment_tx_output: Mutex::new((msg.push_msat, msg.funding_satoshis * 1000 - msg.push_msat)),
funding_tx_confirmed_in: None,
funding_tx_confirmation_height: 0,
short_channel_id: None,
+ channel_creation_height: current_chain_height,
feerate_per_kw: msg.feerate_per_kw,
channel_value_satoshis: msg.funding_satoshis,
counterparty_dust_limit_satoshis: msg.dust_limit_satoshis,
holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
counterparty_max_htlc_value_in_flight_msat: cmp::min(msg.max_htlc_value_in_flight_msat, msg.funding_satoshis * 1000),
+ holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(msg.funding_satoshis),
counterparty_selected_channel_reserve_satoshis: Some(msg.channel_reserve_satoshis),
+ holder_selected_channel_reserve_satoshis,
counterparty_htlc_minimum_msat: msg.htlc_minimum_msat,
holder_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat },
counterparty_max_accepted_htlcs: msg.max_accepted_htlcs,
selected_contest_delay: msg.to_self_delay,
pubkeys: counterparty_pubkeys,
}),
- funding_outpoint: None
+ funding_outpoint: None,
+ opt_anchors: None
},
funding_transaction: None,
#[cfg(any(test, feature = "fuzztarget"))]
historical_inbound_htlc_fulfills: HashSet::new(),
+
+ channel_type,
};
Ok(chan)
/// 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.
- /// Returns (the transaction info, the number of HTLC outputs which were present in the
- /// transaction, the list of HTLCs which were not ignored when building the transaction).
- /// Note that below-dust HTLCs are included in the fourth return value, but not the third, and
- /// sources are provided only for outbound HTLCs in the fourth return value.
#[inline]
- fn build_commitment_transaction<L: Deref>(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, logger: &L) -> (CommitmentTransaction, u32, usize, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>) where L::Target: Logger {
+ 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 value_to_self_msat: i64 = (self.value_to_self_msat - local_htlc_total_msat) as i64 + value_to_self_msat_offset;
+ 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 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;
+ 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)]
};
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 >= Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) as i64);
+ 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 = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (included_non_dust_htlcs.len() as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
+ let total_fee_sat = Channel::<Signer>::commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len());
let (value_to_self, value_to_remote) = if self.is_outbound() {
- (value_to_self_msat / 1000 - total_fee as i64, value_to_remote_msat / 1000)
+ (value_to_self_msat / 1000 - total_fee_sat as i64, value_to_remote_msat / 1000)
} else {
- (value_to_self_msat / 1000, value_to_remote_msat / 1000 - total_fee as i64)
+ (value_to_self_msat / 1000, value_to_remote_msat / 1000 - total_fee_sat as i64)
};
let mut value_to_a = if local { value_to_self } else { value_to_remote };
let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number,
value_to_a as u64,
value_to_b as u64,
- false,
+ self.channel_transaction_parameters.opt_anchors.is_some(),
funding_pubkey_a,
funding_pubkey_b,
keys.clone(),
htlcs_included.sort_unstable_by_key(|h| h.0.transaction_output_index.unwrap());
htlcs_included.append(&mut included_dust_htlcs);
- (tx, feerate_per_kw, num_nondust_htlcs, htlcs_included)
+ // 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,
+ }
}
#[inline]
if msg.channel_reserve_satoshis > self.channel_value_satoshis {
return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than ({})", msg.channel_reserve_satoshis, self.channel_value_satoshis)));
}
- if msg.channel_reserve_satoshis < self.holder_dust_limit_satoshis {
- return Err(ChannelError::Close(format!("Peer never wants payout outputs? channel_reserve_satoshis was ({}). dust_limit is ({})", msg.channel_reserve_satoshis, self.holder_dust_limit_satoshis)));
- }
- let remote_reserve = Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis);
- if msg.dust_limit_satoshis > remote_reserve {
- return Err(ChannelError::Close(format!("Dust limit ({}) is bigger than our channel reserve ({})", msg.dust_limit_satoshis, remote_reserve)));
+ if msg.dust_limit_satoshis > self.holder_selected_channel_reserve_satoshis {
+ return Err(ChannelError::Close(format!("Dust limit ({}) is bigger than our channel reserve ({})", msg.dust_limit_satoshis, self.holder_selected_channel_reserve_satoshis)));
}
let full_channel_value_msat = (self.channel_value_satoshis - msg.channel_reserve_satoshis) * 1000;
if msg.htlc_minimum_msat >= full_channel_value_msat {
let funding_script = self.get_funding_redeemscript();
let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number)?;
- let initial_commitment_tx = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, false, logger).0;
+ let initial_commitment_tx = self.build_commitment_transaction(self.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 counterparty_keys = self.build_remote_transaction_keys()?;
- let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).0;
+ let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.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();
let funding_script = self.get_funding_redeemscript();
let counterparty_keys = self.build_remote_transaction_keys()?;
- let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).0;
+ let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.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_bytes!(self.channel_id()), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
let holder_signer = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number)?;
- let initial_commitment_tx = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &holder_signer, true, false, logger).0;
+ let initial_commitment_tx = self.build_commitment_transaction(self.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();
}
/// Returns a HTLCStats about inbound pending htlcs
- fn get_inbound_pending_htlc_stats(&self) -> HTLCStats {
+ fn get_inbound_pending_htlc_stats(&self, outbound_feerate_update: Option<u32>) -> HTLCStats {
let mut stats = HTLCStats {
pending_htlcs: self.pending_inbound_htlcs.len() as u32,
pending_htlcs_value_msat: 0,
on_counterparty_tx_dust_exposure_msat: 0,
on_holder_tx_dust_exposure_msat: 0,
+ holding_cell_msat: 0,
+ on_holder_tx_holding_cell_htlcs_count: 0,
};
- let counterparty_dust_limit_timeout_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
- let holder_dust_limit_success_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
+ let counterparty_dust_limit_timeout_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
+ let holder_dust_limit_success_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
for ref htlc in self.pending_inbound_htlcs.iter() {
stats.pending_htlcs_value_msat += htlc.amount_msat;
if htlc.amount_msat / 1000 < counterparty_dust_limit_timeout_sat {
}
/// Returns a HTLCStats about pending outbound htlcs, *including* pending adds in our holding cell.
- fn get_outbound_pending_htlc_stats(&self) -> HTLCStats {
+ fn get_outbound_pending_htlc_stats(&self, outbound_feerate_update: Option<u32>) -> HTLCStats {
let mut stats = HTLCStats {
pending_htlcs: self.pending_outbound_htlcs.len() as u32,
pending_htlcs_value_msat: 0,
on_counterparty_tx_dust_exposure_msat: 0,
on_holder_tx_dust_exposure_msat: 0,
+ holding_cell_msat: 0,
+ on_holder_tx_holding_cell_htlcs_count: 0,
};
- let counterparty_dust_limit_success_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
- let holder_dust_limit_timeout_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
+ let counterparty_dust_limit_success_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
+ let holder_dust_limit_timeout_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
for ref htlc in self.pending_outbound_htlcs.iter() {
stats.pending_htlcs_value_msat += htlc.amount_msat;
if htlc.amount_msat / 1000 < counterparty_dust_limit_success_sat {
if let &HTLCUpdateAwaitingACK::AddHTLC { ref amount_msat, .. } = update {
stats.pending_htlcs += 1;
stats.pending_htlcs_value_msat += amount_msat;
+ stats.holding_cell_msat += amount_msat;
if *amount_msat / 1000 < counterparty_dust_limit_success_sat {
stats.on_counterparty_tx_dust_exposure_msat += amount_msat;
}
if *amount_msat / 1000 < holder_dust_limit_timeout_sat {
stats.on_holder_tx_dust_exposure_msat += amount_msat;
+ } else {
+ stats.on_holder_tx_holding_cell_htlcs_count += 1;
}
}
}
(
cmp::max(self.channel_value_satoshis as i64 * 1000
- self.value_to_self_msat as i64
- - self.get_inbound_pending_htlc_stats().pending_htlcs_value_msat as i64
- - Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) as i64 * 1000,
+ - self.get_inbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64
+ - self.holder_selected_channel_reserve_satoshis as i64 * 1000,
0) as u64,
cmp::max(self.value_to_self_msat as i64
- - self.get_outbound_pending_htlc_stats().pending_htlcs_value_msat as i64
+ - self.get_outbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64
- self.counterparty_selected_channel_reserve_satoshis.unwrap_or(0) as i64 * 1000,
0) as u64
)
}
pub fn get_holder_counterparty_selected_channel_reserve_satoshis(&self) -> (u64, Option<u64>) {
- (Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis),
- self.counterparty_selected_channel_reserve_satoshis)
+ (self.holder_selected_channel_reserve_satoshis, self.counterparty_selected_channel_reserve_satoshis)
}
- // Get the fee cost of a commitment tx with a given number of HTLC outputs.
+ // Get the fee cost in MSATS of a commitment tx with a given number of HTLC outputs.
// Note that num_htlcs should not include dust HTLCs.
- fn commit_tx_fee_msat(&self, num_htlcs: usize) -> u64 {
+ fn commit_tx_fee_msat(feerate_per_kw: u32, num_htlcs: usize) -> u64 {
// Note that we need to divide before multiplying to round properly,
// since the lowest denomination of bitcoin on-chain is the satoshi.
- (COMMITMENT_TX_BASE_WEIGHT + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * self.feerate_per_kw as u64 / 1000 * 1000
+ (COMMITMENT_TX_BASE_WEIGHT + 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) -> u64 {
+ feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + 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
}
let num_htlcs = included_htlcs + addl_htlcs;
- let res = self.commit_tx_fee_msat(num_htlcs);
+ let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs);
#[cfg(any(test, feature = "fuzztarget"))]
{
let mut fee = res;
if fee_spike_buffer_htlc.is_some() {
- fee = self.commit_tx_fee_msat(num_htlcs - 1);
+ fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1);
}
let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len()
+ self.holding_cell_htlc_updates.len();
}
let num_htlcs = included_htlcs + addl_htlcs;
- let res = self.commit_tx_fee_msat(num_htlcs);
+ let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs);
#[cfg(any(test, feature = "fuzztarget"))]
{
let mut fee = res;
if fee_spike_buffer_htlc.is_some() {
- fee = self.commit_tx_fee_msat(num_htlcs - 1);
+ fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1);
}
let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len();
let commitment_tx_info = CommitmentTxInfoCached {
return Err(ChannelError::Close(format!("Remote side tried to send less than our minimum HTLC value. Lower limit: ({}). Actual: ({})", self.holder_htlc_minimum_msat, msg.amount_msat)));
}
- let inbound_stats = self.get_inbound_pending_htlc_stats();
- let outbound_stats = self.get_outbound_pending_htlc_stats();
+ let inbound_stats = self.get_inbound_pending_htlc_stats(None);
+ let outbound_stats = self.get_outbound_pending_htlc_stats(None);
if inbound_stats.pending_htlcs + 1 > OUR_MAX_HTLCS as u32 {
return Err(ChannelError::Close(format!("Remote tried to push more than our max accepted HTLCs ({})", OUR_MAX_HTLCS)));
}
- let holder_max_htlc_value_in_flight_msat = Channel::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis);
- if inbound_stats.pending_htlcs_value_msat + msg.amount_msat > holder_max_htlc_value_in_flight_msat {
- return Err(ChannelError::Close(format!("Remote HTLC add would put them over our max HTLC value ({})", holder_max_htlc_value_in_flight_msat)));
+ if inbound_stats.pending_htlcs_value_msat + msg.amount_msat > self.holder_max_htlc_value_in_flight_msat {
+ return Err(ChannelError::Close(format!("Remote HTLC add would put them over our max HTLC value ({})", self.holder_max_htlc_value_in_flight_msat)));
}
// Check holder_selected_channel_reserve_satoshis (we're getting paid, so they have to at least meet
// the reserve_satoshis we told them to always have as direct payment so that they lose
}
}
- let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
+ let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
if msg.amount_msat / 1000 < exposure_dust_limit_timeout_sats {
let on_counterparty_tx_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat + msg.amount_msat;
if on_counterparty_tx_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
}
}
- let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
+ let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
if msg.amount_msat / 1000 < exposure_dust_limit_success_sats {
let on_holder_tx_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat + msg.amount_msat;
if on_holder_tx_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
return Err(ChannelError::Close("Remote HTLC add would not leave enough to pay for fees".to_owned()));
};
- let chan_reserve_msat =
- Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) * 1000;
- if pending_remote_value_msat - msg.amount_msat - remote_commit_tx_fee_msat < chan_reserve_msat {
+ if pending_remote_value_msat - msg.amount_msat - remote_commit_tx_fee_msat < self.holder_selected_channel_reserve_satoshis * 1000 {
return Err(ChannelError::Close("Remote HTLC add would put them under remote reserve value".to_owned()));
}
// sensitive to fee spikes.
let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered);
let remote_fee_cost_incl_stuck_buffer_msat = 2 * self.next_remote_commit_tx_fee_msat(htlc_candidate, Some(()));
- if pending_remote_value_msat - msg.amount_msat - chan_reserve_msat < remote_fee_cost_incl_stuck_buffer_msat {
+ if pending_remote_value_msat - msg.amount_msat - self.holder_selected_channel_reserve_satoshis * 1000 < remote_fee_cost_incl_stuck_buffer_msat {
// Note that if the pending_forward_status is not updated here, then it's because we're already failing
// the HTLC, i.e. its status is already set to failing.
log_info!(logger, "Attempting to fail HTLC due to fee spike buffer violation in channel {}. Rebalancing is required.", log_bytes!(self.channel_id()));
let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number).map_err(|e| (None, e))?;
- let (num_htlcs, mut htlcs_cloned, commitment_tx, commitment_txid, feerate_per_kw) = {
- let commitment_tx = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, false, logger);
- let commitment_txid = {
- let trusted_tx = commitment_tx.0.trust();
- let bitcoin_tx = trusted_tx.built_transaction();
- let sighash = bitcoin_tx.get_sighash_all(&funding_script, self.channel_value_satoshis);
-
- 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!(sighash[..]), encode::serialize_hex(&funding_script), log_bytes!(self.channel_id()));
- if let Err(_) = self.secp_ctx.verify(&sighash, &msg.signature, &self.counterparty_funding_pubkey()) {
- return Err((None, ChannelError::Close("Invalid commitment tx signature from peer".to_owned())));
- }
- bitcoin_tx.txid
- };
- let htlcs_cloned: Vec<_> = commitment_tx.3.iter().map(|htlc| (htlc.0.clone(), htlc.1.map(|h| h.clone()))).collect();
- (commitment_tx.2, htlcs_cloned, commitment_tx.0, commitment_txid, commitment_tx.1)
+ let commitment_stats = self.build_commitment_transaction(self.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();
+ let sighash = bitcoin_tx.get_sighash_all(&funding_script, self.channel_value_satoshis);
+
+ 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!(sighash[..]), encode::serialize_hex(&funding_script), log_bytes!(self.channel_id()));
+ if let Err(_) = self.secp_ctx.verify(&sighash, &msg.signature, &self.counterparty_funding_pubkey()) {
+ return Err((None, ChannelError::Close("Invalid commitment tx signature from peer".to_owned())));
+ }
+ bitcoin_tx.txid
};
+ let mut htlcs_cloned: Vec<_> = commitment_stats.htlcs_included.iter().map(|htlc| (htlc.0.clone(), htlc.1.map(|h| h.clone()))).collect();
// If our counterparty updated the channel fee in this commitment transaction, check that
// they can actually afford the new fee now.
let update_fee = if let Some((_, update_state)) = self.pending_update_fee {
update_state == FeeUpdateState::RemoteAnnounced
} else { false };
- if update_fee { debug_assert!(!self.is_outbound()); }
- let total_fee = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
if update_fee {
- let counterparty_reserve_we_require = Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis);
- if self.channel_value_satoshis - self.value_to_self_msat / 1000 < total_fee + counterparty_reserve_we_require {
+ debug_assert!(!self.is_outbound());
+ let counterparty_reserve_we_require_msat = self.holder_selected_channel_reserve_satoshis * 1000;
+ if commitment_stats.remote_balance_msat < commitment_stats.total_fee_sat * 1000 + counterparty_reserve_we_require_msat {
return Err((None, ChannelError::Close("Funding remote cannot afford proposed new fee".to_owned())));
}
}
&& info.next_holder_htlc_id == self.next_holder_htlc_id
&& info.next_counterparty_htlc_id == self.next_counterparty_htlc_id
&& info.feerate == self.feerate_per_kw {
- assert_eq!(total_fee, info.fee / 1000);
+ assert_eq!(commitment_stats.total_fee_sat, info.fee / 1000);
}
}
}
}
- if msg.htlc_signatures.len() != num_htlcs {
- return Err((None, ChannelError::Close(format!("Got wrong number of HTLC signatures ({}) from remote. It must be {}", msg.htlc_signatures.len(), num_htlcs))));
+ if msg.htlc_signatures.len() != commitment_stats.num_nondust_htlcs {
+ return Err((None, ChannelError::Close(format!("Got wrong number of HTLC signatures ({}) from remote. It must be {}", msg.htlc_signatures.len(), commitment_stats.num_nondust_htlcs))));
}
// TODO: Sadly, we pass HTLCs twice to ChannelMonitor: once via the HolderCommitmentTransaction and once via the update
let mut htlcs_and_sigs = Vec::with_capacity(htlcs_cloned.len());
for (idx, (htlc, source)) in htlcs_cloned.drain(..).enumerate() {
if let Some(_) = htlc.transaction_output_index {
- let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, feerate_per_kw,
- self.get_counterparty_selected_contest_delay().unwrap(), &htlc,
+ let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_stats.feerate_per_kw,
+ self.get_counterparty_selected_contest_delay().unwrap(), &htlc, self.opt_anchors(),
&keys.broadcaster_delayed_payment_key, &keys.revocation_key);
- let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
+ let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &keys);
let htlc_sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, SigHashType::All)[..]);
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.serialize()),
}
let holder_commitment_tx = HolderCommitmentTransaction::new(
- commitment_tx,
+ commitment_stats.tx,
msg.signature,
msg.htlc_signatures.clone(),
&self.get_holder_pubkeys().funding_pubkey,
// to rebalance channels.
match &htlc_update {
&HTLCUpdateAwaitingACK::AddHTLC {amount_msat, cltv_expiry, ref payment_hash, ref source, ref onion_routing_packet, ..} => {
- match self.send_htlc(amount_msat, *payment_hash, cltv_expiry, source.clone(), onion_routing_packet.clone()) {
+ match self.send_htlc(amount_msat, *payment_hash, cltv_expiry, source.clone(), onion_routing_packet.clone(), logger) {
Ok(update_add_msg_option) => update_add_htlcs.push(update_add_msg_option.unwrap()),
Err(e) => {
match e {
return Ok((None, htlcs_to_fail));
}
let update_fee = if let Some(feerate) = self.holding_cell_update_fee.take() {
- assert!(self.is_outbound());
- self.pending_update_fee = Some((feerate, FeeUpdateState::Outbound));
- Some(msgs::UpdateFee {
- channel_id: self.channel_id,
- feerate_per_kw: feerate as u32,
- })
+ self.send_update_fee(feerate, logger)
} else {
None
};
/// waiting on this revoke_and_ack. The generation of this new commitment_signed may also fail,
/// generating an appropriate error *after* the channel state has been updated based on the
/// revoke_and_ack message.
- pub fn revoke_and_ack<L: Deref>(&mut self, msg: &msgs::RevokeAndACK, logger: &L) -> Result<(Option<msgs::CommitmentUpdate>, Vec<(PendingHTLCInfo, u64)>, Vec<(HTLCSource, PaymentHash, HTLCFailReason)>, ChannelMonitorUpdate, Vec<(HTLCSource, PaymentHash)>), ChannelError>
+ pub fn revoke_and_ack<L: Deref>(&mut self, msg: &msgs::RevokeAndACK, logger: &L) -> Result<RAAUpdates, ChannelError>
where L::Target: Logger,
{
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
log_trace!(logger, "Updating HTLCs on receipt of RAA in channel {}...", log_bytes!(self.channel_id()));
let mut to_forward_infos = Vec::new();
let mut revoked_htlcs = Vec::new();
+ let mut finalized_claimed_htlcs = Vec::new();
let mut update_fail_htlcs = Vec::new();
let mut update_fail_malformed_htlcs = Vec::new();
let mut require_commitment = false;
if let Some(reason) = fail_reason.clone() { // We really want take() here, but, again, non-mut ref :(
revoked_htlcs.push((htlc.source.clone(), htlc.payment_hash, reason));
} else {
+ finalized_claimed_htlcs.push(htlc.source.clone());
// They fulfilled, so we sent them money
value_to_self_msat_diff -= htlc.amount_msat as i64;
}
}
self.monitor_pending_forwards.append(&mut to_forward_infos);
self.monitor_pending_failures.append(&mut revoked_htlcs);
+ self.monitor_pending_finalized_fulfills.append(&mut finalized_claimed_htlcs);
log_debug!(logger, "Received a valid revoke_and_ack for channel {} but awaiting a monitor update resolution to reply.", log_bytes!(self.channel_id()));
- return Ok((None, Vec::new(), Vec::new(), monitor_update, Vec::new()))
+ return Ok(RAAUpdates {
+ commitment_update: None, finalized_claimed_htlcs: Vec::new(),
+ accepted_htlcs: Vec::new(), failed_htlcs: Vec::new(),
+ monitor_update,
+ holding_cell_failed_htlcs: Vec::new()
+ });
}
match self.free_holding_cell_htlcs(logger)? {
self.latest_monitor_update_id = monitor_update.update_id;
monitor_update.updates.append(&mut additional_update.updates);
- Ok((Some(commitment_update), to_forward_infos, revoked_htlcs, monitor_update, htlcs_to_fail))
+ Ok(RAAUpdates {
+ commitment_update: Some(commitment_update),
+ finalized_claimed_htlcs,
+ accepted_htlcs: to_forward_infos,
+ failed_htlcs: revoked_htlcs,
+ monitor_update,
+ holding_cell_failed_htlcs: htlcs_to_fail
+ })
},
(None, htlcs_to_fail) => {
if require_commitment {
log_debug!(logger, "Received a valid revoke_and_ack for channel {}. Responding with a commitment update with {} HTLCs failed.",
log_bytes!(self.channel_id()), update_fail_htlcs.len() + update_fail_malformed_htlcs.len());
- Ok((Some(msgs::CommitmentUpdate {
- update_add_htlcs: Vec::new(),
- update_fulfill_htlcs: Vec::new(),
- update_fail_htlcs,
- update_fail_malformed_htlcs,
- update_fee: None,
- commitment_signed
- }), to_forward_infos, revoked_htlcs, monitor_update, htlcs_to_fail))
+ Ok(RAAUpdates {
+ commitment_update: Some(msgs::CommitmentUpdate {
+ update_add_htlcs: Vec::new(),
+ update_fulfill_htlcs: Vec::new(),
+ update_fail_htlcs,
+ update_fail_malformed_htlcs,
+ update_fee: None,
+ commitment_signed
+ }),
+ finalized_claimed_htlcs,
+ accepted_htlcs: to_forward_infos, failed_htlcs: revoked_htlcs,
+ monitor_update, holding_cell_failed_htlcs: htlcs_to_fail
+ })
} else {
log_debug!(logger, "Received a valid revoke_and_ack for channel {} with no reply necessary.", log_bytes!(self.channel_id()));
- Ok((None, to_forward_infos, revoked_htlcs, monitor_update, htlcs_to_fail))
+ Ok(RAAUpdates {
+ commitment_update: None,
+ finalized_claimed_htlcs,
+ accepted_htlcs: to_forward_infos, failed_htlcs: revoked_htlcs,
+ monitor_update, holding_cell_failed_htlcs: htlcs_to_fail
+ })
}
}
}
/// Adds a pending update to this channel. See the doc for send_htlc for
/// further details on the optionness of the return value.
+ /// If our balance is too low to cover the cost of the next commitment transaction at the
+ /// new feerate, the update is cancelled.
/// You MUST call send_commitment prior to any other calls on this Channel
- fn send_update_fee(&mut self, feerate_per_kw: u32) -> Option<msgs::UpdateFee> {
+ fn send_update_fee<L: Deref>(&mut self, feerate_per_kw: u32, logger: &L) -> Option<msgs::UpdateFee> where L::Target: Logger {
if !self.is_outbound() {
panic!("Cannot send fee from inbound channel");
}
panic!("Cannot update fee while peer is disconnected/we're awaiting a monitor update (ChannelManager should have caught this)");
}
+ // 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 = if let Ok(keys) = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number) { keys } else { return None; };
+ let commitment_stats = self.build_commitment_transaction(self.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) * 1000;
+ let holder_balance_msat = commitment_stats.local_balance_msat - outbound_stats.holding_cell_msat;
+ if holder_balance_msat < buffer_fee_msat + self.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 {
+ //TODO: auto-close after a number of failures?
+ log_debug!(logger, "Cannot afford to send new feerate at {}", feerate_per_kw);
+ return None;
+ }
+
+ // Note, we evaluate pending htlc "preemptive" trimmed-to-dust threshold at the proposed `feerate_per_kw`.
+ let holder_tx_dust_exposure = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat;
+ let counterparty_tx_dust_exposure = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat;
+ if holder_tx_dust_exposure > self.get_max_dust_htlc_exposure_msat() {
+ log_debug!(logger, "Cannot afford to send new feerate at {} without infringing max dust htlc exposure", feerate_per_kw);
+ return None;
+ }
+ if counterparty_tx_dust_exposure > self.get_max_dust_htlc_exposure_msat() {
+ log_debug!(logger, "Cannot afford to send new feerate at {} without infringing max dust htlc exposure", feerate_per_kw);
+ return None;
+ }
+
if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::MonitorUpdateFailed as u32)) != 0 {
self.holding_cell_update_fee = Some(feerate_per_kw);
return None;
}
pub fn send_update_fee_and_commit<L: Deref>(&mut self, feerate_per_kw: u32, logger: &L) -> Result<Option<(msgs::UpdateFee, msgs::CommitmentSigned, ChannelMonitorUpdate)>, ChannelError> where L::Target: Logger {
- match self.send_update_fee(feerate_per_kw) {
+ match self.send_update_fee(feerate_per_kw, logger) {
Some(update_fee) => {
let (commitment_signed, monitor_update) = self.send_commitment_no_status_check(logger)?;
Ok(Some((update_fee, commitment_signed, monitor_update)))
/// which failed. The messages which were generated from that call which generated the
/// monitor update failure must *not* have been sent to the remote end, and must instead
/// have been dropped. They will be regenerated when monitor_updating_restored is called.
- pub fn monitor_update_failed(&mut self, resend_raa: bool, resend_commitment: bool, mut pending_forwards: Vec<(PendingHTLCInfo, u64)>, mut pending_fails: Vec<(HTLCSource, PaymentHash, HTLCFailReason)>) {
+ pub fn monitor_update_failed(&mut self, resend_raa: bool, resend_commitment: bool,
+ mut pending_forwards: Vec<(PendingHTLCInfo, u64)>,
+ mut pending_fails: Vec<(HTLCSource, PaymentHash, HTLCFailReason)>,
+ mut pending_finalized_claimed_htlcs: Vec<HTLCSource>
+ ) {
self.monitor_pending_revoke_and_ack |= resend_raa;
self.monitor_pending_commitment_signed |= resend_commitment;
self.monitor_pending_forwards.append(&mut pending_forwards);
self.monitor_pending_failures.append(&mut pending_fails);
+ self.monitor_pending_finalized_fulfills.append(&mut pending_finalized_claimed_htlcs);
self.channel_state |= ChannelState::MonitorUpdateFailed as u32;
}
/// Indicates that the latest ChannelMonitor update has been committed by the client
/// successfully and we should restore normal operation. Returns messages which should be sent
/// to the remote side.
- pub fn monitor_updating_restored<L: Deref>(&mut self, logger: &L) -> (Option<msgs::RevokeAndACK>, Option<msgs::CommitmentUpdate>, RAACommitmentOrder, Vec<(PendingHTLCInfo, u64)>, Vec<(HTLCSource, PaymentHash, HTLCFailReason)>, Option<Transaction>, Option<msgs::FundingLocked>) where L::Target: Logger {
+ pub fn monitor_updating_restored<L: Deref>(&mut self, logger: &L) -> MonitorRestoreUpdates where L::Target: Logger {
assert_eq!(self.channel_state & ChannelState::MonitorUpdateFailed as u32, ChannelState::MonitorUpdateFailed as u32);
self.channel_state &= !(ChannelState::MonitorUpdateFailed as u32);
})
} else { None };
- let mut forwards = Vec::new();
- mem::swap(&mut forwards, &mut self.monitor_pending_forwards);
- let mut failures = Vec::new();
- mem::swap(&mut failures, &mut self.monitor_pending_failures);
+ let mut accepted_htlcs = Vec::new();
+ mem::swap(&mut accepted_htlcs, &mut self.monitor_pending_forwards);
+ let mut failed_htlcs = Vec::new();
+ mem::swap(&mut failed_htlcs, &mut self.monitor_pending_failures);
+ let mut finalized_claimed_htlcs = Vec::new();
+ mem::swap(&mut finalized_claimed_htlcs, &mut self.monitor_pending_finalized_fulfills);
if self.channel_state & (ChannelState::PeerDisconnected as u32) != 0 {
self.monitor_pending_revoke_and_ack = false;
self.monitor_pending_commitment_signed = false;
- return (None, None, RAACommitmentOrder::RevokeAndACKFirst, forwards, failures, funding_broadcastable, funding_locked);
+ return MonitorRestoreUpdates {
+ raa: None, commitment_update: None, order: RAACommitmentOrder::RevokeAndACKFirst,
+ accepted_htlcs, failed_htlcs, finalized_claimed_htlcs, funding_broadcastable, funding_locked
+ };
}
let raa = if self.monitor_pending_revoke_and_ack {
log_bytes!(self.channel_id()), if funding_broadcastable.is_some() { "a funding broadcastable, " } else { "" },
if commitment_update.is_some() { "a" } else { "no" }, if raa.is_some() { "an" } else { "no" },
match order { RAACommitmentOrder::CommitmentFirst => "commitment", RAACommitmentOrder::RevokeAndACKFirst => "RAA"});
- (raa, commitment_update, order, forwards, failures, funding_broadcastable, funding_locked)
+ MonitorRestoreUpdates {
+ raa, commitment_update, order, accepted_htlcs, failed_htlcs, finalized_claimed_htlcs, funding_broadcastable, funding_locked
+ }
}
pub fn update_fee<F: Deref>(&mut self, fee_estimator: &F, msg: &msgs::UpdateFee) -> Result<(), ChannelError>
return Err(ChannelError::Close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
}
Channel::<Signer>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
- let feerate_over_dust_buffer = msg.feerate_per_kw > self.get_dust_buffer_feerate();
+ let feerate_over_dust_buffer = msg.feerate_per_kw > self.get_dust_buffer_feerate(None);
self.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced));
self.update_time_counter += 1;
// `get_dust_buffer_feerate` considers the `pending_update_fee` status), check that we
// won't be pushed over our dust exposure limit by the feerate increase.
if feerate_over_dust_buffer {
- let inbound_stats = self.get_inbound_pending_htlc_stats();
- let outbound_stats = self.get_outbound_pending_htlc_stats();
+ let inbound_stats = self.get_inbound_pending_htlc_stats(None);
+ let outbound_stats = self.get_outbound_pending_htlc_stats(None);
let holder_tx_dust_exposure = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat;
let counterparty_tx_dust_exposure = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat;
if holder_tx_dust_exposure > self.get_max_dust_htlc_exposure_msat() {
// channel might have been used to route very small values (either by honest users or as DoS).
self.channel_value_satoshis * 1000 * 9 / 10,
- Channel::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
+ self.holder_max_htlc_value_in_flight_msat
);
}
self.feerate_per_kw
}
- pub fn get_dust_buffer_feerate(&self) -> u32 {
+ pub fn get_dust_buffer_feerate(&self, outbound_feerate_update: Option<u32>) -> u32 {
// When calculating our exposure to dust HTLCs, we assume that the channel feerate
// may, at any point, increase by at least 10 sat/vB (i.e 2530 sat/kWU) or 25%,
// whichever is higher. This ensures that we aren't suddenly exposed to significantly
if let Some((feerate, _)) = self.pending_update_fee {
feerate_per_kw = cmp::max(feerate_per_kw, feerate);
}
+ if let Some(feerate) = outbound_feerate_update {
+ feerate_per_kw = cmp::max(feerate_per_kw, feerate);
+ }
cmp::max(2530, feerate_per_kw * 1250 / 1000)
}
/// In the first case, we store the confirmation height and calculating the short channel id.
/// In the second, we simply return an Err indicating we need to be force-closed now.
pub fn transactions_confirmed<L: Deref>(&mut self, block_hash: &BlockHash, height: u32, txdata: &TransactionData, logger: &L)
- -> Result<Option<msgs::FundingLocked>, msgs::ErrorMessage> where L::Target: Logger {
+ -> Result<Option<msgs::FundingLocked>, ClosureReason> where L::Target: Logger {
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
for &(index_in_block, tx) in txdata.iter() {
if let Some(funding_txo) = self.get_funding_txo() {
panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
}
self.update_time_counter += 1;
- return Err(msgs::ErrorMessage {
- channel_id: self.channel_id(),
- data: "funding tx had wrong script/value or output index".to_owned()
- });
+ let err_reason = "funding tx had wrong script/value or output index";
+ return Err(ClosureReason::ProcessingError { err: err_reason.to_owned() });
} else {
if self.is_outbound() {
for input in tx.input.iter() {
for inp in tx.input.iter() {
if inp.previous_output == funding_txo.into_bitcoin_outpoint() {
log_info!(logger, "Detected channel-closing tx {} spending {}:{}, closing channel {}", tx.txid(), inp.previous_output.txid, inp.previous_output.vout, log_bytes!(self.channel_id()));
- return Err(msgs::ErrorMessage {
- channel_id: self.channel_id(),
- data: "Commitment or closing transaction was confirmed on chain.".to_owned()
- });
+ return Err(ClosureReason::CommitmentTxConfirmed);
}
}
}
/// May return some HTLCs (and their payment_hash) which have timed out and should be failed
/// back.
pub fn best_block_updated<L: Deref>(&mut self, height: u32, highest_header_time: u32, logger: &L)
- -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> where L::Target: Logger {
+ -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), ClosureReason> where L::Target: Logger {
let mut timed_out_htlcs = Vec::new();
- let unforwarded_htlc_cltv_limit = height + HTLC_FAIL_BACK_BUFFER;
+ // This mirrors the check in ChannelManager::decode_update_add_htlc_onion, refusing to
+ // forward an HTLC when our counterparty should almost certainly just fail it for expiring
+ // ~now.
+ let unforwarded_htlc_cltv_limit = height + LATENCY_GRACE_PERIOD_BLOCKS;
self.holding_cell_htlc_updates.retain(|htlc_update| {
match htlc_update {
&HTLCUpdateAwaitingACK::AddHTLC { ref payment_hash, ref source, ref cltv_expiry, .. } => {
// close the channel and hope we can get the latest state on chain (because presumably
// the funding transaction is at least still in the mempool of most nodes).
if funding_tx_confirmations < self.minimum_depth.unwrap() as i64 / 2 {
- return Err(msgs::ErrorMessage {
- channel_id: self.channel_id(),
- data: format!("Funding transaction was un-confirmed. Locked at {} confs, now have {} confs.", self.minimum_depth.unwrap(), funding_tx_confirmations),
- });
+ let err_reason = format!("Funding transaction was un-confirmed. Locked at {} confs, now have {} confs.",
+ self.minimum_depth.unwrap(), funding_tx_confirmations);
+ return Err(ClosureReason::ProcessingError { err: err_reason });
}
+ } else if !self.is_outbound() && self.funding_tx_confirmed_in.is_none() &&
+ height >= self.channel_creation_height + FUNDING_CONF_DEADLINE_BLOCKS {
+ log_info!(logger, "Closing channel {} due to funding timeout", log_bytes!(self.channel_id));
+ // If funding_tx_confirmed_in is unset, the channel must not be active
+ assert!(non_shutdown_state <= ChannelState::ChannelFunded as u32);
+ assert_eq!(non_shutdown_state & ChannelState::OurFundingLocked as u32, 0);
+ return Err(ClosureReason::FundingTimedOut);
}
Ok((None, timed_out_htlcs))
/// Indicates the funding transaction is no longer confirmed in the main chain. This may
/// force-close the channel, but may also indicate a harmless reorganization of a block or two
/// before the channel has reached funding_locked and we can just wait for more blocks.
- pub fn funding_transaction_unconfirmed<L: Deref>(&mut self, logger: &L) -> Result<(), msgs::ErrorMessage> where L::Target: Logger {
+ pub fn funding_transaction_unconfirmed<L: Deref>(&mut self, logger: &L) -> Result<(), ClosureReason> where L::Target: Logger {
if self.funding_tx_confirmation_height != 0 {
// We handle the funding disconnection by calling best_block_updated with a height one
// below where our funding was connected, implying a reorg back to conf_height - 1.
funding_satoshis: self.channel_value_satoshis,
push_msat: self.channel_value_satoshis * 1000 - self.value_to_self_msat,
dust_limit_satoshis: self.holder_dust_limit_satoshis,
- max_htlc_value_in_flight_msat: Channel::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis),
- channel_reserve_satoshis: Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis),
+ max_htlc_value_in_flight_msat: self.holder_max_htlc_value_in_flight_msat,
+ channel_reserve_satoshis: self.holder_selected_channel_reserve_satoshis,
htlc_minimum_msat: self.holder_htlc_minimum_msat,
feerate_per_kw: self.feerate_per_kw as u32,
to_self_delay: self.get_holder_selected_contest_delay(),
Some(script) => script.clone().into_inner(),
None => Builder::new().into_script(),
}),
+ channel_type: Some(self.channel_type.clone()),
}
}
msgs::AcceptChannel {
temporary_channel_id: self.channel_id,
dust_limit_satoshis: self.holder_dust_limit_satoshis,
- max_htlc_value_in_flight_msat: Channel::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis),
- channel_reserve_satoshis: Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis),
+ max_htlc_value_in_flight_msat: self.holder_max_htlc_value_in_flight_msat,
+ channel_reserve_satoshis: self.holder_selected_channel_reserve_satoshis,
htlc_minimum_msat: self.holder_htlc_minimum_msat,
minimum_depth: self.minimum_depth.unwrap(),
to_self_delay: self.get_holder_selected_contest_delay(),
/// 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.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).0;
+ let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
Ok(self.holder_signer.sign_counterparty_commitment(&counterparty_initial_commitment_tx, &self.secp_ctx)
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?.0)
}
/// You MUST call send_commitment prior to calling any other methods on this Channel!
///
/// If an Err is returned, it's a ChannelError::Ignore!
- pub fn send_htlc(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket) -> Result<Option<msgs::UpdateAddHTLC>, ChannelError> {
+ pub fn send_htlc<L: Deref>(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket, logger: &L) -> Result<Option<msgs::UpdateAddHTLC>, ChannelError> where L::Target: Logger {
if (self.channel_state & (ChannelState::ChannelFunded as u32 | BOTH_SIDES_SHUTDOWN_MASK)) != (ChannelState::ChannelFunded as u32) {
return Err(ChannelError::Ignore("Cannot send HTLC until channel is fully established and we haven't started shutting down".to_owned()));
}
return Err(ChannelError::Ignore("Cannot send an HTLC while disconnected from channel counterparty".to_owned()));
}
- let inbound_stats = self.get_inbound_pending_htlc_stats();
- let outbound_stats = self.get_outbound_pending_htlc_stats();
+ let inbound_stats = self.get_inbound_pending_htlc_stats(None);
+ let outbound_stats = self.get_outbound_pending_htlc_stats(None);
if outbound_stats.pending_htlcs + 1 > self.counterparty_max_accepted_htlcs as u32 {
return Err(ChannelError::Ignore(format!("Cannot push more than their max accepted HTLCs ({})", self.counterparty_max_accepted_htlcs)));
}
return Err(ChannelError::Ignore(format!("Cannot send value that would put us over the max HTLC value in flight our peer will accept ({})", self.counterparty_max_htlc_value_in_flight_msat)));
}
+ let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number)?;
+ let commitment_stats = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, true, logger);
if !self.is_outbound() {
// Check that we won't violate the remote channel reserve by adding this HTLC.
- let counterparty_balance_msat = self.channel_value_satoshis * 1000 - self.value_to_self_msat;
- let holder_selected_chan_reserve_msat = Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) * 1000;
let htlc_candidate = HTLCCandidate::new(amount_msat, HTLCInitiator::LocalOffered);
let counterparty_commit_tx_fee_msat = self.next_remote_commit_tx_fee_msat(htlc_candidate, None);
- if counterparty_balance_msat < holder_selected_chan_reserve_msat + counterparty_commit_tx_fee_msat {
+ let holder_selected_chan_reserve_msat = self.holder_selected_channel_reserve_satoshis * 1000;
+ if commitment_stats.remote_balance_msat < counterparty_commit_tx_fee_msat + holder_selected_chan_reserve_msat {
return Err(ChannelError::Ignore("Cannot send value that would put counterparty balance under holder-announced channel reserve value".to_owned()));
}
}
- let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
+ let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
if amount_msat / 1000 < exposure_dust_limit_success_sats {
let on_counterparty_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat + amount_msat;
if on_counterparty_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
}
}
- let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
+ let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
if amount_msat / 1000 < exposure_dust_limit_timeout_sats {
let on_holder_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat + amount_msat;
if on_holder_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
}
}
- let pending_value_to_self_msat = self.value_to_self_msat - outbound_stats.pending_htlcs_value_msat;
- if pending_value_to_self_msat < amount_msat {
- return Err(ChannelError::Ignore(format!("Cannot send value that would overdraw remaining funds. Amount: {}, pending value to self {}", amount_msat, pending_value_to_self_msat)));
+ let holder_balance_msat = commitment_stats.local_balance_msat - outbound_stats.holding_cell_msat;
+ if holder_balance_msat < amount_msat {
+ return Err(ChannelError::Ignore(format!("Cannot send value that would overdraw remaining funds. Amount: {}, pending value to self {}", amount_msat, holder_balance_msat)));
}
// `2 *` and extra HTLC are for the fee spike buffer.
let htlc_candidate = HTLCCandidate::new(amount_msat, HTLCInitiator::LocalOffered);
FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * self.next_local_commit_tx_fee_msat(htlc_candidate, Some(()))
} else { 0 };
- if pending_value_to_self_msat - amount_msat < commit_tx_fee_msat {
- return Err(ChannelError::Ignore(format!("Cannot send value that would not leave enough to pay for fees. Pending value to self: {}. local_commit_tx_fee {}", pending_value_to_self_msat, commit_tx_fee_msat)));
+ if holder_balance_msat - amount_msat < commit_tx_fee_msat {
+ return Err(ChannelError::Ignore(format!("Cannot send value that would not leave enough to pay for fees. Pending value to self: {}. local_commit_tx_fee {}", holder_balance_msat, commit_tx_fee_msat)));
}
// Check self.counterparty_selected_channel_reserve_satoshis (the amount we must keep as
// reserve for the remote to have something to claim if we misbehave)
let chan_reserve_msat = self.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000;
- if pending_value_to_self_msat - amount_msat - commit_tx_fee_msat < chan_reserve_msat {
+ if holder_balance_msat - amount_msat - commit_tx_fee_msat < chan_reserve_msat {
return Err(ChannelError::Ignore(format!("Cannot send value that would put our balance under counterparty-announced channel reserve value ({})", chan_reserve_msat)));
}
/// when we shouldn't change HTLC/channel state.
fn send_commitment_no_state_update<L: Deref>(&self, logger: &L) -> Result<(msgs::CommitmentSigned, (Txid, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>)), ChannelError> where L::Target: Logger {
let counterparty_keys = self.build_remote_transaction_keys()?;
- let counterparty_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, true, logger);
- let feerate_per_kw = counterparty_commitment_tx.1;
- let counterparty_commitment_txid = counterparty_commitment_tx.0.trust().txid();
+ let commitment_stats = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, true, logger);
+ let counterparty_commitment_txid = commitment_stats.tx.trust().txid();
let (signature, htlc_signatures);
#[cfg(any(test, feature = "fuzztarget"))]
&& info.next_holder_htlc_id == self.next_holder_htlc_id
&& info.next_counterparty_htlc_id == self.next_counterparty_htlc_id
&& info.feerate == self.feerate_per_kw {
- let actual_fee = self.commit_tx_fee_msat(counterparty_commitment_tx.2);
+ let actual_fee = Self::commit_tx_fee_msat(self.feerate_per_kw, commitment_stats.num_nondust_htlcs);
assert_eq!(actual_fee, info.fee);
}
}
}
{
- let mut htlcs = Vec::with_capacity(counterparty_commitment_tx.3.len());
- for &(ref htlc, _) in counterparty_commitment_tx.3.iter() {
+ let mut htlcs = Vec::with_capacity(commitment_stats.htlcs_included.len());
+ for &(ref htlc, _) in commitment_stats.htlcs_included.iter() {
htlcs.push(htlc);
}
- let res = self.holder_signer.sign_counterparty_commitment(&counterparty_commitment_tx.0, &self.secp_ctx)
+ let res = self.holder_signer.sign_counterparty_commitment(&commitment_stats.tx, &self.secp_ctx)
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?;
signature = res.0;
htlc_signatures = res.1;
log_trace!(logger, "Signed remote commitment tx {} (txid {}) with redeemscript {} -> {} in channel {}",
- encode::serialize_hex(&counterparty_commitment_tx.0.trust().built_transaction().transaction),
+ encode::serialize_hex(&commitment_stats.tx.trust().built_transaction().transaction),
&counterparty_commitment_txid, encode::serialize_hex(&self.get_funding_redeemscript()),
log_bytes!(signature.serialize_compact()[..]), log_bytes!(self.channel_id()));
for (ref htlc_sig, ref htlc) in htlc_signatures.iter().zip(htlcs) {
log_trace!(logger, "Signed remote HTLC tx {} with redeemscript {} with pubkey {} -> {} in channel {}",
- encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, feerate_per_kw, self.get_holder_selected_contest_delay(), htlc, &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)),
- encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, &counterparty_keys)),
+ encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, commitment_stats.feerate_per_kw, self.get_holder_selected_contest_delay(), htlc, self.opt_anchors(), &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)),
+ encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &counterparty_keys)),
log_bytes!(counterparty_keys.broadcaster_htlc_key.serialize()),
log_bytes!(htlc_sig.serialize_compact()[..]), log_bytes!(self.channel_id()));
}
channel_id: self.channel_id,
signature,
htlc_signatures,
- }, (counterparty_commitment_txid, counterparty_commitment_tx.3)))
+ }, (counterparty_commitment_txid, commitment_stats.htlcs_included)))
}
/// Adds a pending outbound HTLC to this channel, and creates a signed commitment transaction
/// Shorthand for calling send_htlc() followed by send_commitment(), see docs on those for
/// more info.
pub fn send_htlc_and_commit<L: Deref>(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket, logger: &L) -> Result<Option<(msgs::UpdateAddHTLC, msgs::CommitmentSigned, ChannelMonitorUpdate)>, ChannelError> where L::Target: Logger {
- match self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet)? {
+ match self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, logger)? {
Some(update_add_htlc) => {
let (commitment_signed, monitor_update) = self.send_commitment_no_status_check(logger)?;
Ok(Some((update_add_htlc, commitment_signed, monitor_update)))
htlc.write(writer)?;
}
+ // If the channel type is something other than only-static-remote-key, then we need to have
+ // older clients fail to deserialize this channel at all. If the type is
+ // only-static-remote-key, we simply consider it "default" and don't write the channel type
+ // out at all.
+ let chan_type = if self.channel_type != ChannelTypeFeatures::only_static_remote_key() {
+ Some(&self.channel_type) } else { None };
+
+ // The same logic applies for `holder_selected_channel_reserve_satoshis` and
+ // `holder_max_htlc_value_in_flight_msat` values other than the defaults.
+ let serialized_holder_selected_reserve =
+ if self.holder_selected_channel_reserve_satoshis != Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis)
+ { Some(self.holder_selected_channel_reserve_satoshis) } else { None };
+ let serialized_holder_htlc_max_in_flight =
+ if self.holder_max_htlc_value_in_flight_msat != Self::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
+ { Some(self.holder_max_htlc_value_in_flight_msat) } else { None };
+
write_tlv_fields!(writer, {
(0, self.announcement_sigs, option),
// minimum_depth and counterparty_selected_channel_reserve_satoshis used to have a
// and new versions map the default values to None and allow the TLV entries here to
// override that.
(1, self.minimum_depth, option),
+ (2, chan_type, option),
(3, self.counterparty_selected_channel_reserve_satoshis, option),
+ (4, serialized_holder_selected_reserve, option),
(5, self.config, required),
+ (6, serialized_holder_htlc_max_in_flight, option),
(7, self.shutdown_scriptpubkey, option),
(9, self.target_closing_feerate_sats_per_kw, option),
+ (11, self.monitor_pending_finalized_fulfills, vec_type),
+ (13, self.channel_creation_height, required),
});
Ok(())
}
const MAX_ALLOC_SIZE: usize = 64*1024;
-impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer>
+impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
where K::Target: KeysInterface<Signer = Signer> {
- fn read<R : io::Read>(reader: &mut R, keys_source: &'a K) -> Result<Self, DecodeError> {
+ fn read<R : io::Read>(reader: &mut R, args: (&'a K, u32)) -> Result<Self, DecodeError> {
+ let (keys_source, serialized_height) = args;
let ver = read_ver_prefix!(reader, SERIALIZATION_VERSION);
let user_id = Readable::read(reader)?;
let mut announcement_sigs = None;
let mut target_closing_feerate_sats_per_kw = None;
+ let mut monitor_pending_finalized_fulfills = Some(Vec::new());
+ let mut holder_selected_channel_reserve_satoshis = Some(Self::get_holder_selected_channel_reserve_satoshis(channel_value_satoshis));
+ let mut holder_max_htlc_value_in_flight_msat = Some(Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis));
+ // Prior to supporting channel type negotiation, all of our channels were static_remotekey
+ // only, so we default to that if none was written.
+ let mut channel_type = Some(ChannelTypeFeatures::only_static_remote_key());
+ let mut channel_creation_height = Some(serialized_height);
read_tlv_fields!(reader, {
(0, announcement_sigs, option),
(1, minimum_depth, option),
+ (2, channel_type, option),
(3, counterparty_selected_channel_reserve_satoshis, option),
+ (4, holder_selected_channel_reserve_satoshis, option),
(5, config, option), // Note that if none is provided we will *not* overwrite the existing one.
+ (6, holder_max_htlc_value_in_flight_msat, option),
(7, shutdown_scriptpubkey, option),
(9, target_closing_feerate_sats_per_kw, option),
+ (11, monitor_pending_finalized_fulfills, vec_type),
+ (13, channel_creation_height, option),
});
+ let chan_features = channel_type.as_ref().unwrap();
+ if chan_features.supports_unknown_bits() || chan_features.requires_unknown_bits() {
+ // If the channel was written by a new version and negotiated with features we don't
+ // understand yet, refuse to read it.
+ return Err(DecodeError::UnknownRequiredFeature);
+ }
+
+ if channel_parameters.opt_anchors.is_some() {
+ // Relax this check when ChannelTypeFeatures supports anchors.
+ return Err(DecodeError::InvalidValue);
+ }
+
let mut secp_ctx = Secp256k1::new();
secp_ctx.seeded_randomize(&keys_source.get_secure_random_bytes());
monitor_pending_commitment_signed,
monitor_pending_forwards,
monitor_pending_failures,
+ monitor_pending_finalized_fulfills: monitor_pending_finalized_fulfills.unwrap(),
pending_update_fee,
holding_cell_update_fee,
funding_tx_confirmed_in,
funding_tx_confirmation_height,
short_channel_id,
+ channel_creation_height: channel_creation_height.unwrap(),
counterparty_dust_limit_satoshis,
holder_dust_limit_satoshis,
counterparty_max_htlc_value_in_flight_msat,
+ holder_max_htlc_value_in_flight_msat: holder_max_htlc_value_in_flight_msat.unwrap(),
counterparty_selected_channel_reserve_satoshis,
+ holder_selected_channel_reserve_satoshis: holder_selected_channel_reserve_satoshis.unwrap(),
counterparty_htlc_minimum_msat,
holder_htlc_minimum_msat,
counterparty_max_accepted_htlcs,
#[cfg(any(test, feature = "fuzztarget"))]
historical_inbound_htlc_fulfills,
+
+ channel_type: channel_type.unwrap(),
})
}
}
let secp_ctx = Secp256k1::new();
let node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let config = UserConfig::default();
- match Channel::<EnforcingSigner>::new_outbound(&&fee_estimator, &&keys_provider, node_id, &features, 10000000, 100000, 42, &config) {
+ match Channel::<EnforcingSigner>::new_outbound(&&fee_estimator, &&keys_provider, node_id, &features, 10000000, 100000, 42, &config, 0) {
Err(APIError::IncompatibleShutdownScript { script }) => {
assert_eq!(script.into_inner(), non_v0_segwit_shutdown_script.into_inner());
},
let node_a_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let config = UserConfig::default();
- let node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&fee_est, &&keys_provider, node_a_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config).unwrap();
+ let node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&fee_est, &&keys_provider, node_a_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap();
// Now change the fee so we can check that the fee in the open_channel message is the
// same as the old fee.
let seed = [42; 32];
let network = Network::Testnet;
let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
+ let logger = test_utils::TestLogger::new();
// Go through the flow of opening a channel between two nodes, making sure
// they have different dust limits.
// Create Node A's channel pointing to Node B's pubkey
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let config = UserConfig::default();
- let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config).unwrap();
+ let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap();
// Create Node B's channel by receiving Node A's open_channel message
// Make sure A's dust limit is as we expect.
let open_channel_msg = node_a_chan.get_open_channel(genesis_block(network).header.block_hash());
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
- let node_b_chan = Channel::<EnforcingSigner>::new_from_req(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config).unwrap();
+ let node_b_chan = Channel::<EnforcingSigner>::new_from_req(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger).unwrap();
// Node B --> Node A: accept channel, explicitly setting B's dust limit.
let mut accept_channel_msg = node_b_chan.get_accept_channel();
session_priv: SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
first_hop_htlc_msat: 548,
payment_id: PaymentId([42; 32]),
+ payment_secret: None,
+ payee: None,
}
});
// the dust limit check.
let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered);
let local_commit_tx_fee = node_a_chan.next_local_commit_tx_fee_msat(htlc_candidate, None);
- let local_commit_fee_0_htlcs = node_a_chan.commit_tx_fee_msat(0);
+ let local_commit_fee_0_htlcs = Channel::<EnforcingSigner>::commit_tx_fee_msat(node_a_chan.feerate_per_kw, 0);
assert_eq!(local_commit_tx_fee, local_commit_fee_0_htlcs);
// Finally, make sure that when Node A calculates the remote's commitment transaction fees, all
// of the HTLCs are seen to be above the dust limit.
node_a_chan.channel_transaction_parameters.is_outbound_from_holder = false;
- let remote_commit_fee_3_htlcs = node_a_chan.commit_tx_fee_msat(3);
+ let remote_commit_fee_3_htlcs = Channel::<EnforcingSigner>::commit_tx_fee_msat(node_a_chan.feerate_per_kw, 3);
let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered);
let remote_commit_tx_fee = node_a_chan.next_remote_commit_tx_fee_msat(htlc_candidate, None);
assert_eq!(remote_commit_tx_fee, remote_commit_fee_3_htlcs);
let node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let config = UserConfig::default();
- let mut chan = Channel::<EnforcingSigner>::new_outbound(&&fee_est, &&keys_provider, node_id, &InitFeatures::known(), 10000000, 100000, 42, &config).unwrap();
+ let mut chan = Channel::<EnforcingSigner>::new_outbound(&&fee_est, &&keys_provider, node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap();
- let commitment_tx_fee_0_htlcs = chan.commit_tx_fee_msat(0);
- let commitment_tx_fee_1_htlc = chan.commit_tx_fee_msat(1);
+ let commitment_tx_fee_0_htlcs = Channel::<EnforcingSigner>::commit_tx_fee_msat(chan.feerate_per_kw, 0);
+ let commitment_tx_fee_1_htlc = Channel::<EnforcingSigner>::commit_tx_fee_msat(chan.feerate_per_kw, 1);
// If HTLC_SUCCESS_TX_WEIGHT and HTLC_TIMEOUT_TX_WEIGHT were swapped: then this HTLC would be
// counted as dust when it shouldn't be.
// Create Node A's channel pointing to Node B's pubkey
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let config = UserConfig::default();
- let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config).unwrap();
+ let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap();
// Create Node B's channel by receiving Node A's open_channel message
let open_channel_msg = node_a_chan.get_open_channel(chain_hash);
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
- let mut node_b_chan = Channel::<EnforcingSigner>::new_from_req(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config).unwrap();
+ let mut node_b_chan = Channel::<EnforcingSigner>::new_from_req(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger).unwrap();
// Node B --> Node A: accept channel
let accept_channel_msg = node_b_chan.get_accept_channel();
// Create a channel.
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let config = UserConfig::default();
- let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config).unwrap();
+ let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap();
assert!(node_a_chan.counterparty_forwarding_info.is_none());
assert_eq!(node_a_chan.holder_htlc_minimum_msat, 1); // the default
assert!(node_a_chan.counterparty_forwarding_info().is_none());
let counterparty_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let mut config = UserConfig::default();
config.channel_options.announced_channel = false;
- let mut chan = Channel::<InMemorySigner>::new_outbound(&&feeest, &&keys_provider, counterparty_node_id, &InitFeatures::known(), 10_000_000, 100000, 42, &config).unwrap(); // Nothing uses their network key in this test
+ let mut chan = Channel::<InMemorySigner>::new_outbound(&&feeest, &&keys_provider, counterparty_node_id, &InitFeatures::known(), 10_000_000, 100000, 42, &config, 0).unwrap(); // Nothing uses their network key in this test
chan.holder_dust_limit_satoshis = 546;
chan.counterparty_selected_channel_reserve_satoshis = Some(0); // Filled in in accept_channel
$( { $htlc_idx: expr, $counterparty_htlc_sig_hex: expr, $htlc_sig_hex: expr, $htlc_tx_hex: expr } ), *
} ) => { {
let (commitment_tx, htlcs): (_, Vec<HTLCOutputInCommitment>) = {
- let mut res = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, &logger);
+ let mut commitment_stats = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, &logger);
- let htlcs = res.3.drain(..)
+ let htlcs = commitment_stats.htlcs_included.drain(..)
.filter_map(|(htlc, _)| if htlc.transaction_output_index.is_some() { Some(htlc) } else { None })
.collect();
- (res.0, htlcs)
+ (commitment_stats.tx, htlcs)
};
let trusted_tx = commitment_tx.trust();
let unsigned_tx = trusted_tx.built_transaction();
let remote_signature = Signature::from_der(&hex::decode($counterparty_htlc_sig_hex).unwrap()[..]).unwrap();
let ref htlc = htlcs[$htlc_idx];
+ let opt_anchors = false;
let htlc_tx = chan_utils::build_htlc_transaction(&unsigned_tx.txid, chan.feerate_per_kw,
chan.get_counterparty_selected_contest_delay().unwrap(),
- &htlc, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
- let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
+ &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_sighash = Message::from_slice(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, SigHashType::All)[..]).unwrap();
secp_ctx.verify(&htlc_sighash, &remote_signature, &keys.countersignatory_htlc_key).unwrap();