6464 }
6565 }
6666
67- /// Checks if the current extrinsic can fit into the block with respect to block weight limits.
68- ///
69- /// Upon successes, it returns the new block weight as a `Result`.
70- fn check_block_weight (
71- info : & DispatchInfoOf < T :: RuntimeCall > ,
72- ) -> Result < crate :: ConsumedWeight , TransactionValidityError > {
73- let maximum_weight = T :: BlockWeights :: get ( ) ;
74- let all_weight = Pallet :: < T > :: block_weight ( ) ;
75- calculate_consumed_weight :: < T :: RuntimeCall > ( maximum_weight, all_weight, info)
76- }
77-
7867 /// Checks if the current extrinsic can fit into the block with respect to block length limits.
7968 ///
8069 /// Upon successes, it returns the new block length as a `Result`.
@@ -113,7 +102,12 @@ where
113102 len : usize ,
114103 ) -> Result < ( ) , TransactionValidityError > {
115104 let next_len = Self :: check_block_length ( info, len) ?;
116- let next_weight = Self :: check_block_weight ( info) ?;
105+
106+ let all_weight = Pallet :: < T > :: block_weight ( ) ;
107+ let maximum_weight = T :: BlockWeights :: get ( ) ;
108+ let next_weight =
109+ calculate_consumed_weight :: < T :: RuntimeCall > ( & maximum_weight, all_weight, info) ?;
110+ check_combined_proof_size ( & maximum_weight, next_len, & next_weight) ?;
117111 Self :: check_extrinsic_weight ( info) ?;
118112
119113 crate :: AllExtrinsicsLen :: < T > :: put ( next_len) ;
@@ -136,8 +130,32 @@ where
136130 }
137131}
138132
133+ /// Check that the combined extrinsic length and proof size together do not exceed the PoV limit.
134+ pub fn check_combined_proof_size (
135+ maximum_weight : & BlockWeights ,
136+ next_len : u32 ,
137+ next_weight : & crate :: ConsumedWeight ,
138+ ) -> Result < ( ) , TransactionValidityError > {
139+ // This extra check ensures that the extrinsic length does not push the
140+ // PoV over the limit.
141+ let total_pov_size = next_weight. total ( ) . proof_size ( ) . saturating_add ( next_len as u64 ) ;
142+ if total_pov_size > maximum_weight. max_block . proof_size ( ) {
143+ log:: debug!(
144+ target: LOG_TARGET ,
145+ "Extrinsic exceeds total pov size: {}kb, limit: {}kb" ,
146+ total_pov_size as f64 /1024.0 ,
147+ maximum_weight. max_block. proof_size( ) as f64 /1024.0
148+ ) ;
149+ return Err ( InvalidTransaction :: ExhaustsResources . into ( ) )
150+ }
151+ Ok ( ( ) )
152+ }
153+
154+ /// Checks if the current extrinsic can fit into the block with respect to block weight limits.
155+ ///
156+ /// Upon successes, it returns the new block weight as a `Result`.
139157pub fn calculate_consumed_weight < Call > (
140- maximum_weight : BlockWeights ,
158+ maximum_weight : & BlockWeights ,
141159 mut all_weight : crate :: ConsumedWeight ,
142160 info : & DispatchInfoOf < Call > ,
143161) -> Result < crate :: ConsumedWeight , TransactionValidityError >
@@ -742,17 +760,90 @@ mod tests {
742760
743761 // when
744762 assert_ok ! ( calculate_consumed_weight:: <<Test as Config >:: RuntimeCall >(
745- maximum_weight. clone ( ) ,
763+ & maximum_weight,
746764 all_weight. clone( ) ,
747- & mandatory1
765+ & mandatory1,
748766 ) ) ;
749767 assert_err ! (
750768 calculate_consumed_weight:: <<Test as Config >:: RuntimeCall >(
751- maximum_weight,
769+ & maximum_weight,
752770 all_weight,
753- & mandatory2
771+ & mandatory2,
754772 ) ,
755773 InvalidTransaction :: ExhaustsResources
756774 ) ;
757775 }
776+
777+ #[ test]
778+ fn maximum_proof_size_includes_length ( ) {
779+ let maximum_weight = BlockWeights :: builder ( )
780+ . base_block ( Weight :: zero ( ) )
781+ . for_class ( DispatchClass :: non_mandatory ( ) , |w| {
782+ w. base_extrinsic = Weight :: zero ( ) ;
783+ w. max_total = Some ( Weight :: from_parts ( 20 , 10 ) ) ;
784+ } )
785+ . for_class ( DispatchClass :: Mandatory , |w| {
786+ w. base_extrinsic = Weight :: zero ( ) ;
787+ w. reserved = Some ( Weight :: from_parts ( 5 , 10 ) ) ;
788+ w. max_total = None ;
789+ } )
790+ . build_or_panic ( ) ;
791+
792+ assert_eq ! ( maximum_weight. max_block, Weight :: from_parts( 20 , 10 ) ) ;
793+
794+ // We have 10 reftime and 5 proof size left over.
795+ let next_weight = crate :: ConsumedWeight :: new ( |class| match class {
796+ DispatchClass :: Normal => Weight :: from_parts ( 10 , 5 ) ,
797+ DispatchClass :: Operational => Weight :: from_parts ( 0 , 0 ) ,
798+ DispatchClass :: Mandatory => Weight :: zero ( ) ,
799+ } ) ;
800+
801+ // Simple checks for the length
802+ assert_ok ! ( check_combined_proof_size( & maximum_weight, 0 , & next_weight) ) ;
803+ assert_ok ! ( check_combined_proof_size( & maximum_weight, 5 , & next_weight) ) ;
804+ assert_err ! (
805+ check_combined_proof_size( & maximum_weight, 6 , & next_weight) ,
806+ InvalidTransaction :: ExhaustsResources
807+ ) ;
808+
809+ // We have 10 reftime and 0 proof size left over.
810+ let next_weight = crate :: ConsumedWeight :: new ( |class| match class {
811+ DispatchClass :: Normal => Weight :: from_parts ( 10 , 10 ) ,
812+ DispatchClass :: Operational => Weight :: from_parts ( 0 , 0 ) ,
813+ DispatchClass :: Mandatory => Weight :: zero ( ) ,
814+ } ) ;
815+ assert_ok ! ( check_combined_proof_size( & maximum_weight, 0 , & next_weight) ) ;
816+ assert_err ! (
817+ check_combined_proof_size( & maximum_weight, 1 , & next_weight) ,
818+ InvalidTransaction :: ExhaustsResources
819+ ) ;
820+
821+ // We have 10 reftime and 2 proof size left over.
822+ // Used weight is spread across dispatch classes this time.
823+ let next_weight = crate :: ConsumedWeight :: new ( |class| match class {
824+ DispatchClass :: Normal => Weight :: from_parts ( 10 , 5 ) ,
825+ DispatchClass :: Operational => Weight :: from_parts ( 0 , 3 ) ,
826+ DispatchClass :: Mandatory => Weight :: zero ( ) ,
827+ } ) ;
828+ assert_ok ! ( check_combined_proof_size( & maximum_weight, 0 , & next_weight) ) ;
829+ assert_ok ! ( check_combined_proof_size( & maximum_weight, 2 , & next_weight) ) ;
830+ assert_err ! (
831+ check_combined_proof_size( & maximum_weight, 3 , & next_weight) ,
832+ InvalidTransaction :: ExhaustsResources
833+ ) ;
834+
835+ // Ref time is over the limit. Should not happen, but we should make sure that it is
836+ // ignored.
837+ let next_weight = crate :: ConsumedWeight :: new ( |class| match class {
838+ DispatchClass :: Normal => Weight :: from_parts ( 30 , 5 ) ,
839+ DispatchClass :: Operational => Weight :: from_parts ( 0 , 0 ) ,
840+ DispatchClass :: Mandatory => Weight :: zero ( ) ,
841+ } ) ;
842+ assert_ok ! ( check_combined_proof_size( & maximum_weight, 0 , & next_weight) ) ;
843+ assert_ok ! ( check_combined_proof_size( & maximum_weight, 5 , & next_weight) ) ;
844+ assert_err ! (
845+ check_combined_proof_size( & maximum_weight, 6 , & next_weight) ,
846+ InvalidTransaction :: ExhaustsResources
847+ ) ;
848+ }
758849}
0 commit comments