Skip to content

Commit c3aab6f

Browse files
author
Antoine Riard
committed
Extract fee computation utilities out of OnchainTxHandler
1 parent c264514 commit c3aab6f

File tree

2 files changed

+98
-96
lines changed

2 files changed

+98
-96
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);
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);
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);
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) {
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: 9 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ use ln::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER};
1717
use ln::channelmanager::PaymentPreimage;
1818
use ln::chan_utils::LocalCommitmentTransaction;
1919
use ln::onchain_utils::{OnchainRequest, PackageTemplate};
20-
use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
20+
use ln::onchain_utils;
21+
use chain::chaininterface::{FeeEstimator, BroadcasterInterface};
2122
use chain::keysinterface::ChannelKeys;
2223
use util::logger::Logger;
2324
use util::ser::{Readable, Writer, Writeable};
@@ -46,41 +47,6 @@ enum OnchainEvent {
4647
}
4748
}
4849

49-
macro_rules! subtract_high_prio_fee {
50-
($logger: ident, $fee_estimator: expr, $value: expr, $predicted_weight: expr, $used_feerate: expr) => {
51-
{
52-
$used_feerate = $fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority);
53-
let mut fee = $used_feerate * ($predicted_weight as u64) / 1000;
54-
if $value <= fee {
55-
$used_feerate = $fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
56-
fee = $used_feerate * ($predicted_weight as u64) / 1000;
57-
if $value <= fee {
58-
$used_feerate = $fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
59-
fee = $used_feerate * ($predicted_weight as u64) / 1000;
60-
if $value <= fee {
61-
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)",
62-
fee, $value);
63-
false
64-
} else {
65-
log_warn!($logger, "Used low priority fee for on-chain punishment tx as high priority fee was more than the entire claim balance ({} sat)",
66-
$value);
67-
$value -= fee;
68-
true
69-
}
70-
} else {
71-
log_warn!($logger, "Used medium priority fee for on-chain punishment tx as high priority fee was more than the entire claim balance ({} sat)",
72-
$value);
73-
$value -= fee;
74-
true
75-
}
76-
} else {
77-
$value -= fee;
78-
true
79-
}
80-
}
81-
}
82-
}
83-
8450
impl Readable for Option<Vec<Option<(usize, Signature)>>> {
8551
fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
8652
match Readable::read(reader)? {
@@ -333,45 +299,6 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
333299
{
334300
if cached_request.content.outpoints().len() == 0 { return None } // But don't prune pending claiming request yet, we may have to resurrect HTLCs
335301

336-
macro_rules! RBF_bump {
337-
($amount: expr, $old_feerate: expr, $fee_estimator: expr, $predicted_weight: expr) => {
338-
{
339-
let mut used_feerate;
340-
// If old feerate inferior to actual one given back by Fee Estimator, use it to compute new fee...
341-
let new_fee = if $old_feerate < $fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) {
342-
let mut value = $amount;
343-
if subtract_high_prio_fee!(logger, $fee_estimator, value, $predicted_weight, used_feerate) {
344-
// Overflow check is done in subtract_high_prio_fee
345-
$amount - value
346-
} else {
347-
log_trace!(logger, "Can't new-estimation bump new claiming tx, amount {} is too small", $amount);
348-
return None;
349-
}
350-
// ...else just increase the previous feerate by 25% (because that's a nice number)
351-
} else {
352-
let fee = $old_feerate * $predicted_weight / 750;
353-
if $amount <= fee {
354-
log_trace!(logger, "Can't 25% bump new claiming tx, amount {} is too small", $amount);
355-
return None;
356-
}
357-
fee
358-
};
359-
360-
let previous_fee = $old_feerate * $predicted_weight / 1000;
361-
let min_relay_fee = MIN_RELAY_FEE_SAT_PER_1000_WEIGHT * $predicted_weight / 1000;
362-
// BIP 125 Opt-in Full Replace-by-Fee Signaling
363-
// * 3. The replacement transaction pays an absolute fee of at least the sum paid by the original transactions.
364-
// * 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.
365-
let new_fee = if new_fee < previous_fee + min_relay_fee {
366-
new_fee + previous_fee + min_relay_fee - new_fee
367-
} else {
368-
new_fee
369-
};
370-
Some((new_fee, new_fee * 1000 / $predicted_weight))
371-
}
372-
}
373-
}
374-
375302
// Compute new height timer to decide when we need to regenerate a new bumped version of the claim tx (if we
376303
// didn't receive confirmation of it before, or not enough reorg-safe depth on top of it).
377304
let new_timer = Some(Self::get_height_timer(height, cached_request.absolute_timelock));
@@ -380,28 +307,14 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
380307
if amt == 0 { dynamic_fee = false; }
381308
if dynamic_fee {
382309
let predicted_weight = cached_request.content.package_weight(&self.destination_script);
383-
let mut new_feerate;
384-
// If old feerate is 0, first iteration of this claim, use normal fee calculation
385-
if cached_request.feerate_previous != 0 {
386-
if let Some((new_fee, feerate)) = RBF_bump!(amt, cached_request.feerate_previous, fee_estimator, predicted_weight as u64) {
387-
// If new computed fee is superior at the whole claimable amount burn all in fees
388-
if new_fee > amt {
389-
amt = 0;
390-
} else {
391-
amt = amt - new_fee;
392-
}
393-
new_feerate = feerate;
394-
} else { return None; }
395-
} else {
396-
if subtract_high_prio_fee!(logger, fee_estimator, amt, predicted_weight, new_feerate) {
397-
} else { return None; }
398-
}
399-
assert!(new_feerate != 0);
310+
if let Some((output_value, new_feerate)) = onchain_utils::compute_output_value(predicted_weight, amt, cached_request.feerate_previous, &fee_estimator, &logger) {
311+
assert!(new_feerate != 0);
400312

401-
let transaction = cached_request.content.package_finalize(self, amt, self.destination_script.clone(), &logger).unwrap();
402-
log_trace!(logger, "...with timer {} and feerate {}", new_timer.unwrap(), new_feerate);
403-
assert!(predicted_weight >= transaction.get_weight());
404-
return Some((new_timer, new_feerate, transaction))
313+
let transaction = cached_request.content.package_finalize(self, output_value, self.destination_script.clone(), &logger).unwrap();
314+
log_trace!(logger, "...with timer {} and feerate {}", new_timer.unwrap(), new_feerate);
315+
assert!(predicted_weight >= transaction.get_weight());
316+
return Some((new_timer, new_feerate, transaction))
317+
}
405318
} else {
406319
if let Some(transaction) = cached_request.content.package_finalize(self, amt, self.destination_script.clone(), &logger) {
407320
return Some((None, self.local_commitment.as_ref().unwrap().feerate_per_kw, transaction));

0 commit comments

Comments
 (0)