Skip to content

Commit 68e2f6c

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 23855e1 commit 68e2f6c

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

lightning/src/ln/onchain_utils.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment};
2424
use ln::chan_utils;
2525
use ln::msgs::DecodeError;
2626
use ln::onchaintx::OnchainTxHandler;
27+
use chain::chaininterface::{FeeEstimator, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
2728
use chain::keysinterface::Sign;
2829
use util::byte_utils;
2930
use util::logger::Logger;
@@ -769,3 +770,104 @@ impl Readable for PackageTemplate {
769770
})
770771
}
771772
}
773+
774+
/// Attempt to propose a fee based on consumed outpoints's values and predicted weight of the claiming
775+
/// transaction. We start with the highest priority feerate returned by the node's fee estimator
776+
/// then fall-back to lower priorities until we have enough value available to suck from.
777+
/// If the proposed fee is more than the claimable balance, we return None
778+
fn subtract_high_prio_fee<F: Deref, L: Deref>(input_amounts: u64, predicted_weight: usize, fee_estimator: &F, logger: &L) -> Option<(u64, u64)>
779+
where F::Target: FeeEstimator,
780+
L::Target: Logger,
781+
{
782+
let mut updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64;
783+
let mut fee = updated_feerate * (predicted_weight as u64) / 1000;
784+
if input_amounts <= fee {
785+
updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal) as u64;
786+
fee = updated_feerate * (predicted_weight as u64) / 1000;
787+
if input_amounts <= fee {
788+
updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background) as u64;
789+
fee = updated_feerate * (predicted_weight as u64) / 1000;
790+
if input_amounts <= fee {
791+
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)",
792+
fee, input_amounts);
793+
None
794+
} else {
795+
log_warn!(logger, "Used low priority fee for on-chain punishment tx as high priority fee was more than the entire claim balance ({} sat)",
796+
input_amounts);
797+
Some((fee, updated_feerate))
798+
}
799+
} else {
800+
log_warn!(logger, "Used medium priority fee for on-chain punishment tx as high priority fee was more than the entire claim balance ({} sat)",
801+
input_amounts);
802+
Some((fee, updated_feerate))
803+
}
804+
} else {
805+
Some((fee, updated_feerate))
806+
}
807+
}
808+
809+
/// Attempt to propose a bumping fee based on consumed outpoint's value and predicted weight of the
810+
/// claiming transaction. If feerates proposed by the fee-estimator have been increasing since last
811+
/// fee-bumping attempt, use them. Otherwise, blindly bump the feerate by 25% of the previous
812+
/// feerate.
813+
/// We also verify that those bumping heuristics respect BIP125 rules 3) and 4) and if required
814+
/// adjust the new fee to meet the RBF policy requirement.
815+
fn feerate_bump<F: Deref, L: Deref>(predicted_weight: usize, input_amounts: u64, previous_feerate: u64, fee_estimator: &F, logger: &L) -> Option<(u64, u64)>
816+
where F::Target: FeeEstimator,
817+
L::Target: Logger,
818+
{
819+
// If old feerate inferior to actual one given back by Fee Estimator, use it to compute new fee...
820+
let new_fee = if previous_feerate < fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64 {
821+
if let Some((new_fee, _)) = subtract_high_prio_fee(input_amounts, predicted_weight, fee_estimator, logger) {
822+
new_fee
823+
} else {
824+
log_trace!(logger, "Can't new-estimation bump new claiming tx, amount {} is too small", input_amounts);
825+
return None;
826+
}
827+
// ...else just increase the previous feerate by 25% (because that's a nice number)
828+
} else {
829+
let fee = previous_feerate * (predicted_weight as u64) / 750;
830+
if input_amounts <= fee {
831+
log_trace!(logger, "Can't 25% bump new claiming tx, amount {} is too small", input_amounts);
832+
return None;
833+
}
834+
fee
835+
};
836+
837+
let previous_fee = previous_feerate * (predicted_weight as u64) / 1000;
838+
let min_relay_fee = MIN_RELAY_FEE_SAT_PER_1000_WEIGHT * (predicted_weight as u64) / 1000;
839+
// BIP 125 Opt-in Full Replace-by-Fee Signaling
840+
// * 3. The replacement transaction pays an absolute fee of at least the sum paid by the original transactions.
841+
// * 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.
842+
let new_fee = if new_fee < previous_fee + min_relay_fee {
843+
new_fee + previous_fee + min_relay_fee - new_fee
844+
} else {
845+
new_fee
846+
};
847+
Some((new_fee, new_fee * 1000 / (predicted_weight as u64)))
848+
}
849+
850+
/// Deduce a new proposed fee from the claiming transaction output value.
851+
/// If the new proposed fee is superior to the consumed outpoint's value, burn everything in miner's
852+
/// fee to deter counterparties attacker.
853+
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)>
854+
where F::Target: FeeEstimator,
855+
L::Target: Logger,
856+
{
857+
// If old feerate is 0, first iteration of this claim, use normal fee calculation
858+
if previous_feerate != 0 {
859+
if let Some((new_fee, feerate)) = feerate_bump(predicted_weight, input_amounts, previous_feerate, fee_estimator, logger) {
860+
// If new computed fee is superior at the whole claimable amount burn all in fees
861+
if new_fee > input_amounts {
862+
return Some((0, feerate));
863+
} else {
864+
return Some((input_amounts - new_fee, feerate));
865+
}
866+
}
867+
} else {
868+
if let Some((new_fee, feerate)) = subtract_high_prio_fee(input_amounts, predicted_weight, fee_estimator, logger) {
869+
return Some((input_amounts - new_fee, feerate));
870+
}
871+
}
872+
None
873+
}

0 commit comments

Comments
 (0)