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