Skip to content

Commit f74f0d0

Browse files
author
Antoine Riard
committed
Duplicate fee computation utilities out of OnchainTxHandler
Duplicated code in onchain.rs is removed in next commits.
1 parent f58029f commit f74f0d0

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

lightning/src/ln/package.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment, HTLC_OUTPUT_IN_COMM
2525
use ln::chan_utils;
2626
use ln::msgs::DecodeError;
2727
use ln::onchaintx::OnchainTxHandler;
28+
use chain::chaininterface::{FeeEstimator, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
2829
use chain::keysinterface::Sign;
2930
use util::byte_utils;
3031
use util::logger::Logger;
@@ -792,3 +793,107 @@ pub(crate) fn get_witnesses_weight(inputs: &[InputDescriptors]) -> usize {
792793
}
793794
tx_weight
794795
}
796+
797+
/// Attempt to propose a bumping fee for a transaction from its spent output's values and predicted
798+
/// weight. We start with the highest priority feerate returned by the node's fee estimator then
799+
/// fall-back to lower priorities until we have enough value available to suck from.
800+
///
801+
/// If the proposed fee is less than the available spent output's values, we return the proposed
802+
/// fee and the corresponding updated feerate. If the proposed fee is equal or more than the
803+
/// available spent output's values, we return nothing
804+
fn compute_fee_from_spent_amounts<F: Deref, L: Deref>(input_amounts: u64, predicted_weight: usize, fee_estimator: &F, logger: &L) -> Option<(u64, u64)>
805+
where F::Target: FeeEstimator,
806+
L::Target: Logger,
807+
{
808+
let mut updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64;
809+
let mut fee = updated_feerate * (predicted_weight as u64) / 1000;
810+
if input_amounts <= fee {
811+
updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal) as u64;
812+
fee = updated_feerate * (predicted_weight as u64) / 1000;
813+
if input_amounts <= fee {
814+
updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background) as u64;
815+
fee = updated_feerate * (predicted_weight as u64) / 1000;
816+
if input_amounts <= fee {
817+
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)",
818+
fee, input_amounts);
819+
None
820+
} else {
821+
log_warn!(logger, "Used low priority fee for on-chain punishment tx as high priority fee was more than the entire claim balance ({} sat)",
822+
input_amounts);
823+
Some((fee, updated_feerate))
824+
}
825+
} else {
826+
log_warn!(logger, "Used medium priority fee for on-chain punishment tx as high priority fee was more than the entire claim balance ({} sat)",
827+
input_amounts);
828+
Some((fee, updated_feerate))
829+
}
830+
} else {
831+
Some((fee, updated_feerate))
832+
}
833+
}
834+
835+
/// Attempt to propose a bumping fee for a transaction from its spent output's values and predicted
836+
/// weight. If feerates proposed by the fee-estimator have been increasing since last fee-bumping
837+
/// attempt, use them. Otherwise, blindly bump the feerate by 25% of the previous feerate. We also
838+
/// verify that those bumping heuristics respect BIP125 rules 3) and 4) and if required adjust
839+
/// the new fee to meet the RBF policy requirement.
840+
fn feerate_bump<F: Deref, L: Deref>(predicted_weight: usize, input_amounts: u64, previous_feerate: u64, fee_estimator: &F, logger: &L) -> Option<(u64, u64)>
841+
where F::Target: FeeEstimator,
842+
L::Target: Logger,
843+
{
844+
// If old feerate inferior to actual one given back by Fee Estimator, use it to compute new fee...
845+
let new_fee = if let Some((new_fee, _)) = compute_fee_from_spent_amounts(input_amounts, predicted_weight, fee_estimator, logger) {
846+
let updated_feerate = new_fee / (predicted_weight as u64 * 1000);
847+
if updated_feerate > previous_feerate {
848+
new_fee
849+
} else {
850+
// ...else just increase the previous feerate by 25% (because that's a nice number)
851+
let new_fee = previous_feerate * (predicted_weight as u64) / 750;
852+
if input_amounts <= new_fee {
853+
log_trace!(logger, "Can't 25% bump new claiming tx, amount {} is too small", input_amounts);
854+
return None;
855+
}
856+
new_fee
857+
}
858+
} else {
859+
log_trace!(logger, "Can't new-estimation bump new claiming tx, amount {} is too small", input_amounts);
860+
return None;
861+
};
862+
863+
let previous_fee = previous_feerate * (predicted_weight as u64) / 1000;
864+
let min_relay_fee = MIN_RELAY_FEE_SAT_PER_1000_WEIGHT * (predicted_weight as u64) / 1000;
865+
// BIP 125 Opt-in Full Replace-by-Fee Signaling
866+
// * 3. The replacement transaction pays an absolute fee of at least the sum paid by the original transactions.
867+
// * 4. The replacement transaction must also pay for its own bandwidth at or above the rate set by the node's minimum relay fee setting.
868+
let new_fee = if new_fee < previous_fee + min_relay_fee {
869+
new_fee + previous_fee + min_relay_fee - new_fee
870+
} else {
871+
new_fee
872+
};
873+
Some((new_fee, new_fee * 1000 / (predicted_weight as u64)))
874+
}
875+
876+
/// Deduce a new proposed fee from the claiming transaction output value.
877+
/// If the new proposed fee is superior to the consumed outpoint's value, burn everything in miner's
878+
/// fee to deter counterparties attacker.
879+
pub(crate) fn compute_output_value<F: Deref, L: Deref>(predicted_weight: usize, input_amounts: u64, previous_feerate: u64, fee_estimator: &F, logger: &L) -> Option<(u64, u64)>
880+
where F::Target: FeeEstimator,
881+
L::Target: Logger,
882+
{
883+
// If old feerate is 0, first iteration of this claim, use normal fee calculation
884+
if previous_feerate != 0 {
885+
if let Some((new_fee, feerate)) = feerate_bump(predicted_weight, input_amounts, previous_feerate, fee_estimator, logger) {
886+
// If new computed fee is superior at the whole claimable amount burn all in fees
887+
if new_fee > input_amounts {
888+
return Some((0, feerate));
889+
} else {
890+
return Some((input_amounts - new_fee, feerate));
891+
}
892+
}
893+
} else {
894+
if let Some((new_fee, feerate)) = compute_fee_from_spent_amounts(input_amounts, predicted_weight, fee_estimator, logger) {
895+
return Some((input_amounts - new_fee, feerate));
896+
}
897+
}
898+
None
899+
}

0 commit comments

Comments
 (0)