use crate::ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment};
use crate::ln::chan_utils;
use crate::ln::msgs::DecodeError;
-use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
+use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT, compute_feerate_sat_per_1000_weight, FEERATE_FLOOR_SATS_PER_KW};
use crate::sign::WriteableEcdsaChannelSigner;
use crate::chain::onchaintx::{ExternalHTLCClaim, OnchainTxHandler};
use crate::util::logger::Logger;
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct HolderFundingOutput {
funding_redeemscript: Script,
- funding_amount: Option<u64>,
+ pub(crate) funding_amount: Option<u64>,
channel_type_features: ChannelTypeFeatures,
}
_ => { mem::discriminant(self) == mem::discriminant(&input) }
}
}
+ fn as_tx_input(&self, previous_output: BitcoinOutPoint) -> TxIn {
+ let sequence = match self {
+ PackageSolvingData::RevokedOutput(_) => Sequence::ENABLE_RBF_NO_LOCKTIME,
+ PackageSolvingData::RevokedHTLCOutput(_) => Sequence::ENABLE_RBF_NO_LOCKTIME,
+ PackageSolvingData::CounterpartyOfferedHTLCOutput(outp) => if outp.channel_type_features.supports_anchors_zero_fee_htlc_tx() {
+ Sequence::from_consensus(1)
+ } else {
+ Sequence::ENABLE_RBF_NO_LOCKTIME
+ },
+ PackageSolvingData::CounterpartyReceivedHTLCOutput(outp) => if outp.channel_type_features.supports_anchors_zero_fee_htlc_tx() {
+ Sequence::from_consensus(1)
+ } else {
+ Sequence::ENABLE_RBF_NO_LOCKTIME
+ },
+ _ => {
+ debug_assert!(false, "This should not be reachable by 'untractable' or 'malleable with external funding' packages");
+ Sequence::ENABLE_RBF_NO_LOCKTIME
+ },
+ };
+ TxIn {
+ previous_output,
+ script_sig: Script::new(),
+ sequence,
+ witness: Witness::new(),
+ }
+ }
fn finalize_input<Signer: WriteableEcdsaChannelSigner>(&self, bumped_tx: &mut Transaction, i: usize, onchain_handler: &mut OnchainTxHandler<Signer>) -> bool {
match self {
PackageSolvingData::RevokedOutput(ref outp) => {
value,
}],
};
- for (outpoint, _) in self.inputs.iter() {
- bumped_tx.input.push(TxIn {
- previous_output: *outpoint,
- script_sig: Script::new(),
- sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
- witness: Witness::new(),
- });
+ for (outpoint, outp) in self.inputs.iter() {
+ bumped_tx.input.push(outp.as_tx_input(*outpoint));
}
for (i, (outpoint, out)) in self.inputs.iter().enumerate() {
log_debug!(logger, "Adding claiming input for outpoint {}:{}", outpoint.txid, outpoint.vout);
) -> u32 where F::Target: FeeEstimator {
let feerate_estimate = fee_estimator.bounded_sat_per_1000_weight(conf_target);
if self.feerate_previous != 0 {
- // If old feerate inferior to actual one given back by Fee Estimator, use it to compute new fee...
+ // Use the new fee estimate if it's higher than the one previously used.
if feerate_estimate as u64 > self.feerate_previous {
feerate_estimate
} else if !force_feerate_bump {
self.feerate_previous.try_into().unwrap_or(u32::max_value())
} else {
- // ...else just increase the previous feerate by 25% (because that's a nice number)
- (self.feerate_previous + (self.feerate_previous / 4)).try_into().unwrap_or(u32::max_value())
+ // Our fee estimate has decreased, but our transaction remains unconfirmed after
+ // using our previous fee estimate. This may point to an unreliable fee estimator,
+ // so we choose to bump our previous feerate by 25%, making sure we don't use a
+ // lower feerate or overpay by a large margin by limiting it to 5x the new fee
+ // estimate.
+ let previous_feerate = self.feerate_previous.try_into().unwrap_or(u32::max_value());
+ let mut new_feerate = previous_feerate.saturating_add(previous_feerate / 4);
+ if new_feerate > feerate_estimate * 5 {
+ new_feerate = cmp::max(feerate_estimate * 5, previous_feerate);
+ }
+ new_feerate
}
} else {
feerate_estimate
}
/// Attempt to propose a bumping fee for a transaction from its spent output's values and predicted
-/// weight. We start with the highest priority feerate returned by the node's fee estimator then
-/// fall-back to lower priorities until we have enough value available to suck from.
+/// weight. We first try our [`OnChainSweep`] feerate, if it's not enough we try to sweep half of
+/// the input amounts.
///
/// If the proposed fee is less than the available spent output's values, we return the proposed
-/// fee and the corresponding updated feerate. If the proposed fee is equal or more than the
-/// available spent output's values, we return nothing
+/// fee and the corresponding updated feerate. If fee is under [`FEERATE_FLOOR_SATS_PER_KW`], we
+/// return nothing.
+///
+/// [`OnChainSweep`]: crate::chain::chaininterface::ConfirmationTarget::OnChainSweep
+/// [`FEERATE_FLOOR_SATS_PER_KW`]: crate::chain::chaininterface::MIN_RELAY_FEE_SAT_PER_1000_WEIGHT
fn compute_fee_from_spent_amounts<F: Deref, L: Deref>(input_amounts: u64, predicted_weight: usize, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L) -> Option<(u64, u64)>
where F::Target: FeeEstimator,
L::Target: Logger,
{
- let mut updated_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64;
- let mut fee = updated_feerate * (predicted_weight as u64) / 1000;
- if input_amounts <= fee {
- updated_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal) as u64;
- fee = updated_feerate * (predicted_weight as u64) / 1000;
- if input_amounts <= fee {
- updated_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Background) as u64;
- fee = updated_feerate * (predicted_weight as u64) / 1000;
- if input_amounts <= fee {
- log_error!(logger, "Failed to generate an on-chain punishment tx as even low priority fee ({} sat) was more than the entire claim balance ({} sat)",
- fee, input_amounts);
- None
- } else {
- log_warn!(logger, "Used low priority fee for on-chain punishment tx as high priority fee was more than the entire claim balance ({} sat)",
- input_amounts);
- Some((fee, updated_feerate))
- }
- } else {
- log_warn!(logger, "Used medium priority fee for on-chain punishment tx as high priority fee was more than the entire claim balance ({} sat)",
- input_amounts);
- Some((fee, updated_feerate))
- }
+ let sweep_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::OnChainSweep);
+ let fee_rate = cmp::min(sweep_feerate, compute_feerate_sat_per_1000_weight(input_amounts / 2, predicted_weight as u64)) as u64;
+ let fee = fee_rate * (predicted_weight as u64) / 1000;
+
+ // if the fee rate is below the floor, we don't sweep
+ if fee_rate < FEERATE_FLOOR_SATS_PER_KW as u64 {
+ log_error!(logger, "Failed to generate an on-chain tx with fee ({} sat/kw) was less than the floor ({} sat/kw)",
+ fee_rate, FEERATE_FLOOR_SATS_PER_KW);
+ None
} else {
- Some((fee, updated_feerate))
+ Some((fee, fee_rate))
}
}