@@ -926,8 +926,8 @@ pub const fn predict_weight_from_slices(
926926/// associated constants/methods.
927927#[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
928928pub struct InputWeightPrediction {
929- script_size : usize ,
930- witness_size : usize ,
929+ script_size : u32 ,
930+ witness_size : u32 ,
931931}
932932
933933impl InputWeightPrediction {
@@ -990,6 +990,23 @@ impl InputWeightPrediction {
990990 /// [`InputWeightPrediction::new`].
991991 pub const P2TR_KEY_NON_DEFAULT_SIGHASH : Self = InputWeightPrediction :: from_slice ( 0 , & [ 65 ] ) ;
992992
993+ const fn saturate_to_u32 ( x : usize ) -> u32 {
994+ if x > u32:: MAX as usize {
995+ u32:: MAX
996+ } else {
997+ x as u32 //cast ok, condition prevents larger than u32::MAX.
998+ }
999+ }
1000+
1001+ const fn encoded_size ( value : usize ) -> u32 {
1002+ match value {
1003+ 0 ..=0xFC => 1 ,
1004+ 0xFD ..=0xFFFF => 3 ,
1005+ 0x10000 ..=0xFFFFFFFF => 5 ,
1006+ _ => 9 ,
1007+ }
1008+ }
1009+
9931010 /// Input weight prediction corresponding to spending of P2WPKH output using [signature
9941011 /// grinding].
9951012 ///
@@ -1059,16 +1076,17 @@ impl InputWeightPrediction {
10591076 T :: Item : Borrow < usize > ,
10601077 {
10611078 let ( count, total_size) = witness_element_lengths. into_iter ( ) . fold (
1062- ( 0usize , 0 ) ,
1079+ ( 0usize , 0u32 ) ,
10631080 |( count, total_size) , elem_len| {
10641081 let elem_len = * elem_len. borrow ( ) ;
1065- let elem_size = elem_len + compact_size:: encoded_size ( elem_len) ;
1066- ( count + 1 , total_size + elem_size)
1082+ let elem_size =
1083+ Self :: saturate_to_u32 ( elem_len) . saturating_add ( Self :: encoded_size ( elem_len) ) ;
1084+ ( count + 1 , total_size. saturating_add ( elem_size) )
10671085 } ,
10681086 ) ;
1069- let witness_size =
1070- if count > 0 { total_size + compact_size :: encoded_size ( count ) } else { 0 } ;
1071- let script_size = input_script_len + compact_size :: encoded_size ( input_script_len) ;
1087+ let witness_size = if count > 0 { total_size + Self :: encoded_size ( count ) } else { 0 } ;
1088+ let script_size =
1089+ Self :: saturate_to_u32 ( input_script_len) + Self :: encoded_size ( input_script_len) ;
10721090
10731091 InputWeightPrediction { script_size, witness_size }
10741092 }
@@ -1080,33 +1098,40 @@ impl InputWeightPrediction {
10801098 /// `new` and thus is intended to be only used in `const` context.
10811099 pub const fn from_slice ( input_script_len : usize , witness_element_lengths : & [ usize ] ) -> Self {
10821100 let mut i = 0 ;
1083- let mut total_size = 0 ;
1101+ let mut total_size: u32 = 0 ;
10841102 // for loops not supported in const fn
10851103 while i < witness_element_lengths. len ( ) {
10861104 let elem_len = witness_element_lengths[ i] ;
1087- let elem_size = elem_len + compact_size:: encoded_size_const ( elem_len as u64 ) ;
1088- total_size += elem_size;
1105+ let elem_size =
1106+ Self :: saturate_to_u32 ( elem_len) . saturating_add ( Self :: encoded_size ( elem_len) ) ;
1107+ total_size = total_size. saturating_add ( elem_size) ;
10891108 i += 1 ;
10901109 }
10911110 let witness_size = if !witness_element_lengths. is_empty ( ) {
1092- total_size + compact_size :: encoded_size_const ( witness_element_lengths. len ( ) as u64 )
1111+ total_size. saturating_add ( Self :: encoded_size ( witness_element_lengths. len ( ) ) )
10931112 } else {
10941113 0
10951114 } ;
1096- let script_size =
1097- input_script_len + compact_size :: encoded_size_const ( input_script_len as u64 ) ;
1115+ let script_size = Self :: saturate_to_u32 ( input_script_len )
1116+ . saturating_add ( Self :: encoded_size ( input_script_len) ) ;
10981117
10991118 InputWeightPrediction { script_size, witness_size }
11001119 }
11011120
11021121 /// Computes the **signature weight** added to a transaction by an input with this weight prediction,
11031122 /// not counting the prevout (txid, index), sequence, potential witness flag bytes or the witness count varint.
1123+ ///
1124+ /// This function's internal arithmetic saturates at u32::MAX, so the return value of this
1125+ /// function may be inaccurate for extremely large witness predictions.
11041126 #[ deprecated( since = "TBD" , note = "use `InputWeightPrediction::witness_weight()` instead" ) ]
11051127 pub const fn weight ( & self ) -> Weight { Self :: witness_weight ( self ) }
11061128
11071129 /// Computes the signature, prevout (txid, index), and sequence weights of this weight
11081130 /// prediction.
11091131 ///
1132+ /// This function's internal arithmetic saturates at u32::MAX, so the return value of this
1133+ /// function may be inaccurate for extremely large witness predictions.
1134+ ///
11101135 /// See also [`InputWeightPrediction::witness_weight`]
11111136 pub const fn total_weight ( & self ) -> Weight {
11121137 // `impl const Trait` is currently unavailable: rust/issues/67792
@@ -1117,6 +1142,9 @@ impl InputWeightPrediction {
11171142
11181143 /// Computes the **signature weight** added to a transaction by an input with this weight prediction,
11191144 /// not counting the prevout (txid, index), sequence, potential witness flag bytes or the witness count varint.
1145+ ///
1146+ /// This function's internal arithmetic saturates at u32::MAX, so the return value of this
1147+ /// function may be inaccurate for extremely large witness predictions.
11201148 ///
11211149 /// See also [`InputWeightPrediction::total_weight`]
11221150 pub const fn witness_weight ( & self ) -> Weight {
@@ -1140,31 +1168,23 @@ mod sealed {
11401168#[ cfg( feature = "arbitrary" ) ]
11411169impl < ' a > Arbitrary < ' a > for InputWeightPrediction {
11421170 fn arbitrary ( u : & mut Unstructured < ' a > ) -> arbitrary:: Result < Self > {
1143- // limit script size to 4Mwu block size.
1144- let max_block = Weight :: MAX_BLOCK . to_wu ( ) as usize ;
1145- let input_script_len = u. int_in_range ( 0 ..=max_block) ?;
1146- let remaining = max_block - input_script_len;
1147-
1148- // create witness data if there is remaining space.
1149- let mut witness_length = u. int_in_range ( 0 ..=remaining) ?;
1150- let mut witness_element_lengths = Vec :: new ( ) ;
1151-
1152- // build vec of random witness element lengths.
1153- while witness_length > 0 {
1154- let elem = u. int_in_range ( 1 ..=witness_length) ?;
1155- witness_element_lengths. push ( elem) ;
1156- witness_length -= elem;
1157- }
1158-
11591171 match u. int_in_range ( 0 ..=7 ) ? {
11601172 0 => Ok ( InputWeightPrediction :: P2WPKH_MAX ) ,
11611173 1 => Ok ( InputWeightPrediction :: NESTED_P2WPKH_MAX ) ,
11621174 2 => Ok ( InputWeightPrediction :: P2PKH_COMPRESSED_MAX ) ,
11631175 3 => Ok ( InputWeightPrediction :: P2PKH_UNCOMPRESSED_MAX ) ,
11641176 4 => Ok ( InputWeightPrediction :: P2TR_KEY_DEFAULT_SIGHASH ) ,
11651177 5 => Ok ( InputWeightPrediction :: P2TR_KEY_NON_DEFAULT_SIGHASH ) ,
1166- 6 => Ok ( InputWeightPrediction :: new ( input_script_len, witness_element_lengths) ) ,
1167- _ => Ok ( InputWeightPrediction :: from_slice ( input_script_len, & witness_element_lengths) ) ,
1178+ 6 => {
1179+ let input_script_len = usize:: arbitrary ( u) ?;
1180+ let witness_element_lengths: Vec < usize > = Vec :: arbitrary ( u) ?;
1181+ Ok ( InputWeightPrediction :: new ( input_script_len, witness_element_lengths) )
1182+ }
1183+ _ => {
1184+ let input_script_len = usize:: arbitrary ( u) ?;
1185+ let witness_element_lengths: Vec < usize > = Vec :: arbitrary ( u) ?;
1186+ Ok ( InputWeightPrediction :: from_slice ( input_script_len, & witness_element_lengths) )
1187+ }
11681188 }
11691189 }
11701190}
0 commit comments