88// licenses.
99
1010use bitcoin:: amount:: Amount ;
11- use bitcoin:: transaction:: { Transaction , TxOut } ;
12- use bitcoin:: script:: ScriptBuf ;
13- use bitcoin:: consensus:: Encodable ;
1411use bitcoin:: consensus:: encode:: VarInt ;
12+ use bitcoin:: consensus:: Encodable ;
13+ use bitcoin:: script:: ScriptBuf ;
14+ use bitcoin:: transaction:: { Transaction , TxOut } ;
1515
1616#[ allow( unused_imports) ]
1717use crate :: prelude:: * ;
1818
1919use crate :: io_extras:: sink;
2020use core:: cmp:: Ordering ;
2121
22- pub fn sort_outputs < T , C : Fn ( & T , & T ) -> Ordering > ( outputs : & mut Vec < ( TxOut , T ) > , tie_breaker : C ) {
22+ pub fn sort_outputs < T , C : Fn ( & T , & T ) -> Ordering > ( outputs : & mut Vec < ( TxOut , T ) > , tie_breaker : C ) {
2323 outputs. sort_unstable_by ( |a, b| {
2424 a. 0 . value . cmp ( & b. 0 . value ) . then_with ( || {
25- a. 0 . script_pubkey [ ..] . cmp ( & b. 0 . script_pubkey [ ..] ) . then_with ( || {
26- tie_breaker ( & a. 1 , & b. 1 )
27- } )
25+ a. 0 . script_pubkey [ ..] . cmp ( & b. 0 . script_pubkey [ ..] ) . then_with ( || tie_breaker ( & a. 1 , & b. 1 ) )
2826 } )
2927 } ) ;
3028}
@@ -34,34 +32,44 @@ pub fn sort_outputs<T, C : Fn(&T, &T) -> Ordering>(outputs: &mut Vec<(TxOut, T)>
3432/// Assumes at least one input will have a witness (ie spends a segwit output).
3533/// Returns an Err(()) if the requested feerate cannot be met.
3634/// Returns the expected maximum weight of the fully signed transaction on success.
37- pub ( crate ) fn maybe_add_change_output ( tx : & mut Transaction , input_value : Amount , witness_max_weight : u64 , feerate_sat_per_1000_weight : u32 , change_destination_script : ScriptBuf ) -> Result < u64 , ( ) > {
38- if input_value > Amount :: MAX_MONEY { return Err ( ( ) ) ; }
35+ pub ( crate ) fn maybe_add_change_output (
36+ tx : & mut Transaction , input_value : Amount , witness_max_weight : u64 ,
37+ feerate_sat_per_1000_weight : u32 , change_destination_script : ScriptBuf ,
38+ ) -> Result < u64 , ( ) > {
39+ if input_value > Amount :: MAX_MONEY {
40+ return Err ( ( ) ) ;
41+ }
3942
4043 const WITNESS_FLAG_BYTES : u64 = 2 ;
4144
4245 let mut output_value = Amount :: ZERO ;
4346 for output in tx. output . iter ( ) {
4447 output_value += output. value ;
45- if output_value >= input_value { return Err ( ( ) ) ; }
48+ if output_value >= input_value {
49+ return Err ( ( ) ) ;
50+ }
4651 }
4752
4853 let dust_value = change_destination_script. minimal_non_dust ( ) ;
49- let mut change_output = TxOut {
50- script_pubkey : change_destination_script,
51- value : Amount :: ZERO ,
52- } ;
54+ let mut change_output = TxOut { script_pubkey : change_destination_script, value : Amount :: ZERO } ;
5355 let change_len = change_output. consensus_encode ( & mut sink ( ) ) . unwrap ( ) ;
5456 let starting_weight = tx. weight ( ) . to_wu ( ) + WITNESS_FLAG_BYTES + witness_max_weight as u64 ;
5557 let mut weight_with_change: i64 = starting_weight as i64 + change_len as i64 * 4 ;
5658 // Include any extra bytes required to push an extra output.
57- weight_with_change += ( VarInt ( tx. output . len ( ) as u64 + 1 ) . size ( ) - VarInt ( tx. output . len ( ) as u64 ) . size ( ) ) as i64 * 4 ;
59+ weight_with_change += ( VarInt ( tx. output . len ( ) as u64 + 1 ) . size ( )
60+ - VarInt ( tx. output . len ( ) as u64 ) . size ( ) ) as i64
61+ * 4 ;
5862 // When calculating weight, add two for the flag bytes
59- let change_value: i64 = ( input_value - output_value) . to_sat ( ) as i64 - weight_with_change * feerate_sat_per_1000_weight as i64 / 1000 ;
63+ let change_value: i64 = ( input_value - output_value) . to_sat ( ) as i64
64+ - weight_with_change * feerate_sat_per_1000_weight as i64 / 1000 ;
6065 if change_value >= dust_value. to_sat ( ) as i64 {
6166 change_output. value = Amount :: from_sat ( change_value as u64 ) ;
6267 tx. output . push ( change_output) ;
6368 Ok ( weight_with_change as u64 )
64- } else if ( input_value - output_value) . to_sat ( ) as i64 - ( starting_weight as i64 ) * feerate_sat_per_1000_weight as i64 / 1000 < 0 {
69+ } else if ( input_value - output_value) . to_sat ( ) as i64
70+ - ( starting_weight as i64 ) * feerate_sat_per_1000_weight as i64 / 1000
71+ < 0
72+ {
6573 Err ( ( ) )
6674 } else {
6775 Ok ( starting_weight)
@@ -73,60 +81,58 @@ mod tests {
7381 use super :: * ;
7482
7583 use bitcoin:: amount:: Amount ;
76- use bitcoin:: locktime:: absolute:: LockTime ;
77- use bitcoin:: transaction:: { TxIn , OutPoint , Version } ;
78- use bitcoin:: script:: Builder ;
7984 use bitcoin:: hash_types:: Txid ;
8085 use bitcoin:: hashes:: Hash ;
8186 use bitcoin:: hex:: FromHex ;
87+ use bitcoin:: locktime:: absolute:: LockTime ;
88+ use bitcoin:: script:: Builder ;
89+ use bitcoin:: transaction:: { OutPoint , TxIn , Version } ;
8290 use bitcoin:: { PubkeyHash , Sequence , Witness } ;
8391
8492 use alloc:: vec;
8593
8694 #[ test]
8795 fn sort_output_by_value ( ) {
8896 let txout1 = TxOut {
89- value : Amount :: from_sat ( 100 ) ,
90- script_pubkey : Builder :: new ( ) . push_int ( 0 ) . into_script ( )
97+ value : Amount :: from_sat ( 100 ) ,
98+ script_pubkey : Builder :: new ( ) . push_int ( 0 ) . into_script ( ) ,
9199 } ;
92100 let txout1_ = txout1. clone ( ) ;
93101
94102 let txout2 = TxOut {
95103 value : Amount :: from_sat ( 99 ) ,
96- script_pubkey : Builder :: new ( ) . push_int ( 0 ) . into_script ( )
104+ script_pubkey : Builder :: new ( ) . push_int ( 0 ) . into_script ( ) ,
97105 } ;
98106 let txout2_ = txout2. clone ( ) ;
99107
100108 let mut outputs = vec ! [ ( txout1, "ignore" ) , ( txout2, "ignore" ) ] ;
101- sort_outputs ( & mut outputs, |_, _| { unreachable ! ( ) ; } ) ;
109+ sort_outputs ( & mut outputs, |_, _| {
110+ unreachable ! ( ) ;
111+ } ) ;
102112
103- assert_eq ! (
104- & outputs,
105- & vec![ ( txout2_, "ignore" ) , ( txout1_, "ignore" ) ]
106- ) ;
113+ assert_eq ! ( & outputs, & vec![ ( txout2_, "ignore" ) , ( txout1_, "ignore" ) ] ) ;
107114 }
108115
109116 #[ test]
110117 fn sort_output_by_script_pubkey ( ) {
111118 let txout1 = TxOut {
112- value : Amount :: from_sat ( 100 ) ,
119+ value : Amount :: from_sat ( 100 ) ,
113120 script_pubkey : Builder :: new ( ) . push_int ( 3 ) . into_script ( ) ,
114121 } ;
115122 let txout1_ = txout1. clone ( ) ;
116123
117124 let txout2 = TxOut {
118125 value : Amount :: from_sat ( 100 ) ,
119- script_pubkey : Builder :: new ( ) . push_int ( 1 ) . push_int ( 2 ) . into_script ( )
126+ script_pubkey : Builder :: new ( ) . push_int ( 1 ) . push_int ( 2 ) . into_script ( ) ,
120127 } ;
121128 let txout2_ = txout2. clone ( ) ;
122129
123130 let mut outputs = vec ! [ ( txout1, "ignore" ) , ( txout2, "ignore" ) ] ;
124- sort_outputs ( & mut outputs, |_, _| { unreachable ! ( ) ; } ) ;
131+ sort_outputs ( & mut outputs, |_, _| {
132+ unreachable ! ( ) ;
133+ } ) ;
125134
126- assert_eq ! (
127- & outputs,
128- & vec![ ( txout2_, "ignore" ) , ( txout1_, "ignore" ) ]
129- ) ;
135+ assert_eq ! ( & outputs, & vec![ ( txout2_, "ignore" ) , ( txout1_, "ignore" ) ] ) ;
130136 }
131137
132138 #[ test]
@@ -145,29 +151,28 @@ mod tests {
145151 let txout2_ = txout2. clone ( ) ;
146152
147153 let mut outputs = vec ! [ ( txout1, "ignore" ) , ( txout2, "ignore" ) ] ;
148- sort_outputs ( & mut outputs, |_, _| { unreachable ! ( ) ; } ) ;
154+ sort_outputs ( & mut outputs, |_, _| {
155+ unreachable ! ( ) ;
156+ } ) ;
149157
150158 assert_eq ! ( & outputs, & vec![ ( txout1_, "ignore" ) , ( txout2_, "ignore" ) ] ) ;
151159 }
152160
153161 #[ test]
154162 fn sort_output_tie_breaker_test ( ) {
155163 let txout1 = TxOut {
156- value : Amount :: from_sat ( 100 ) ,
157- script_pubkey : Builder :: new ( ) . push_int ( 1 ) . push_int ( 2 ) . into_script ( )
164+ value : Amount :: from_sat ( 100 ) ,
165+ script_pubkey : Builder :: new ( ) . push_int ( 1 ) . push_int ( 2 ) . into_script ( ) ,
158166 } ;
159167 let txout1_ = txout1. clone ( ) ;
160168
161169 let txout2 = txout1. clone ( ) ;
162170 let txout2_ = txout1. clone ( ) ;
163171
164172 let mut outputs = vec ! [ ( txout1, 420 ) , ( txout2, 69 ) ] ;
165- sort_outputs ( & mut outputs, |a, b| { a. cmp ( b) } ) ;
173+ sort_outputs ( & mut outputs, |a, b| a. cmp ( b) ) ;
166174
167- assert_eq ! (
168- & outputs,
169- & vec![ ( txout2_, 69 ) , ( txout1_, 420 ) ]
170- ) ;
175+ assert_eq ! ( & outputs, & vec![ ( txout2_, 69 ) , ( txout1_, 420 ) ] ) ;
171176 }
172177
173178 fn script_from_hex ( hex_str : & str ) -> ScriptBuf {
@@ -215,18 +220,35 @@ mod tests {
215220 #[ test]
216221 fn test_tx_value_overrun ( ) {
217222 // If we have a bogus input amount or outputs valued more than inputs, we should fail
218- let mut tx = Transaction { version : Version :: TWO , lock_time : LockTime :: ZERO , input : Vec :: new ( ) , output : vec ! [ TxOut {
219- script_pubkey: ScriptBuf :: new( ) , value: Amount :: from_sat( 1000 )
220- } ] } ;
221- assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 21_000_000_0000_0001 ) , 0 , 253 , ScriptBuf :: new( ) ) . is_err( ) ) ;
222- assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 400 ) , 0 , 253 , ScriptBuf :: new( ) ) . is_err( ) ) ;
223- assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 4000 ) , 0 , 253 , ScriptBuf :: new( ) ) . is_ok( ) ) ;
223+ let mut tx = Transaction {
224+ version : Version :: TWO ,
225+ lock_time : LockTime :: ZERO ,
226+ input : Vec :: new ( ) ,
227+ output : vec ! [ TxOut { script_pubkey: ScriptBuf :: new( ) , value: Amount :: from_sat( 1000 ) } ] ,
228+ } ;
229+ assert ! ( maybe_add_change_output(
230+ & mut tx,
231+ Amount :: from_sat( 21_000_000_0000_0001 ) ,
232+ 0 ,
233+ 253 ,
234+ ScriptBuf :: new( )
235+ )
236+ . is_err( ) ) ;
237+ assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 400 ) , 0 , 253 , ScriptBuf :: new( ) )
238+ . is_err( ) ) ;
239+ assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 4000 ) , 0 , 253 , ScriptBuf :: new( ) )
240+ . is_ok( ) ) ;
224241 }
225242
226243 #[ test]
227244 fn test_tx_change_edge ( ) {
228245 // Check that we never add dust outputs
229- let mut tx = Transaction { version : Version :: TWO , lock_time : LockTime :: ZERO , input : Vec :: new ( ) , output : Vec :: new ( ) } ;
246+ let mut tx = Transaction {
247+ version : Version :: TWO ,
248+ lock_time : LockTime :: ZERO ,
249+ input : Vec :: new ( ) ,
250+ output : Vec :: new ( ) ,
251+ } ;
230252 let orig_wtxid = tx. compute_wtxid ( ) ;
231253 let output_spk = ScriptBuf :: new_p2pkh ( & PubkeyHash :: hash ( & [ 0 ; 0 ] ) ) ;
232254 assert_eq ! ( output_spk. minimal_non_dust( ) . to_sat( ) , 546 ) ;
@@ -235,25 +257,48 @@ mod tests {
235257 // weight = 3 * base size + total size = 3 * (4 + 1 + 0 + 1 + 0 + 4) + (4 + 1 + 1 + 1 + 0 + 1 + 0 + 4) = 3 * 10 + 12 = 42
236258 assert_eq ! ( tx. weight( ) . to_wu( ) , 42 ) ;
237259 // 10 sats isn't enough to pay fee on a dummy transaction...
238- assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 10 ) , 0 , 250 , output_spk. clone( ) ) . is_err( ) ) ;
260+ assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 10 ) , 0 , 250 , output_spk. clone( ) )
261+ . is_err( ) ) ;
239262 assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // Failure doesn't change the transaction
240- // but 11 (= ceil(42 * 250 / 1000)) is, just not enough to add a change output...
241- assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 11 ) , 0 , 250 , output_spk. clone( ) ) . is_ok( ) ) ;
263+ // but 11 (= ceil(42 * 250 / 1000)) is, just not enough to add a change output...
264+ assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 11 ) , 0 , 250 , output_spk. clone( ) )
265+ . is_ok( ) ) ;
242266 assert_eq ! ( tx. output. len( ) , 0 ) ;
243267 assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // If we don't add an output, we don't change the transaction
244- assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 549 ) , 0 , 250 , output_spk. clone( ) ) . is_ok( ) ) ;
268+ assert ! ( maybe_add_change_output(
269+ & mut tx,
270+ Amount :: from_sat( 549 ) ,
271+ 0 ,
272+ 250 ,
273+ output_spk. clone( )
274+ )
275+ . is_ok( ) ) ;
245276 assert_eq ! ( tx. output. len( ) , 0 ) ;
246277 assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // If we don't add an output, we don't change the transaction
247- // 590 is also not enough
248- assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 590 ) , 0 , 250 , output_spk. clone( ) ) . is_ok( ) ) ;
278+ // 590 is also not enough
279+ assert ! ( maybe_add_change_output(
280+ & mut tx,
281+ Amount :: from_sat( 590 ) ,
282+ 0 ,
283+ 250 ,
284+ output_spk. clone( )
285+ )
286+ . is_ok( ) ) ;
249287 assert_eq ! ( tx. output. len( ) , 0 ) ;
250288 assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // If we don't add an output, we don't change the transaction
251- // at 591 we can afford the change output at the dust limit (546)
252- assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 591 ) , 0 , 250 , output_spk. clone( ) ) . is_ok( ) ) ;
289+ // at 591 we can afford the change output at the dust limit (546)
290+ assert ! ( maybe_add_change_output(
291+ & mut tx,
292+ Amount :: from_sat( 591 ) ,
293+ 0 ,
294+ 250 ,
295+ output_spk. clone( )
296+ )
297+ . is_ok( ) ) ;
253298 assert_eq ! ( tx. output. len( ) , 1 ) ;
254299 assert_eq ! ( tx. output[ 0 ] . value. to_sat( ) , 546 ) ;
255300 assert_eq ! ( tx. output[ 0 ] . script_pubkey, output_spk) ;
256- assert_eq ! ( tx. weight( ) . to_wu( ) / 4 , 590 - 546 ) ; // New weight is exactly the fee we wanted.
301+ assert_eq ! ( tx. weight( ) . to_wu( ) / 4 , 590 - 546 ) ; // New weight is exactly the fee we wanted.
257302
258303 tx. output . pop ( ) ;
259304 assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // The only change is the addition of one output.
@@ -262,28 +307,65 @@ mod tests {
262307 #[ test]
263308 fn test_tx_extra_outputs ( ) {
264309 // Check that we correctly handle existing outputs
265- let mut tx = Transaction { version : Version :: TWO , lock_time : LockTime :: ZERO , input : vec ! [ TxIn {
266- previous_output: OutPoint :: new( Txid :: all_zeros( ) , 0 ) , script_sig: ScriptBuf :: new( ) , witness: Witness :: new( ) , sequence: Sequence :: ZERO ,
267- } ] , output : vec ! [ TxOut {
268- script_pubkey: Builder :: new( ) . push_int( 1 ) . into_script( ) , value: Amount :: from_sat( 1000 )
269- } ] } ;
310+ let mut tx = Transaction {
311+ version : Version :: TWO ,
312+ lock_time : LockTime :: ZERO ,
313+ input : vec ! [ TxIn {
314+ previous_output: OutPoint :: new( Txid :: all_zeros( ) , 0 ) ,
315+ script_sig: ScriptBuf :: new( ) ,
316+ witness: Witness :: new( ) ,
317+ sequence: Sequence :: ZERO ,
318+ } ] ,
319+ output : vec ! [ TxOut {
320+ script_pubkey: Builder :: new( ) . push_int( 1 ) . into_script( ) ,
321+ value: Amount :: from_sat( 1000 ) ,
322+ } ] ,
323+ } ;
270324 let orig_wtxid = tx. compute_wtxid ( ) ;
271325 let orig_weight = tx. weight ( ) . to_wu ( ) ;
272326 assert_eq ! ( orig_weight / 4 , 61 ) ;
273327
274328 assert_eq ! ( Builder :: new( ) . push_int( 2 ) . into_script( ) . minimal_non_dust( ) . to_sat( ) , 474 ) ;
275329
276330 // Input value of the output value + fee - 1 should fail:
277- assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 1000 + 61 + 100 - 1 ) , 400 , 250 , Builder :: new( ) . push_int( 2 ) . into_script( ) ) . is_err( ) ) ;
331+ assert ! ( maybe_add_change_output(
332+ & mut tx,
333+ Amount :: from_sat( 1000 + 61 + 100 - 1 ) ,
334+ 400 ,
335+ 250 ,
336+ Builder :: new( ) . push_int( 2 ) . into_script( )
337+ )
338+ . is_err( ) ) ;
278339 assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // Failure doesn't change the transaction
279- // but one more input sat should succeed, without changing the transaction
280- assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 1000 + 61 + 100 ) , 400 , 250 , Builder :: new( ) . push_int( 2 ) . into_script( ) ) . is_ok( ) ) ;
340+ // but one more input sat should succeed, without changing the transaction
341+ assert ! ( maybe_add_change_output(
342+ & mut tx,
343+ Amount :: from_sat( 1000 + 61 + 100 ) ,
344+ 400 ,
345+ 250 ,
346+ Builder :: new( ) . push_int( 2 ) . into_script( )
347+ )
348+ . is_ok( ) ) ;
281349 assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // If we don't add an output, we don't change the transaction
282- // In order to get a change output, we need to add 474 plus the output's weight / 4 (10)...
283- assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 1000 + 61 + 100 + 474 + 9 ) , 400 , 250 , Builder :: new( ) . push_int( 2 ) . into_script( ) ) . is_ok( ) ) ;
350+ // In order to get a change output, we need to add 474 plus the output's weight / 4 (10)...
351+ assert ! ( maybe_add_change_output(
352+ & mut tx,
353+ Amount :: from_sat( 1000 + 61 + 100 + 474 + 9 ) ,
354+ 400 ,
355+ 250 ,
356+ Builder :: new( ) . push_int( 2 ) . into_script( )
357+ )
358+ . is_ok( ) ) ;
284359 assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // If we don't add an output, we don't change the transaction
285360
286- assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 1000 + 61 + 100 + 474 + 10 ) , 400 , 250 , Builder :: new( ) . push_int( 2 ) . into_script( ) ) . is_ok( ) ) ;
361+ assert ! ( maybe_add_change_output(
362+ & mut tx,
363+ Amount :: from_sat( 1000 + 61 + 100 + 474 + 10 ) ,
364+ 400 ,
365+ 250 ,
366+ Builder :: new( ) . push_int( 2 ) . into_script( )
367+ )
368+ . is_ok( ) ) ;
287369 assert_eq ! ( tx. output. len( ) , 2 ) ;
288370 assert_eq ! ( tx. output[ 1 ] . value. to_sat( ) , 474 ) ;
289371 assert_eq ! ( tx. output[ 1 ] . script_pubkey, Builder :: new( ) . push_int( 2 ) . into_script( ) ) ;
0 commit comments