Skip to content

Commit

Permalink
Backport 1.12.0: check-weight: Disable total pov size check for manda…
Browse files Browse the repository at this point in the history
…tory extrinsics (#4592)

Backport of #4571

---------

Co-authored-by: command-bot <>
  • Loading branch information
skunert authored May 27, 2024
1 parent b401690 commit d3bf1a8
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 20 deletions.
17 changes: 17 additions & 0 deletions prdoc/1.12.0/pr_4571.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json

title: Ignore mandatory extrinsics in total PoV size check

doc:
- audience: Runtime Dev
description: |
The `CheckWeight` extension is checking that extrinsic length and used storage proof
weight together do not exceed the PoV size limit. This lead to problems when
the PoV size was already reached before mandatory extrinsics were applied.The `CheckWeight`
extension will now allow extrinsics of `DispatchClass::Mandatory` to be applied even if
the limit is reached.

crates:
- name: frame-system
bump: minor
130 changes: 110 additions & 20 deletions substrate/frame/system/src/extensions/check_weight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::{limits::BlockWeights, Config, Pallet, LOG_TARGET};
use crate::{limits::BlockWeights, Config, DispatchClass, Pallet, LOG_TARGET};
use codec::{Decode, Encode};
use frame_support::{
dispatch::{DispatchInfo, PostDispatchInfo},
Expand Down Expand Up @@ -107,7 +107,7 @@ where
let maximum_weight = T::BlockWeights::get();
let next_weight =
calculate_consumed_weight::<T::RuntimeCall>(&maximum_weight, all_weight, info)?;
check_combined_proof_size(&maximum_weight, next_len, &next_weight)?;
check_combined_proof_size::<T::RuntimeCall>(info, &maximum_weight, next_len, &next_weight)?;
Self::check_extrinsic_weight(info)?;

crate::AllExtrinsicsLen::<T>::put(next_len);
Expand All @@ -131,22 +131,31 @@ where
}

/// Check that the combined extrinsic length and proof size together do not exceed the PoV limit.
pub fn check_combined_proof_size(
pub fn check_combined_proof_size<Call>(
info: &DispatchInfoOf<Call>,
maximum_weight: &BlockWeights,
next_len: u32,
next_weight: &crate::ConsumedWeight,
) -> Result<(), TransactionValidityError> {
) -> Result<(), TransactionValidityError>
where
Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
{
// This extra check ensures that the extrinsic length does not push the
// PoV over the limit.
let total_pov_size = next_weight.total().proof_size().saturating_add(next_len as u64);
if total_pov_size > maximum_weight.max_block.proof_size() {
log::debug!(
target: LOG_TARGET,
"Extrinsic exceeds total pov size: {}kb, limit: {}kb",
"Extrinsic exceeds total pov size. Still including if mandatory. size: {}kb, limit: {}kb, is_mandatory: {}",
total_pov_size as f64/1024.0,
maximum_weight.max_block.proof_size() as f64/1024.0
maximum_weight.max_block.proof_size() as f64/1024.0,
info.class == DispatchClass::Mandatory
);
return Err(InvalidTransaction::ExhaustsResources.into())
return match info.class {
// Allow mandatory extrinsics
DispatchClass::Mandatory => Ok(()),
_ => Err(InvalidTransaction::ExhaustsResources.into()),
};
}
Ok(())
}
Expand Down Expand Up @@ -190,7 +199,7 @@ where
"Exceeded the per-class allowance.",
);

return Err(InvalidTransaction::ExhaustsResources.into())
return Err(InvalidTransaction::ExhaustsResources.into());
},
// There is no `max_total` limit (`None`),
// or we are below the limit.
Expand All @@ -208,7 +217,7 @@ where
"Total block weight is exceeded.",
);

