Skip to content

Commit 7090edb

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 093209a commit 7090edb

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

0 commit comments

Comments
 (0)