This repository has been archived by the owner on Nov 15, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Fix issues with Operational
transactions validity and prioritization.
#6435
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1394,8 +1394,10 @@ impl<T: Trait + Send + Sync> CheckWeight<T> where | |
info: &DispatchInfoOf<T::Call>, | ||
) -> Result<(), TransactionValidityError> { | ||
match info.class { | ||
// Mandatory and Operational transactions does not | ||
DispatchClass::Mandatory | DispatchClass::Operational => Ok(()), | ||
// Mandatory transactions are included in a block unconditionally, so | ||
// we don't verify weight. | ||
DispatchClass::Mandatory => Ok(()), | ||
// Normal transactions must not exceed `MaximumExtrinsicWeight`. | ||
DispatchClass::Normal => { | ||
let maximum_weight = T::MaximumExtrinsicWeight::get(); | ||
let extrinsic_weight = info.weight.saturating_add(T::ExtrinsicBaseWeight::get()); | ||
|
@@ -1404,7 +1406,22 @@ impl<T: Trait + Send + Sync> CheckWeight<T> where | |
} else { | ||
Ok(()) | ||
} | ||
} | ||
}, | ||
// For operational transactions we make sure it doesn't exceed | ||
// the space alloted for `Operational` class. | ||
DispatchClass::Operational => { | ||
let maximum_weight = T::MaximumBlockWeight::get(); | ||
let operational_limit = | ||
Self::get_dispatch_limit_ratio(DispatchClass::Operational) * maximum_weight; | ||
let operational_limit = | ||
operational_limit.saturating_sub(T::BlockExecutionWeight::get()); | ||
let extrinsic_weight = info.weight.saturating_add(T::ExtrinsicBaseWeight::get()); | ||
if extrinsic_weight > operational_limit { | ||
Err(InvalidTransaction::ExhaustsResources.into()) | ||
} else { | ||
Ok(()) | ||
} | ||
}, | ||
} | ||
} | ||
|
||
|
@@ -1483,9 +1500,11 @@ impl<T: Trait + Send + Sync> CheckWeight<T> where | |
fn get_priority(info: &DispatchInfoOf<T::Call>) -> TransactionPriority { | ||
match info.class { | ||
DispatchClass::Normal => info.weight.into(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just tagging the related issue to this funny line: #5672 Probably not a problem that needs to be solved now |
||
DispatchClass::Operational => Bounded::max_value(), | ||
// Don't use up the whole priority space, to allow things like `tip` | ||
// to be taken into account as well. | ||
DispatchClass::Operational => TransactionPriority::max_value() / 2, | ||
gui1117 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Mandatory extrinsics are only for inherents; never transactions. | ||
DispatchClass::Mandatory => Bounded::min_value(), | ||
DispatchClass::Mandatory => TransactionPriority::min_value(), | ||
} | ||
} | ||
|
||
|
@@ -2451,6 +2470,42 @@ pub(crate) mod tests { | |
}); | ||
} | ||
|
||
#[test] | ||
fn operational_extrinsic_limited_by_operational_space_limit() { | ||
new_test_ext().execute_with(|| { | ||
let operational_limit = CheckWeight::<Test>::get_dispatch_limit_ratio( | ||
DispatchClass::Operational | ||
) * <Test as Trait>::MaximumBlockWeight::get(); | ||
let base_weight = <Test as Trait>::ExtrinsicBaseWeight::get(); | ||
let block_base = <Test as Trait>::BlockExecutionWeight::get(); | ||
|
||
let weight = operational_limit - base_weight - block_base; | ||
let okay = DispatchInfo { | ||
weight, | ||
class: DispatchClass::Operational, | ||
..Default::default() | ||
}; | ||
let max = DispatchInfo { | ||
weight: weight + 1, | ||
class: DispatchClass::Operational, | ||
..Default::default() | ||
}; | ||
let len = 0_usize; | ||
|
||
assert_eq!( | ||
CheckWeight::<Test>::do_validate(&okay, len), | ||
Ok(ValidTransaction { | ||
priority: CheckWeight::<Test>::get_priority(&okay), | ||
..Default::default() | ||
}) | ||
); | ||
assert_noop!( | ||
CheckWeight::<Test>::do_validate(&max, len), | ||
InvalidTransaction::ExhaustsResources | ||
); | ||
}); | ||
} | ||
|
||
#[test] | ||
fn register_extra_weight_unchecked_doesnt_care_about_limits() { | ||
new_test_ext().execute_with(|| { | ||
|
@@ -2478,6 +2533,8 @@ pub(crate) mod tests { | |
assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&rest_operational, len)); | ||
assert_eq!(<Test as Trait>::MaximumBlockWeight::get(), 1024); | ||
assert_eq!(System::block_weight().total(), <Test as Trait>::MaximumBlockWeight::get()); | ||
// Checking single extrinsic should not take current block weight into account. | ||
assert_eq!(CheckWeight::<Test>::check_extrinsic_weight(&rest_operational), Ok(())); | ||
}); | ||
} | ||
|
||
|
@@ -2513,6 +2570,8 @@ pub(crate) mod tests { | |
assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&dispatch_operational, len)); | ||
// Not too much though | ||
assert_noop!(CheckWeight::<Test>::do_pre_dispatch(&dispatch_operational, len), InvalidTransaction::ExhaustsResources); | ||
// Even with full block, validity of single transaction should be correct. | ||
assert_eq!(CheckWeight::<Test>::check_extrinsic_weight(&dispatch_operational), Ok(())); | ||
}); | ||
} | ||
|
||
|
@@ -2558,7 +2617,7 @@ pub(crate) mod tests { | |
.validate(&1, CALL, &op, len) | ||
.unwrap() | ||
.priority; | ||
assert_eq!(priority, u64::max_value()); | ||
assert_eq!(priority, u64::max_value() / 2); | ||
}) | ||
} | ||
|
||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This calculation is missing
BaseBlockWeight
if we want to be entirely accurate.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if a transaction satisfies this but can actually never be included because check_block_weight always fails ? Is that an issue like the transaction will stay forever in the queue ?
Because in the moment I guess it also doesn't include the minimum cost of OnInitialize.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, if it's immortal.
Good point. With
Normal
dispatchables, we have a separate parameter that allows to control the max size when runtime is created. I guess it might make sense to lift it up forOperational
as well and define as like90%
of max block weight or sth.