return Err(InvalidTransaction::ExhaustsResources.into())
return Err(InvalidTransaction::ExhaustsResources.into());
},
// There is either no limit in reserved pool (`None`),
// or we are below the limit.
Expand Down Expand Up @@ -791,6 +800,8 @@ mod tests {

assert_eq!(maximum_weight.max_block, Weight::from_parts(20, 10));

let info = DispatchInfo { class: DispatchClass::Normal, ..Default::default() };
let mandatory = DispatchInfo { class: DispatchClass::Mandatory, ..Default::default() };
// We have 10 reftime and 5 proof size left over.
let next_weight = crate::ConsumedWeight::new(|class| match class {
DispatchClass::Normal => Weight::from_parts(10, 5),
Expand All @@ -799,24 +810,61 @@ mod tests {
});

// Simple checks for the length
assert_ok!(check_combined_proof_size(&maximum_weight, 0, &next_weight));
assert_ok!(check_combined_proof_size(&maximum_weight, 5, &next_weight));
assert_ok!(check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&info,
&maximum_weight,
0,
&next_weight
));
assert_ok!(check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&info,
&maximum_weight,
5,
&next_weight
));
assert_err!(
check_combined_proof_size(&maximum_weight, 6, &next_weight),
check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&info,
&maximum_weight,
6,
&next_weight
),
InvalidTransaction::ExhaustsResources
);
assert_ok!(check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&mandatory,
&maximum_weight,
6,
&next_weight
));

// We have 10 reftime and 0 proof size left over.
let next_weight = crate::ConsumedWeight::new(|class| match class {
DispatchClass::Normal => Weight::from_parts(10, 10),
DispatchClass::Operational => Weight::from_parts(0, 0),
DispatchClass::Mandatory => Weight::zero(),
});
assert_ok!(check_combined_proof_size(&maximum_weight, 0, &next_weight));
assert_ok!(check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&info,
&maximum_weight,
0,
&next_weight
));
assert_err!(
check_combined_proof_size(&maximum_weight, 1, &next_weight),
check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&info,
&maximum_weight,
1,
&next_weight
),
InvalidTransaction::ExhaustsResources
);
assert_ok!(check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&mandatory,
&maximum_weight,
1,
&next_weight
));

// We have 10 reftime and 2 proof size left over.
// Used weight is spread across dispatch classes this time.
Expand All @@ -825,12 +873,33 @@ mod tests {
DispatchClass::Operational => Weight::from_parts(0, 3),
DispatchClass::Mandatory => Weight::zero(),
});
assert_ok!(check_combined_proof_size(&maximum_weight, 0, &next_weight));
assert_ok!(check_combined_proof_size(&maximum_weight, 2, &next_weight));
assert_ok!(check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&info,
&maximum_weight,
0,
&next_weight
));
assert_ok!(check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&info,
&maximum_weight,
2,
&next_weight
));
assert_err!(
check_combined_proof_size(&maximum_weight, 3, &next_weight),
check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&info,
&maximum_weight,
3,
&next_weight
),
InvalidTransaction::ExhaustsResources
);
assert_ok!(check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&mandatory,
&maximum_weight,
3,
&next_weight
));

// Ref time is over the limit. Should not happen, but we should make sure that it is
// ignored.
Expand All @@ -839,11 +908,32 @@ mod tests {
DispatchClass::Operational => Weight::from_parts(0, 0),
DispatchClass::Mandatory => Weight::zero(),
});
assert_ok!(check_combined_proof_size(&maximum_weight, 0, &next_weight));
assert_ok!(check_combined_proof_size(&maximum_weight, 5, &next_weight));
assert_ok!(check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&info,
&maximum_weight,
0,
&next_weight
));
assert_ok!(check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&info,
&maximum_weight,
5,
&next_weight
));
assert_err!(
check_combined_proof_size(&maximum_weight, 6, &next_weight),
check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&info,
&maximum_weight,
6,
&next_weight
),
InvalidTransaction::ExhaustsResources
);
assert_ok!(check_combined_proof_size::<<Test as Config>::RuntimeCall>(
&mandatory,
&maximum_weight,
6,
&next_weight
));
}
}

0 comments on commit d3bf1a8

Please sign in to comment.