@@ -24,6 +24,7 @@ use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment, HTLC_OUTPUT_IN_COMM
24
24
use ln:: chan_utils;
25
25
use ln:: msgs:: DecodeError ;
26
26
use ln:: onchaintx:: OnchainTxHandler ;
27
+ use chain:: chaininterface:: { FeeEstimator , ConfirmationTarget , MIN_RELAY_FEE_SAT_PER_1000_WEIGHT } ;
27
28
use chain:: keysinterface:: Sign ;
28
29
use util:: byte_utils;
29
30
use util:: logger:: Logger ;
@@ -778,3 +779,104 @@ pub(crate) fn get_witnesses_weight(inputs: &[InputDescriptors]) -> usize {
778
779
}
779
780
tx_weight
780
781
}
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