1- use crate :: Input ;
2- use bitcoin:: {
1+ use crate :: { CreatePsbtError , Input } ;
2+ use alloc:: vec:: Vec ;
3+ use miniscript:: bitcoin:: {
34 absolute:: { self , LockTime } ,
45 transaction:: Version ,
56 Sequence , Transaction , WitnessVersion ,
67} ;
7- use std:: vec:: Vec ;
88
99use rand_core:: { OsRng , RngCore } ;
1010
@@ -14,34 +14,31 @@ pub fn apply_anti_fee_sniping(
1414 inputs : & [ Input ] ,
1515 current_height : absolute:: Height ,
1616 rbf_enabled : bool ,
17- ) {
17+ ) -> Result < ( ) , CreatePsbtError > {
1818 const MAX_SEQUENCE_VALUE : u32 = 65_535 ;
19- const USE_NLOCKTIME_PROBABILITY : f64 = 0.5 ;
19+ const USE_NLOCKTIME_PROBABILITY : u32 = 2 ;
2020 const MIN_SEQUENCE_VALUE : u32 = 1 ;
21- const FURTHER_BACK_PROBABILITY : f64 = 0.1 ;
21+ const FURTHER_BACK_PROBABILITY : u32 = 10 ;
2222 const MAX_RANDOM_OFFSET : u32 = 99 ;
2323
24- tx . version = Version :: TWO ;
24+ let mut rng = OsRng ;
2525
26- let taproot_inputs: Vec < _ > = inputs
27- . iter ( )
28- . enumerate ( )
29- . filter ( |( _, input) | {
30- matches ! (
31- input. plan( ) . and_then( |plan| plan. witness_version( ) ) ,
32- Some ( WitnessVersion :: V1 )
33- )
26+ if tx. version < Version :: TWO {
27+ return Err ( CreatePsbtError :: UnsupportedVersion ( tx. version ) ) ;
28+ }
29+
30+ let taproot_inputs: Vec < usize > = ( 0 ..tx. input . len ( ) )
31+ . filter ( |& idx| {
32+ // Check if this input is taproot using the corresponding Input data
33+ inputs
34+ . get ( idx)
35+ . and_then ( |input| input. plan ( ) )
36+ . and_then ( |plan| plan. witness_version ( ) )
37+ . map ( |version| version == WitnessVersion :: V1 )
38+ . unwrap_or ( false )
3439 } )
3540 . collect ( ) ;
3641
37- // Initialize all nsequence to indicate the requested RBF state
38- for input in & mut tx. input {
39- input. sequence = if rbf_enabled {
40- Sequence ( 0xFFFFFFFF - 2 ) // 2^32 - 3
41- } else {
42- Sequence ( 0xFFFFFFFF - 1 ) // 2^32 - 2
43- }
44- }
4542 // Check always‐locktime conditions
4643 let must_use_locktime = inputs. iter ( ) . any ( |input| {
4744 let confirmation = input. confirmations ( current_height) ;
@@ -56,68 +53,46 @@ pub fn apply_anti_fee_sniping(
5653 let use_locktime = !rbf_enabled
5754 || must_use_locktime
5855 || taproot_inputs. is_empty ( )
59- || random_probability ( USE_NLOCKTIME_PROBABILITY ) ;
56+ || random_probability ( & mut rng , USE_NLOCKTIME_PROBABILITY ) ;
6057
6158 if use_locktime {
6259 // Use nLockTime
6360 let mut locktime = current_height. to_consensus_u32 ( ) ;
6461
65- if random_probability ( FURTHER_BACK_PROBABILITY ) {
66- let random_offset = random_range ( 0 , MAX_RANDOM_OFFSET ) ;
62+ if random_probability ( & mut rng , FURTHER_BACK_PROBABILITY ) {
63+ let random_offset = random_range ( & mut rng , MAX_RANDOM_OFFSET ) ;
6764 locktime = locktime. saturating_sub ( random_offset) ;
6865 }
6966
70- tx. lock_time = LockTime :: from_height ( locktime) . unwrap ( ) ;
67+ let new_locktime = LockTime :: from_height ( locktime)
68+ . map_err ( |_| CreatePsbtError :: InvalidHeight ( locktime) ) ?;
69+
70+ tx. lock_time = new_locktime;
7171 } else {
7272 // Use Sequence
7373 tx. lock_time = LockTime :: ZERO ;
74-
75- let input_index = random_range ( 0 , taproot_inputs. len ( ) as u32 ) as usize ;
76-
77- let ( idx, input) = & taproot_inputs[ input_index] ;
78-
79- let confirmation = input. confirmations ( current_height) ;
74+ let input_index = random_range ( & mut rng, taproot_inputs. len ( ) as u32 ) as usize ;
75+ let confirmation = inputs[ input_index] . confirmations ( current_height) ;
8076
8177 let mut sequence_value = confirmation;
82-
83- if random_probability ( FURTHER_BACK_PROBABILITY ) {
84- let random_offset = random_range ( 0 , MAX_RANDOM_OFFSET ) ;
78+ if random_probability ( & mut rng, FURTHER_BACK_PROBABILITY ) {
79+ let random_offset = random_range ( & mut rng, MAX_RANDOM_OFFSET ) ;
8580 sequence_value = sequence_value
8681 . saturating_sub ( random_offset)
8782 . max ( MIN_SEQUENCE_VALUE ) ;
8883 }
8984
90- tx. input [ * idx ] . sequence = Sequence ( sequence_value) ;
85+ tx. input [ input_index ] . sequence = Sequence ( sequence_value) ;
9186 }
92- }
9387
94- fn random_probability ( probability : f64 ) -> bool {
95- debug_assert ! (
96- ( 0.0 ..=1.0 ) . contains( & probability) ,
97- "Probability must be between 0.0 and 1.0"
98- ) ;
88+ Ok ( ( ) )
89+ }
9990
100- let mut rng = OsRng ;
101- let rand_val = rng. next_u32 ( ) as f64 ;
102- let max_u32 = u32:: MAX as f64 ;
103- ( rand_val / max_u32) < probability
91+ fn random_probability ( rng : & mut OsRng , probability : u32 ) -> bool {
92+ let rand_val = rng. next_u32 ( ) ;
93+ rand_val % probability == 0
10494}
10595
106- fn random_range ( min : u32 , max : u32 ) -> u32 {
107- if min >= max {
108- return min;
109- }
110- let mut rng = OsRng ;
111- let range = max. saturating_sub ( min) ;
112- let threshold = u32:: MAX . saturating_sub ( u32:: MAX % range) ;
113- let min_val = min + ( rng. next_u32 ( ) % ( max - min) ) ;
114- let mut r;
115-
116- loop {
117- r = rng. next_u32 ( ) ;
118- if r < threshold {
119- break ;
120- }
121- }
122- min_val. saturating_add ( r % range)
96+ fn random_range ( rng : & mut OsRng , max : u32 ) -> u32 {
97+ rng. next_u32 ( ) % max
12398}
0 commit comments