@@ -52,16 +52,19 @@ pub(crate) fn maybe_add_change_output(tx: &mut Transaction, input_value: Amount,
5252 } ;
5353 let change_len = change_output. consensus_encode ( & mut sink ( ) ) . unwrap ( ) ;
5454 let starting_weight = tx. weight ( ) . to_wu ( ) + WITNESS_FLAG_BYTES + witness_max_weight as u64 ;
55+ let starting_fees = ( starting_weight as i64 ) * feerate_sat_per_1000_weight as i64 / 1000 ;
5556 let mut weight_with_change: i64 = starting_weight as i64 + change_len as i64 * 4 ;
5657 // 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 ;
58+ let num_outputs = tx. output . len ( ) as u64 ;
59+ weight_with_change += ( VarInt ( num_outputs + 1 ) . size ( ) - VarInt ( num_outputs) . size ( ) ) as i64 * 4 ;
5860 // 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 ;
61+ let fees_with_change = weight_with_change * feerate_sat_per_1000_weight as i64 / 1000 ;
62+ let change_value: i64 = ( input_value - output_value) . to_sat ( ) as i64 - fees_with_change;
6063 if change_value >= dust_value. to_sat ( ) as i64 {
6164 change_output. value = Amount :: from_sat ( change_value as u64 ) ;
6265 tx. output . push ( change_output) ;
6366 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 {
67+ } else if ( input_value - output_value) . to_sat ( ) as i64 - starting_fees < 0 {
6568 Err ( ( ) )
6669 } else {
6770 Ok ( starting_weight)
@@ -79,7 +82,7 @@ mod tests {
7982 use bitcoin:: hash_types:: Txid ;
8083 use bitcoin:: hashes:: Hash ;
8184 use bitcoin:: hex:: FromHex ;
82- use bitcoin:: { PubkeyHash , Sequence , Witness } ;
85+ use bitcoin:: { PubkeyHash , Sequence , Witness , witness } ;
8386
8487 use alloc:: vec;
8588
@@ -215,18 +218,28 @@ mod tests {
215218 #[ test]
216219 fn test_tx_value_overrun ( ) {
217220 // 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( ) ) ;
221+ let version = Version :: TWO ;
222+ let lock_time = LockTime :: ZERO ;
223+ let input = Vec :: new ( ) ;
224+ let tx_out = TxOut { script_pubkey : ScriptBuf :: new ( ) , value : Amount :: from_sat ( 1000 ) } ;
225+ let output = vec ! [ tx_out] ;
226+ let mut tx = Transaction { version, lock_time, input, output } ;
227+ let amount = Amount :: from_sat ( 21_000_000_0000_0001 ) ;
228+ assert ! ( maybe_add_change_output( & mut tx, amount, 0 , 253 , ScriptBuf :: new( ) ) . is_err( ) ) ;
229+ let amount = Amount :: from_sat ( 400 ) ;
230+ assert ! ( maybe_add_change_output( & mut tx, amount, 0 , 253 , ScriptBuf :: new( ) ) . is_err( ) ) ;
231+ let amount = Amount :: from_sat ( 4000 ) ;
232+ assert ! ( maybe_add_change_output( & mut tx, amount, 0 , 253 , ScriptBuf :: new( ) ) . is_ok( ) ) ;
224233 }
225234
226235 #[ test]
227236 fn test_tx_change_edge ( ) {
228237 // 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 ( ) } ;
238+ let version = Version :: TWO ;
239+ let lock_time = LockTime :: ZERO ;
240+ let input = Vec :: new ( ) ;
241+ let output = Vec :: new ( ) ;
242+ let mut tx = Transaction { version, lock_time, input, output } ;
230243 let orig_wtxid = tx. compute_wtxid ( ) ;
231244 let output_spk = ScriptBuf :: new_p2pkh ( & PubkeyHash :: hash ( & [ 0 ; 0 ] ) ) ;
232245 assert_eq ! ( output_spk. minimal_non_dust( ) . to_sat( ) , 546 ) ;
@@ -235,60 +248,91 @@ mod tests {
235248 // 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
236249 assert_eq ! ( tx. weight( ) . to_wu( ) , 42 ) ;
237250 // 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( ) ) ;
239- assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // Failure doesn't change the transaction
251+ let amount = Amount :: from_sat ( 10 ) ;
252+ assert ! ( maybe_add_change_output( & mut tx, amount, 0 , 250 , output_spk. clone( ) ) . is_err( ) ) ;
253+ // Failure doesn't change the transaction
254+ assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ;
240255 // 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( ) ) ;
256+ let amount = Amount :: from_sat ( 11 ) ;
257+ assert ! ( maybe_add_change_output( & mut tx, amount, 0 , 250 , output_spk. clone( ) ) . is_ok( ) ) ;
242258 assert_eq ! ( tx. output. len( ) , 0 ) ;
243- 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( ) ) ;
259+ // If we don't add an output, we don't change the transaction
260+ assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ;
261+ let amount = Amount :: from_sat ( 549 ) ;
262+ assert ! ( maybe_add_change_output( & mut tx, amount, 0 , 250 , output_spk. clone( ) ) . is_ok( ) ) ;
245263 assert_eq ! ( tx. output. len( ) , 0 ) ;
246- assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // If we don't add an output, we don't change the transaction
264+ // If we don't add an output, we don't change the transaction
265+ assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ;
247266 // 590 is also not enough
248- assert ! ( maybe_add_change_output( & mut tx, Amount :: from_sat( 590 ) , 0 , 250 , output_spk. clone( ) ) . is_ok( ) ) ;
267+ let amount = Amount :: from_sat ( 590 ) ;
268+ assert ! ( maybe_add_change_output( & mut tx, amount, 0 , 250 , output_spk. clone( ) ) . is_ok( ) ) ;
249269 assert_eq ! ( tx. output. len( ) , 0 ) ;
250- assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // If we don't add an output, we don't change the transaction
270+ // If we don't add an output, we don't change the transaction
271+ assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ;
251272 // 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( ) ) ;
273+ let amount = Amount :: from_sat ( 591 ) ;
274+ assert ! ( maybe_add_change_output( & mut tx, amount, 0 , 250 , output_spk. clone( ) ) . is_ok( ) ) ;
253275 assert_eq ! ( tx. output. len( ) , 1 ) ;
254276 assert_eq ! ( tx. output[ 0 ] . value. to_sat( ) , 546 ) ;
255277 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.
278+ // New weight is exactly the fee we wanted.
279+ assert_eq ! ( tx. weight( ) . to_wu( ) / 4 , 590 -546 ) ;
257280
258281 tx. output . pop ( ) ;
259- assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // The only change is the addition of one output.
282+ // The only change is the addition of one output.
283+ assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ;
260284 }
261285
262286 #[ test]
263287 fn test_tx_extra_outputs ( ) {
264288 // 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- } ] } ;
289+ let script_pubkey = Builder :: new ( ) . push_int ( 1 ) . into_script ( ) ;
290+ let tx_out = TxOut { script_pubkey, value : Amount :: from_sat ( 1000 ) } ;
291+ let previous_output = OutPoint :: new ( Txid :: all_zeros ( ) , 0 ) ;
292+ let script_sig = ScriptBuf :: new ( ) ;
293+ let witness = Witness :: new ( ) ;
294+ let sequence = Sequence :: ZERO ;
295+ let tx_in = TxIn { previous_output, script_sig, witness, sequence } ;
296+ let version = Version :: TWO ;
297+ let lock_time = LockTime :: ZERO ;
298+ let input = vec ! [ tx_in] ;
299+ let output = vec ! [ tx_out] ;
300+ let mut tx = Transaction { version, lock_time, input, output } ;
270301 let orig_wtxid = tx. compute_wtxid ( ) ;
271302 let orig_weight = tx. weight ( ) . to_wu ( ) ;
272303 assert_eq ! ( orig_weight / 4 , 61 ) ;
273304
274305 assert_eq ! ( Builder :: new( ) . push_int( 2 ) . into_script( ) . minimal_non_dust( ) . to_sat( ) , 474 ) ;
275306
276307 // 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( ) ) ;
278- assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // Failure doesn't change the transaction
308+ let amount = Amount :: from_sat ( 1000 + 61 + 100 - 1 ) ;
309+ let script = Builder :: new ( ) . push_int ( 2 ) . into_script ( ) ;
310+ assert ! ( maybe_add_change_output( & mut tx, amount, 400 , 250 , script) . is_err( ) ) ;
311+ // Failure doesn't change the transaction
312+ assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ;
279313 // 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( ) ) ;
281- assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // If we don't add an output, we don't change the transaction
314+ let amount = Amount :: from_sat ( 1000 + 61 + 100 ) ;
315+ let script = Builder :: new ( ) . push_int ( 2 ) . into_script ( ) ;
316+ assert ! ( maybe_add_change_output( & mut tx, amount, 400 , 250 , script) . is_ok( ) ) ;
317+ // If we don't add an output, we don't change the transaction
318+ assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ;
282319 // 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( ) ) ;
284- assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // If we don't add an output, we don't change the transaction
285-
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( ) ) ;
320+ let amount = Amount :: from_sat ( 1000 + 61 + 100 + 474 + 9 ) ;
321+ let script = Builder :: new ( ) . push_int ( 2 ) . into_script ( ) ;
322+ assert ! ( maybe_add_change_output( & mut tx, amount, 400 , 250 , script) . is_ok( ) ) ;
323+ // If we don't add an output, we don't change the transaction
324+ assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ;
325+
326+ let amount = Amount :: from_sat ( 1000 + 61 + 100 + 474 + 10 ) ;
327+ let script = Builder :: new ( ) . push_int ( 2 ) . into_script ( ) ;
328+ assert ! ( maybe_add_change_output( & mut tx, amount, 400 , 250 , script) . is_ok( ) ) ;
287329 assert_eq ! ( tx. output. len( ) , 2 ) ;
288330 assert_eq ! ( tx. output[ 1 ] . value. to_sat( ) , 474 ) ;
289331 assert_eq ! ( tx. output[ 1 ] . script_pubkey, Builder :: new( ) . push_int( 2 ) . into_script( ) ) ;
290- assert_eq ! ( tx. weight( ) . to_wu( ) - orig_weight, 40 ) ; // Weight difference matches what we had to add above
332+ // Weight difference matches what we had to add above
333+ assert_eq ! ( tx. weight( ) . to_wu( ) - orig_weight, 40 ) ;
291334 tx. output . pop ( ) ;
292- assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ; // The only change is the addition of one output.
335+ // The only change is the addition of one output.
336+ assert_eq ! ( tx. compute_wtxid( ) , orig_wtxid) ;
293337 }
294338}
0 commit comments