ParaInherent
This module is responsible for providing all data given to the runtime by the block author to the various parachains modules. The entry-point is mandatory, in that it must be invoked exactly once within every block, and it is also "inherent", in that it is provided with no origin by the block author. The data within it carries its own authentication; i.e. the data takes the form of signed statements by validators. If any of the steps within fails, the entry-point is considered as having failed and the block will be invalid.
This module does not have the same initialization/finalization concerns as the others, as it only requires that entry points be triggered after all modules have initialized and that finalization happens after entry points are triggered. Both of these are assumptions we have already made about the runtime's order of operations, so this module doesn't need to be initialized or finalized by the Initializer
.
There are a couple of important notes to the operations in this inherent as they relate to disputes.
- We don't accept bitfields or backed candidates if in "governance-only" mode from having a local dispute conclude on this fork.
- When disputes are initiated, we remove the block from pending availability. This allows us to roll back chains to the block before blocks are included as opposed to backing. It's important to do this before processing bitfields.
Inclusion::collect_disputed
is kind of expensive so it's important to gate this on whether there are actually any new disputes. Which should be never.- And we don't accept parablocks that have open disputes or disputes that have concluded against the candidate. It's important to import dispute statements before backing, but this is already the case as disputes are imported before processing bitfields.
Storage
#![allow(unused)] fn main() { /// Whether the para inherent was included or not. Included: Option<()>, }
#![allow(unused)] fn main() { /// Scraped on chain votes to be used in disputes off-chain. OnChainVotes: Option<ScrapedOnChainVotes>, }
Finalization
- Take (get and clear) the value of
Included
. If it is notSome
, throw an unrecoverable error.
Entry Points
-
enter
: This entry-point accepts one parameter:ParaInherentData
.- Ensure the origin is none.
- Ensure
Included
is set asNone
. - Set
Included
asSome
. - Unpack
ParachainsInherentData
intosigned_bitfields
,backed_candidates
,parent_header
, anddisputes
. - Hash the parent header and make sure that it corresponds to the block hash of the parent (tracked by the
frame_system
FRAME module). - Calculate the
candidate_weight
,bitfields_weight
, anddisputes_weight
. - If the sum of
candidate_weight
,bitfields_weight
, anddisputes_weight
is greater than the max block weight we do the following with the goal of prioritizing the inclusion of disputes without making it game-able by block authors:- clear
bitfields
and setbitfields_weight
equal to 0. - clear
backed_candidates
and setcandidate_weight
equal to 0. - invoke
limit_disputes
on thedisputes
with the max block weight iff the disputes weight is greater than the max block weight.
- clear
- Invoke
Disputes::provide_multi_dispute_data
. - If
Disputes::is_frozen
, return. - If there are any concluded disputes from the current session, invoke
Inclusion::collect_disputed
with the disputed candidates. Annotate each returned core withFreedReason::Concluded
, sort them, and invokeScheduler::free_cores
with them. - The
Bitfields
are first forwarded to theInclusion::process_bitfields
routine, returning a set included candidates and the respective freed cores. Provide the number of availability cores (Scheduler::availability_cores().len()
) as the expected number of bits and aScheduler::core_para
as a core-lookup to theprocess_bitfields
routine. Annotate each of these freed cores withFreedReason::Concluded
. - For each freed candidate from the
Inclusion::process_bitfields
call, invokeDisputes::note_included(current_session, candidate)
. - If
Scheduler::availability_timeout_predicate
isSome
, invokeInclusion::collect_pending
using it and annotate each of those freed cores withFreedReason::TimedOut
. - Combine and sort the the bitfield-freed cores and the timed-out cores.
- Invoke
Scheduler::clear
- Invoke
Scheduler::schedule(freed_cores, System::current_block())
- Extract
parent_storage_root
from the parent header, - If
Disputes::concluded_invalid(current_session, candidate)
is true for any of thebacked_candidates
, fail. - Invoke the
Inclusion::process_candidates
routine with the parameters(parent_storage_root, backed_candidates, Scheduler::scheduled(), Scheduler::group_validators)
. - Deconstruct the returned
ProcessedCandidates
value intooccupied
core indices, and backing validators by candidatebacking_validators_per_candidate
represented byVec<(CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>)>
. - Set
OnChainVotes
toScrapedOnChainVotes
, based on thecurrent_session
, concludeddisputes
, andbacking_validators_per_candidate
. - Call
Scheduler::occupied
using theoccupied
core indices of the returned above, first sorting the list of assigned core indices. - Call the
Ump::process_pending_upward_messages
routine to execute all messages in upward dispatch queues. - If all of the above succeeds, set
Included
toSome(())
.
-
create_inherent
: This entry-point accepts one parameter:InherentData
.- Invoke
create_inherent_inner(InherentData)
, the unit testable logic for filtering and sanitzing the inherent data used when invokingenter
. Save the result asinherent_data
. - If the
inherent_data
is anErr
variant, return theenter
call signature with all inherent data cleared else return theenter
call signature withinherent_data
passed in as thedata
param.
- Invoke
Routines
create_inherent_inner(data: &InherentData) -> Option<ParachainsInherentData<T::Header>>
- Unpack
InherentData
into its parts,bitfields
,backed_candidates
,disputes
and theparent_header
. If data cannot be unpacked returnNone
. - Hash the
parent_header
and make sure that it corresponds to the block hash of the parent (tracked by theframe_system
FRAME module). - Invoke
Disputes::filter_multi_dispute_data
to remove duplicates et al fromdisputes
. - Run the following within a
with_transaction
closure to avoid side effects (we are essentially replicating the logic that would otherwise happen withinenter
so we can get the filtered bitfields and theconcluded_invalid_disputes
+scheduled
to use in filtering thebacked_candidates
.): - Invoke
Disputes::provide_multi_dispute_data
. - Collect
current_concluded_invalid_disputes
, the disputed candidate hashes from the current session that have concluded invalid. - Collect
concluded_invalid_disputes
, the disputed candidate hashes from the givenbacked_candidates
. - Invoke
Inclusion::collect_disputed
with the newly disputed candidates. Annotate each returned core withFreedReason::Concluded
, sort them, and invokeScheduler::free_cores
with them. - Collect filtered
bitfields
by invokingsanitize_bitfields<false>
. - Collect
freed_concluded
by invokingupdate_pending_availability_and_get_freed_cores
on the filtered bitfields. - Collect all
freed
cores by invokingcollect_all_freed_cores
onfreed_concluding
. - Invoke
scheduler::Pallet<T>>::clear()
. - Invoke
scheduler::Pallet<T>>::schedule
withfreed
and the current block number to create the same schedule of the cores thatenter
will create. - Read the new
<scheduler::Pallet<T>>::scheduled()
intoschedule
. - From the
with_transaction
closure returnconcluded_invalid_disputes
,bitfields
, andscheduled
. - Invoke
sanitize_backed_candidates
using thescheduled
return from thewith_transaction
and pass the closure|candidate_hash: CandidateHash| -> bool { DisputesHandler::concluded_invalid(current_session, candidate_hash) }
for the paramcandidate_has_concluded_invalid_dispute
. - create a
rng
fromrand_chacha::ChaChaRng::from_seed(compute_entropy::<T>(parent_hash))
. - Invoke
limit_disputes
with the max block weight andrng
, storing the returned weigh inremaining_weight
. - Fill up the remaining of the block weight with backed candidates and bitfields by invoking
apply_weight_limit
withremaining_weigh
andrng
. - Return
Some(ParachainsInherentData { bitfields, backed_candidates, disputes, parent_header }
.
- Unpack