@@ -19,7 +19,7 @@ use std::{
19
19
} ;
20
20
21
21
use crypto:: key:: { PrivateKey , PublicKey , Signature } ;
22
- use serialization:: Encode ;
22
+ use serialization:: { CompactLen , Encode } ;
23
23
24
24
use crate :: chain:: {
25
25
classic_multisig:: ClassicMultisigChallenge ,
@@ -40,6 +40,8 @@ use crate::chain::{
40
40
pub enum SizeEstimationError {
41
41
#[ error( "Unsupported input destination" ) ]
42
42
UnsupportedInputDestination ( Destination ) ,
43
+ #[ error( "Attempted to estimate the size of a TX with too many inputs or outputs {0}" ) ]
44
+ TooManyElements ( usize ) ,
43
45
}
44
46
45
47
/// Return the encoded size of an input signature.
@@ -194,31 +196,40 @@ pub fn input_signature_size_from_destination(
194
196
195
197
/// Return the encoded size for a SignedTransaction also accounting for the compact encoding of the
196
198
/// vectors for the specified number of inputs and outputs
197
- pub fn tx_size_with_num_inputs_and_outputs ( num_outputs : usize , num_inputs : usize ) -> usize {
198
- #[ derive( Encode ) ]
199
- struct CompactSize {
200
- #[ codec( compact) ]
201
- value : u64 ,
199
+ pub fn tx_size_with_num_inputs_and_outputs (
200
+ num_outputs : usize ,
201
+ num_inputs : usize ,
202
+ ) -> Result < usize , SizeEstimationError > {
203
+ lazy_static:: lazy_static! {
204
+ static ref EMPTY_SIGNED_TX_SIZE : usize = {
205
+ let tx = SignedTransaction :: new(
206
+ Transaction :: new( 1 , vec![ ] , vec![ ] ) . expect( "should not fail" ) ,
207
+ vec![ ] ,
208
+ )
209
+ . expect( "should not fail" ) ;
210
+ serialization:: Encode :: encoded_size( & tx)
211
+ } ;
212
+ }
213
+ lazy_static:: lazy_static! {
214
+ static ref ZERO_COMPACT_SIZE : usize = {
215
+ serialization:: Compact :: <u32 >:: compact_len( & 0 )
216
+ } ;
202
217
}
203
218
204
- let tx = SignedTransaction :: new (
205
- Transaction :: new ( 1 , vec ! [ ] , vec ! [ ] ) . expect ( "should not fail" ) ,
206
- vec ! [ ] ,
207
- )
208
- . expect ( "should not fail" ) ;
209
- let size = serialization:: Encode :: encoded_size ( & tx) ;
210
-
211
- let input_compact_size_diff =
212
- serialization:: Encode :: encoded_size ( & CompactSize {
213
- value : num_inputs as u64 ,
214
- } ) - serialization:: Encode :: encoded_size ( & CompactSize { value : 0 } ) ;
219
+ let input_compact_size_diff = serialization:: Compact :: < u32 > :: compact_len (
220
+ & ( num_inputs
221
+ . try_into ( )
222
+ . map_err ( |_| SizeEstimationError :: TooManyElements ( num_inputs) ) ?) ,
223
+ ) - * ZERO_COMPACT_SIZE ;
215
224
216
- let output_compact_size_diff =
217
- serialization:: Encode :: encoded_size ( & CompactSize {
218
- value : num_outputs as u64 ,
219
- } ) - serialization:: Encode :: encoded_size ( & CompactSize { value : 0 } ) ;
225
+ let output_compact_size_diff = serialization:: Compact :: < u32 > :: compact_len (
226
+ & ( num_outputs
227
+ . try_into ( )
228
+ . map_err ( |_| SizeEstimationError :: TooManyElements ( num_inputs) ) ?) ,
229
+ ) - * ZERO_COMPACT_SIZE ;
220
230
221
- size + output_compact_size_diff + ( input_compact_size_diff * 2 ) // 2 for number of inputs and number of input signatures
231
+ // 2 for number of inputs and number of input signatures
232
+ Ok ( * EMPTY_SIGNED_TX_SIZE + output_compact_size_diff + ( input_compact_size_diff * 2 ) )
222
233
}
223
234
224
235
pub fn outputs_encoded_size ( outputs : & [ TxOutput ] ) -> usize {
@@ -241,3 +252,6 @@ fn get_tx_output_destination(txo: &TxOutput) -> Option<&Destination> {
241
252
| TxOutput :: CreateOrder ( _) => None ,
242
253
}
243
254
}
255
+
256
+ #[ cfg( test) ]
257
+ mod tests;
0 commit comments