-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Add after_inherents
#14414
base: master
Are you sure you want to change the base?
Add after_inherents
#14414
Conversation
Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
From what I can say, we must be fine with it as there is no other way, unless if we want to leak the concept of I don't think it is particularly horrible to do that. Not suggesting we leak Or even more broadly, the runtime would return a The client would indeed need to know the This can also help relax the strict need that Inherents must always be first (can't find the discussion, but was talked about recently -- cc @thiolliere). They can appear at any point in the block, and as long as their significance is higher than what All of this can also be backwards compatible, as by returning 255 or 0 you can block all or nothing, which is basically the current behavior. Truthfully, I don't think you should block this PR or MBM for what I am saying, but I hope to give you ideas to refactor the API to something a bit clearer in the long run. Right now, it seems like we are just adding APIs that fix the problem right in front of us and nothing more. |
Okay now i understood how that should work, because i did not from the other comment alone, thanks 😆 Nothing to add so far. Hopefully it is possible in |
In general I don't see the need why
Not sure why you want this? Finally we start coming up with a proper way of ensuring that certain operations are not executed before |
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.
Yeah, I don't really see a need to let after_inherents
return some value. We should just handle this by "artificially" using all weight of the block. Then there is no need to add all these extra checks that you have introduced.
Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
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.
looks correct to me.
without approve
solely to draw in engineers who are more experienced in this topic.
primitives/runtime/src/lib.rs
Outdated
/// All logic is allowed to run. | ||
/// | ||
/// For example: | ||
/// - Extrinsics with dispatch class `Normal`. | ||
/// - `on_idle` hook. | ||
Normal, | ||
/// Only _necessary_ logic is allowed to run. | ||
/// | ||
/// Explicitly forbidden are: | ||
/// - Extrinsics with dispatch classes `Normal` and `Operational`. | ||
/// - `on_idle` and `poll` hooks. | ||
/// | ||
/// Explicitly allowed are: | ||
/// - Mandatory extrinsics (i.e. via OCW). | ||
/// - `on_initialize` and `on_finalize` hooks. | ||
/// - Storage migrations. | ||
/// | ||
/// Everything in between is to be judged by the runtime. | ||
Minimal, |
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.
I do like Normal
and Minimal
(or could be System
). it's not only about non-inherents inclusion, but also about hooks and could be more in the future. More generic names with documentation looks like more flexible approach here. My five cents.
Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
frame/executive/src/lib.rs
Outdated
} | ||
|
||
/// Same as `apply_extrinsic` but gets the `mode` directly passed in. | ||
pub fn apply_extrinsic_with_mode( |
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.
pub fn apply_extrinsic_with_mode( | |
fn apply_extrinsic_with_mode( |
might help the readability of this file if we only make the things used in the runtime public, and even name them such that it is clear in which API they are meant to be used eg pub fn block_builder_finalze_block()
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.
I will make them private otherwise, yes. Not sure if we should do the renaming though. WDYT @bkchr?
return Err(InvalidTransaction::BadMandatory.into()) | ||
} | ||
if mode == ExtrinsicInclusionMode::OnlyInherents && !mandatory { | ||
// Note: The block builder should never try to do this. |
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.
Why? imagine we are running MBMs, and there is some non-mandatory inherent (of which we currently don't have an example, but it could exist).
It seems like ExtrinsicInclusionMode::OnlyInherents
is actually ExtrinsicInclusionMode::OnlyMandatoryInherents
? 🙈
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.
There could still be optional inherents, the blockbuilder would just omit them.
Mandatory has two meanings that can get mixed up here: Mandatory in the sense of being infallible and Mandatory in the sense that it needs to execute in every block. We can still have optional inherents that are non-mandatory in the second sense by letting the blockbuilder omit them.
But having an inherents that can fail is not quite useful i think. LMK if you meant something else 😄
Not sure about the OnlyMandatoryInherents
, maybe but since there are no non-mandatory it is not adding any information, or?
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.
Code is solid, but I think the namings we are using here are prone to becoming a puzzle for our future selves, or even worse, others to understand this code.
If no better option exists, I suggest putting some extra documentation about the known behavior of this entire system once the MBM system is final.
If you are breaking the core and blockbuilder apis anyway, maybe this is a good time to move See https://substrate.stackexchange.com/questions/3128/why-is-initialize-block-in-the-core-runtime-api-as-opposed-to-blockbuilder for details. |
Yes i actually did that in the MR, but then reverted it since we cannot keep backwards compatibility by completely removing a runtime API function. Normally we have this |
Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
The CI pipeline was cancelled due to failure one of the required jobs. |
Adds an
after_inherents
function to theBlockBuilder
runtime API. The function is not exposed as hook to the pallets. (Preparation for the MBMs, as requested here)after_inherents
is invoked after Inherents and before any Transaction processing.It returns
RuntimeExecutiveMode
which decides whether Transactions can be included in this block. The BlockBuilder respects this return value and includes only inherents otherwise.frame-executive
refuses to import a block whenafter_inherents
returnsTransactionsForbidden
but transactions are present. This is done by changingensure_inherents_are_first
to return the number of inherents and comparing that with the number of extrinsics in the block.Changes:
after_inherents
to Runtime APIBlockBuilder
.initialize_block
from Runtime APICore
to returnRuntimeExecutiveMode
.TransactionsForbidden
toEndProposingReason
.frame-executive
tests to own file.ensure_inherents_are_first
return the number of inherents.execute_extrinsics_with_book_keeping
toapply_extrinsic
and add aapply_extrinsic_with_mode
variant.Integration
Add it to your runtime implementation of
Core
andBlockBuilder
:TODO
try-runtime
still works