Skip to content

Commit ee6711f

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 a59bb6c commit ee6711f

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
@@ -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;
@@ -821,3 +822,104 @@ pub(crate) fn get_witnesses_weight(inputs: &[InputDescriptors]) -> usize {
821822
}
822823
tx_weight
823824
}
825+
826+
/// Attempt to propose a fee based on consumed outpoints's values and predicted weight of the claiming
827+
/// transaction. We start with the highest priority feerate returned by the node's fee estimator
828+
/// then fall-back to lower priorities until we have enough value available to suck from.
829+
/// If the proposed fee is more than the claimable balance, we return None
830+
fn subtract_high_prio_fee<F: Deref, L: Deref>(input_amounts: u64, predicted_weight: usize, fee_estimator: &F, logger: &L) -> Option<(u64, u64)>
831+
where F::Target: FeeEstimator,
832+
L::Target: Logger,
833+
{
834+
let mut updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64;
835+
let mut fee = updated_feerate * (predicted_weight as u64) / 1000;
836+
if input_amounts <= fee {
837+
updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal) as u64;
838+
fee = updated_feerate * (predicted_weight as u64) / 1000;
839+
if input_amounts <= fee {
840+
updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background) as u64;
841+
fee = updated_feerate * (predicted_weight as u64) / 1000;
842+
if input_amounts <= fee {
843+
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)",
844+
fee, input_amounts);
845+
None
846+
} else {
847+
log_warn!(logger, "Used low priority fee for on-chain punishment tx as high priority fee was more than the entire claim balance ({} sat)",
848+
input_amounts);
849+
Some((fee, updated_feerate))
850+
}
851+
} else {
852+
log_warn!(logger, "Used medium priority fee for on-chain punishment tx as high priority fee was more than the entire claim balance ({} sat)",
853+
input_amounts);
854+
Some((fee, updated_feerate))
855+
}
856+
} else {
857+
Some((fee, updated_feerate))
858+
}
859+
}
860+
861+
/// Attempt to propose a bumping fee based on consumed outpoint's value and predicted weight of the
862+
/// claiming transaction. If feerates proposed by the fee-estimator have been increasing since last
863+
/// fee-bumping attempt, use them. Otherwise, blindly bump the feerate by 25% of the previous
864+
/// feerate.
865+
/// We also verify that those bumping heuristics respect BIP125 rules 3) and 4) and if required
866+
/// adjust the new fee to meet the RBF policy requirement.
867+
fn feerate_bump<F: Deref, L: Deref>(predicted_weight: usize, input_amounts: u64, previous_feerate: u64, fee_estimator: &F, logger: &L) -> Option<(u64, u64)>
868+
where F::Target: FeeEstimator,
869+
L::Target: Logger,
870+
{
871+
// If old feerate inferior to actual one given back by Fee Estimator, use it to compute new fee...
872+
let new_fee = if previous_feerate < fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64 {
873+
if let Some((new_fee, _)) = subtract_high_prio_fee(input_amounts, predicted_weight, fee_estimator, logger) {
874+
new_fee
875+
} else {
876+
log_trace!(logger, "Can't new-estimation bump new claiming tx, amount {} is too small", input_amounts);
877+
return None;
878+
}
879+
// ...else just increase the previous feerate by 25% (because that's a nice number)
880+
} else {
881+
let fee = previous_feerate * (predicted_weight as u64) / 750;
882+
if input_amounts <= fee {
883+
log_trace!(logger, "Can't 25% bump new claiming tx, amount {} is too small", input_amounts);
884+
return None;
885+
}
886+
fee
887+
};
888+
889+
let previous_fee = previous_feerate * (predicted_weight as u64) / 1000;
890+
let min_relay_fee = MIN_RELAY_FEE_SAT_PER_1000_WEIGHT * (predicted_weight as u64) / 1000;
891+
// BIP 125 Opt-in Full Replace-by-Fee Signaling
892+
// * 3. The replacement transaction pays an absolute fee of at least the sum paid by the original transactions.
893+
// * 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.
894+
let new_fee = if new_fee < previous_fee + min_relay_fee {
895+
new_fee + previous_fee + min_relay_fee - new_fee
896+
} else {
897+
new_fee
898+
};
899+
Some((new_fee, new_fee * 1000 / (predicted_weight as u64)))
900+
}
901+
902+
/// Deduce a new proposed fee from the claiming transaction output value.
903+
/// If the new proposed fee is superior to the consumed outpoint's value, burn everything in miner's
904+
/// fee to deter counterparties attacker.
905+
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)>
906+
where F::Target: FeeEstimator,
907+
L::Target: Logger,
908+
{
909+
// If old feerate is 0, first iteration of this claim, use normal fee calculation
910+
if previous_feerate != 0 {
911+
if let Some((new_fee, feerate)) = feerate_bump(predicted_weight, input_amounts, previous_feerate, fee_estimator, logger) {
912+
// If new computed fee is superior at the whole claimable amount burn all in fees
913+
if new_fee > input_amounts {
914+
return Some((0, feerate));
915+
} else {
916+
return Some((input_amounts - new_fee, feerate));
917+
}
918+
}
919+
} else {
920+
if let Some((new_fee, feerate)) = subtract_high_prio_fee(input_amounts, predicted_weight, fee_estimator, logger) {
921+
return Some((input_amounts - new_fee, feerate));
922+
}
923+
}
924+
None
925+
}

0 commit comments

Comments
 (0)