Skip to content

Commit a123d75

Browse files
author
Antoine Riard
committed
Extract fee computation utilities out of OnchainTxHandler
1 parent 384fda6 commit a123d75

File tree

2 files changed

+100
-98
lines changed

2 files changed

+100
-98
lines changed

lightning/src/ln/onchain_utils.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment};
1313
use ln::chan_utils;
1414
use ln::msgs::DecodeError;
1515
use ln::onchaintx::OnchainTxHandler;
16+
use chain::chaininterface::{FeeEstimator, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
1617
use chain::keysinterface::ChannelKeys;
1718
use util::byte_utils;
1819
use util::logger::Logger;
@@ -801,3 +802,91 @@ impl Readable for OnchainRequest {
801802
})
802803
}
803804
}
805+
806+
fn subtract_high_prio_fee<F: Deref, L: Deref>(input_amounts: u64, predicted_weight: usize, fee_estimator: &F, logger: &L) -> Option<(u64, u64)>
807+
where F::Target: FeeEstimator,
808+
L::Target: Logger,
809+
{
810+
let mut updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64;
811+
let mut fee = updated_feerate * (predicted_weight as u64) / 1000;
812+
if input_amounts <= fee {
813+
updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal) as u64;
814+
fee = updated_feerate * (predicted_weight as u64) / 1000;
815+
if input_amounts <= fee {
816+
updated_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background) as u64;
817+
fee = updated_feerate * (predicted_weight as u64) / 1000;
818+
if input_amounts <= fee {
819+
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)",
820+
fee, input_amounts);
821+
None
822+
} else {
823+
log_warn!(logger, "Used low priority fee for on-chain punishment tx as high priority fee was more than the entire claim balance ({} sat)",
824+
input_amounts);
825+
Some((fee, updated_feerate))
826+
}
827+
} else {
828+
log_warn!(logger, "Used medium priority fee for on-chain punishment tx as high priority fee was more than the entire claim balance ({} sat)",
829+
input_amounts);
830+
Some((fee, updated_feerate))
831+
}
832+
} else {
833+
Some((fee, updated_feerate))
834+
}
835+
}
836+
837+
fn feerate_bump<F: Deref, L: Deref>(predicted_weight: usize, input_amounts: u64, previous_feerate: u64, fee_estimator: &F, logger: &L) -> Option<(u64, u64)>
838+
where F::Target: FeeEstimator,
839+
L::Target: Logger,
840+
{
841+
// If old feerate inferior to actual one given back by Fee Estimator, use it to compute new fee...
842+
let new_fee = if previous_feerate < fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64 {
843+
if let Some((new_fee, _)) = subtract_high_prio_fee(input_amounts, predicted_weight, fee_estimator, logger) {
844+
new_fee
845+
} else {
846+
log_trace!(logger, "Can't new-estimation bump new claiming tx, amount {} is too small", input_amounts);
847+
return None;
848+
}
849+
// ...else just increase the previous feerate by 25% (because that's a nice number)
850+
} else {
851+
let fee = previous_feerate * (predicted_weight as u64) / 750;
852+
if input_amounts <= fee {
853+
log_trace!(logger, "Can't 25% bump new claiming tx, amount {} is too small", input_amounts);
854+
return None;
855+
}
856+
fee
857+
};
858+
859+
let previous_fee = previous_feerate * (predicted_weight as u64) / 1000;
860+
let min_relay_fee = MIN_RELAY_FEE_SAT_PER_1000_WEIGHT * (predicted_weight as u64) / 1000;
861+
// BIP 125 Opt-in Full Replace-by-Fee Signaling
862+
// * 3. The replacement transaction pays an absolute fee of at least the sum paid by the original transactions.
863+
// * 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.
864+
let new_fee = if new_fee < previous_fee + min_relay_fee {
865+
new_fee + previous_fee + min_relay_fee - new_fee
866+
} else {
867+
new_fee
868+
};
869+
Some((new_fee, new_fee * 1000 / (predicted_weight as u64)))
870+
}
871+
872+
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)>
873+
where F::Target: FeeEstimator,
874+
L::Target: Logger,
875+
{
876+
// If old feerate is 0, first iteration of this claim, use normal fee calculation
877+
if previous_feerate != 0 {
878+
if let Some((new_fee, feerate)) = feerate_bump(predicted_weight, input_amounts, previous_feerate, fee_estimator, logger) {
879+
// If new computed fee is superior at the whole claimable amount burn all in fees
880+
if new_fee > input_amounts {
881+
return Some((0, feerate));
882+
} else {
883+
return Some((input_amounts - new_fee, feerate));
884+
}
885+
}
886+
} else {
887+
if let Some((new_fee, feerate)) = subtract_high_prio_fee(input_amounts, predicted_weight, fee_estimator, logger) {
888+
return Some((input_amounts - new_fee, feerate));
889+
}
890+
}
891+
None
892+
}

lightning/src/ln/onchaintx.rs

Lines changed: 11 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ use ln::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER};
2626
use ln::channelmanager::PaymentPreimage;
2727
use ln::chan_utils::HolderCommitmentTransaction;
2828
use ln::onchain_utils::{OnchainRequest, PackageTemplate};
29-
use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
29+
use ln::onchain_utils;
30+
use chain::chaininterface::{FeeEstimator, BroadcasterInterface};
3031
use chain::keysinterface::ChannelKeys;
3132
use util::logger::Logger;
3233
use util::ser::{Readable, Writer, Writeable};
@@ -55,41 +56,6 @@ enum OnchainEvent {
5556
}
5657
}
5758

58-
macro_rules! subtract_high_prio_fee {
59-
($logger: ident, $fee_estimator: expr, $value: expr, $predicted_weight: expr, $used_feerate: expr) => {
60-
{
61-
$used_feerate = $fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority).into();
62-
let mut fee = $used_feerate as u64 * $predicted_weight / 1000;
63-
if $value <= fee {
64-
$used_feerate = $fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal).into();
65-
fee = $used_feerate as u64 * $predicted_weight / 1000;
66-
if $value <= fee.into() {
67-
$used_feerate = $fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background).into();
68-
fee = $used_feerate as u64 * $predicted_weight / 1000;
69-
if $value <= fee {
70-
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)",
71-
fee, $value);
72-
false
73-
} else {
74-
log_warn!($logger, "Used low priority fee for on-chain punishment tx as high priority fee was more than the entire claim balance ({} sat)",
75-
$value);
76-
$value -= fee;
77-
true
78-
}
79-
} else {
80-
log_warn!($logger, "Used medium priority fee for on-chain punishment tx as high priority fee was more than the entire claim balance ({} sat)",
81-
$value);
82-
$value -= fee;
83-
true
84-
}
85-
} else {
86-
$value -= fee;
87-
true
88-
}
89-
}
90-
}
91-
}
92-
9359
impl Readable for Option<Vec<Option<(usize, Signature)>>> {
9460
fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
9561
match Readable::read(reader)? {
@@ -342,75 +308,22 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
342308
{
343309
if cached_request.content.outpoints().len() == 0 { return None } // But don't prune pending claiming request yet, we may have to resurrect HTLCs
344310

345-
macro_rules! RBF_bump {
346-
($amount: expr, $old_feerate: expr, $fee_estimator: expr, $predicted_weight: expr) => {
347-
{
348-
let mut used_feerate: u32;
349-
// If old feerate inferior to actual one given back by Fee Estimator, use it to compute new fee...
350-
let new_fee = if $old_feerate < $fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64 {
351-
let mut value = $amount;
352-
if subtract_high_prio_fee!(logger, $fee_estimator, value, $predicted_weight, used_feerate) {
353-
// Overflow check is done in subtract_high_prio_fee
354-
($amount - value)
355-
} else {
356-
log_trace!(logger, "Can't new-estimation bump new claiming tx, amount {} is too small", $amount);
357-
return None;
358-
}
359-
// ...else just increase the previous feerate by 25% (because that's a nice number)
360-
} else {
361-
let fee = $old_feerate as u64 * ($predicted_weight as u64) / 750;
362-
if $amount <= fee {
363-
log_trace!(logger, "Can't 25% bump new claiming tx, amount {} is too small", $amount);
364-
return None;
365-
}
366-
fee
367-
};
368-
369-
let previous_fee = $old_feerate as u64 * ($predicted_weight as u64) / 1000;
370-
let min_relay_fee = MIN_RELAY_FEE_SAT_PER_1000_WEIGHT * ($predicted_weight as u64) / 1000;
371-
// BIP 125 Opt-in Full Replace-by-Fee Signaling
372-
// * 3. The replacement transaction pays an absolute fee of at least the sum paid by the original transactions.
373-
// * 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.
374-
let new_fee = if new_fee < previous_fee + min_relay_fee {
375-
new_fee + previous_fee + min_relay_fee - new_fee
376-
} else {
377-
new_fee
378-
};
379-
Some((new_fee, new_fee * 1000 / ($predicted_weight as u64)))
380-
}
381-
}
382-
}
383-
384311
// Compute new height timer to decide when we need to regenerate a new bumped version of the claim tx (if we
385312
// didn't receive confirmation of it before, or not enough reorg-safe depth on top of it).
386313
let new_timer = Some(Self::get_height_timer(height, cached_request.absolute_timelock));
387-
let mut amt = cached_request.content.package_amounts();
314+
let amt = cached_request.content.package_amounts();
388315
let mut dynamic_fee = true;
389316
if amt == 0 { dynamic_fee = false; }
390317
if dynamic_fee {
391-
let predicted_weight = cached_request.content.package_weight(&self.destination_script) as u64;
392-
let mut new_feerate;
393-
// If old feerate is 0, first iteration of this claim, use normal fee calculation
394-
if cached_request.feerate_previous != 0 {
395-
if let Some((new_fee, feerate)) = RBF_bump!(amt, cached_request.feerate_previous, fee_estimator, predicted_weight as u64) {
396-
// If new computed fee is superior at the whole claimable amount burn all in fees
397-
if new_fee > amt {
398-
amt = 0;
399-
} else {
400-
amt = amt - new_fee;
401-
}
402-
new_feerate = feerate;
403-
} else { return None; }
404-
} else {
405-
if subtract_high_prio_fee!(logger, fee_estimator, amt, predicted_weight, new_feerate) {
406-
} else { return None; }
318+
let predicted_weight = cached_request.content.package_weight(&self.destination_script);
319+
if let Some((output_value, new_feerate)) = onchain_utils::compute_output_value(predicted_weight, amt, cached_request.feerate_previous, &fee_estimator, &logger) {
320+
assert!(new_feerate != 0);
321+
322+
let transaction = cached_request.content.package_finalize(self, output_value, self.destination_script.clone(), &logger).unwrap();
323+
log_trace!(logger, "...with timer {} and feerate {}", new_timer.unwrap(), new_feerate);
324+
assert!(predicted_weight >= transaction.get_weight());
325+
return Some((new_timer, new_feerate, transaction))
407326
}
408-
assert!(new_feerate != 0);
409-
410-
let transaction = cached_request.content.package_finalize(self, amt, self.destination_script.clone(), &logger).unwrap();
411-
log_trace!(logger, "...with timer {} and feerate {}", new_timer.unwrap(), new_feerate);
412-
assert!(predicted_weight >= transaction.get_weight() as u64);
413-
return Some((new_timer, new_feerate, transaction))
414327
} else {
415328
if let Some(transaction) = cached_request.content.package_finalize(self, amt, self.destination_script.clone(), &logger) {
416329
return Some((None, self.holder_commitment.as_ref().unwrap().feerate_per_kw as u64, transaction));

0 commit comments

Comments
 (0)