pallet_chain_manager/types.rs
1// SPDX-License-Identifier: MPL-2.0
2//
3// Part of Auguth Labs open-source softwares.
4// Built for the Substrate framework.
5//
6// This Source Code Form is subject to the terms of the Mozilla Public
7// License, v. 2.0. If a copy of the MPL was not distributed with this
8// file, You can obtain one at https://mozilla.org/MPL/2.0/.
9//
10// Copyright (c) 2026 Auguth Labs (OPC) Pvt Ltd, India
11
12// ===============================================================================
13// ````````````````````````````` CHAIN MANAGER TYPES `````````````````````````````
14// ===============================================================================
15
16//! **Core types and aliases for the Chain Manager system.**
17//!
18//! This module primarily defines **type aliases**, **public structs**, and
19//! **runtime-specialized unsigned payloads** used across
20//! [`pallet_chain_manager`](crate).
21//!
22//! The Chain Manager relies on external trait adapters such as:
23//! - [`Config::RoleAdapter`]
24//! - [`Config::ElectionAdapter`]
25//! - [`Config::Asset`] (fungible-adapter)
26//! - [`Config::PointsAdapter`]
27//!
28//! These abstractions delegate core logic to other pallets/framework layers,
29//! while the types in this module provide a **unified, runtime-bound view**
30//! and are used in the pallet's **public APIs**.
31//!
32//! Raw unsigned payload types are defined in [`crate::crypto`], but it is
33//! recommended to use the aliases here to ensure correct runtime binding
34//! to offchain signing types.
35//!
36//! ## Example
37//!
38//! ```ignore
39//! use pallet_chain_manager::types::ElectionPayloadOf;
40//!
41//! let payload = ElectionPayloadOf::<T> { ... };
42//! SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(
43//! Call::elect { payload }.into()
44//! );
45//! ```
46
47// ===============================================================================
48// ``````````````````````````````````` IMPORTS ```````````````````````````````````
49// ===============================================================================
50
51// --- Local crate imports ---
52use crate::{crypto::*, Config};
53
54// --- Scale-codec crates ---
55use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
56use scale_info::TypeInfo;
57
58// --- FRAME Suite ---
59use frame_suite::{elections::*, roles::*, routines::Moment};
60
61// --- FRAME Support ---
62use frame_support::{
63 pallet_prelude::TransactionPriority, traits::fungible::Inspect, RuntimeDebugNoBound,
64};
65
66// --- FRAME System ---
67use frame_system::{offchain::SigningTypes, pallet_prelude::BlockNumberFor};
68
69// --- Substrate primitives ---
70use sp_core::RuntimeDebug;
71use sp_runtime::{Perbill, Permill, Vec};
72
73// ===============================================================================
74// ``````````````````````````````````` ALIASES ```````````````````````````````````
75// ===============================================================================
76
77/// The `AccountId` type representing an author in this runtime.
78///
79/// Acts as the primary key for tracking points, rewards, penalties, and election data.
80pub type AuthorOf<T> = <T as frame_system::pallet::Config>::AccountId;
81
82/// The asset type associated with an author-role.
83///
84/// Used for funding, collateral, rewarding or penalizing authors and backers.
85pub type AssetOf<T> = <<T as Config>::RoleAdapter as RoleManager<AuthorOf<T>>>::Asset;
86
87/// Timestamp associated with an author role for various operations
88/// such as deffered rewards and penalities
89pub type AuthorTimeStampOf<T> = <<T as Config>::RoleAdapter as RoleManager<AuthorOf<T>>>::TimeStamp;
90
91/// Type representing an entity or account backing an author, as managed by [`FundRoles`].
92///
93/// - Typically used to track external funding, sponsorship, or support for authors.
94/// - Allows pallets to query or interact with the backing source of an author.
95pub type BackerOf<T> = <<T as Config>::RoleAdapter as FundRoles<AuthorOf<T>>>::Backer;
96
97/// The concrete fungible balance type of the asset associated with an author.
98///
99/// Represents the fungible units that can be rewarded, or penalized.
100///
101/// This is ensured to be [`AssetOf`] where `AssetOf == ActualAsset` enforced
102/// via [`Config::Asset`]
103pub type ActualAsset<T> = <<T as Config>::Asset as Inspect<AuthorOf<T>>>::Balance;
104
105/// Represents a singular election weight of numerous weights holded by the author.
106///
107/// Raw or intermediate election metric type
108pub type ElectionWeight<T> =
109 <<T as Config>::ElectionAdapter as ElectionManager<AuthorOf<T>>>::ElectionWeight;
110
111/// Type representing the election weight of an author.
112///
113/// - Used to rank, score, or prioritize authors in elections.
114/// - Typically derived from participation, stake, or other metrics.
115/// - Serves as the primary metric for electing authors.
116pub type ElectionVia<T> =
117 <<T as Config>::ElectionAdapter as ElectionManager<AuthorOf<T>>>::ElectionWeightOf;
118
119/// Parameters for configuring an election i.e, the input authors and their
120/// corresponding election weight.
121pub type ElectionParams<T> =
122 <<T as Config>::ElectionAdapter as ElectionManager<AuthorOf<T>>>::Params;
123
124/// Set of authors successfully elected by the author-role election module.
125///
126/// - Can be iterated over to assign points, rewards, or responsibilities.
127/// - Typically used to determine which authors are active for a reward cycle
128/// or session.
129pub type ElectionElects<T> =
130 <<T as Config>::ElectionAdapter as ElectionManager<AuthorOf<T>>>::Elected;
131
132/// Represents a **collection of authors and their ephemeral points**
133/// (e.g., block producer points) for a single reward cycle.
134///
135/// - Each entry is `(Author, Points)`.
136/// - Serves as input to the [`Config::RewardModel`] plugin to compute per-author payouts.
137/// - Points are temporary and cleared after the cycle.
138pub type PayoutFor<T> = Vec<(AuthorOf<T>, <T as Config>::Points)>;
139
140/// Represents a **collection of authors and their final rewards**
141/// for a given reward cycle.
142///
143/// - Each entry is `(Author, Asset)`.
144/// - Produced by the [`Config::RewardModel`] plugin after distributing total payout
145/// based on ephemeral points.
146/// - Used to execute the actual reward transfers or minting.
147pub type PayeeList<T> = Vec<(AuthorOf<T>, AssetOf<T>)>;
148
149/// Represents a **single penalty as a proportion** of a total value.
150///
151/// - Uses [`PerThing`](sp_runtime::PerThing) to allow fine-grained fractional penalties.
152/// - Ideal for proportional deductions from author-risked assets for block-production.
153/// - Ensures consistency and flexibility across different asset scales.
154pub type PenaltyOf<T> = <<T as Config>::RoleAdapter as CompensateRoles<AuthorOf<T>>>::Ratio;
155
156/// Collection of authors and their proportional penalties for a given cycle.
157///
158/// - Each entry represents `(Author, PenaltyOf)`.
159/// - Input for [`Config::PenaltyModel`] plugin and output for transformed penalties.
160/// - Supports multiple penalties applied in a single cycle.
161pub type PenaltyFor<T> = Vec<(AuthorOf<T>, PenaltyOf<T>)>;
162
163/// Represents the index of a block production session.
164///
165/// - Typically increments with each session in the runtime.
166/// - Used to track author activity, points, rewards, or penalties per session.
167pub type SessionIndex = sp_staking::SessionIndex;
168
169/// Type alias for the **Validator ID** used by [`pallet_session`].
170///
171/// In the context of elections, candidate authors are mapped to this type
172/// to interact with the session pallet (e.g., for validator set queries or election participation).
173pub type SessionId<T> = <T as pallet_session::Config>::ValidatorId;
174
175/// Type alias representing an **offending validator** in session history.
176pub type Offender<T> = pallet_session::historical::IdentificationTuple<T>;
177
178/// Type alias representing the **reporting account** that detected the offence.
179pub type OffenceReporter<T> = <T as frame_system::Config>::AccountId;
180
181/// The **runtime-storable identifier** of an affidavit key.
182///
183/// This represents the public identity of an affidavit key **as stored on-chain**.
184/// While application crypto operates on raw public keys, the runtime persists
185/// this identifier in the runtime's `AccountId` format for consistency and
186/// interoperability with other pallets.
187pub type AffidavitId<T> = <T as frame_system::pallet::Config>::AccountId;
188
189/// Type representing **relative session duration**.
190///
191/// Used to define timing of affidavit and election phases
192/// as a fraction of the current session.
193///
194/// Interpreted as a percentage ([`PerThing`](sp_runtime::PerThing)) of session length:
195///
196/// `block = session_start + (Duration * session_length)`
197pub type Duration = Permill;
198
199/// Type representing the **penalty ratio** applied to a author for
200/// bad-behaviour.
201///
202/// Expressed as a [`Perbill`], aligning with
203/// [`OnOffenceHandler`](sp_staking::offence::OnOffenceHandler)
204/// which applies penalties directly using per-bill fractions.
205pub type PenaltyRatio = Perbill;
206
207// ===============================================================================
208// `````````````````````````````````` ROUTINES ```````````````````````````````````
209// ===============================================================================
210
211/// Operational context for **affidavit key initialization**.
212///
213/// This type represents the contextual information required to initialize
214/// or recover an affidavit key during the key lifecycle.
215///
216/// Affidavit keys are **ephemeral, operational keys** that are rotated
217/// independently of long-term authority, stash, or consensus keys.
218/// Initialization may execute sequentially multiple times as a looped
219/// routine (e.g. via offchain workers), and therefore requires an explicit,
220/// lightweight context object.
221///
222/// ## Notes
223/// - This is **not a transaction payload**.
224/// - This type is never submitted on-chain.
225/// - It is used internally during:
226/// - affidavit key generation
227/// - key recovery
228/// - keystore initialization or repair
229///
230/// ## Fork Awareness
231/// - The `at` field captures the block number at which the initialization
232/// process begins.
233/// - When executed via offchain workers, this context must tolerate
234/// forks, re-orgs, and speculative execution.
235/// - Implementors are responsible for ensuring idempotency and re-entrancy safety.
236///
237/// ## Initialization Flow
238///
239/// The process repeatedly attempts to resolve a affidavit key-pair. It
240/// self-heals by creating and inserting keys when missing, and retries
241/// on missing or error states until a consistent state is reached.
242///
243/// ## Pseudocode
244///
245/// ```ignore
246/// loop {
247/// // Fetch the tagged active affidavit from offchain storage
248/// match offchain_storage.fetch_active_affidavit() {
249/// Ok(None) => {
250/// // No active-tagged affidavit-key exists -> create a new key-pair locally
251/// keystore.create_affidavit_key();
252///
253/// // Publish the key reference to offchain storage
254/// offchain_storage.insert_affidavit_key();
255/// continue;
256/// }
257/// Ok(Some(affidavit)) => {
258/// // A active-tagged affidavit exists -> ensure the local key-pair is present
259/// match keystore.get_affidavit_key() {
260/// Some(key) => break key,
261/// None => {
262/// // Storage provided public key, but its actual key-pair
263/// // is missing locally -> repair
264/// keystore.create_affidavit_key();
265/// continue;
266/// }
267/// }
268/// }
269/// Ok(Some(_other_status)) => continue,
270/// Err(_storage_error) => continue, // transient storage error -> retry
271/// }
272/// }
273/// ```
274///
275/// ## Guarantee
276///
277/// This process yields an active affidavit key **only when** its tagged/referenced
278/// via an offchain storage and its corresponding the key-pair exists in the
279/// local keystore. Otherwise, it creates/repairs the key and keeps retrying
280/// until the affidavit becomes tagged and the keystore is consistent.
281///
282/// ```ignore
283/// loop {
284/// if offchain_storage.has_affidavit_key()
285/// && keystore.has_affidavit_key()
286/// {
287/// break;
288/// }
289///
290/// keystore.create_or_repair_affidavit_key();
291/// offchain_storage.ensure_affidavit_key_reference();
292/// // retry until next key reaches consistency
293/// }
294/// ```
295///
296/// All behavior is supplied by trait implementations operating on this type.
297///
298/// ## FlowChart
299///
300/// [](https://mermaid.live/edit#pako:eNqFUsFu2zAM_RWBpwxIMseNPUeHAVnaDsWwtWh72ryDYjO2MFsOZDldmuTfR1lxWjfAqoNEkXyP5JN2kFQpAodVUT0ludCGPV7GKlaM1oOh-68Y2pOzGyXNfLWSqdhI8w23gw8x_O5y62aZabHOWQynHEZJLUqKQj4LIysVg0u3K5UaE-tkj19evNdokpyKtiebU8IG2Qvl4MFUWmTI7pplIRNbwrXR4RcahUEicAb7gU-s39FgobdrUzHLhH3wjaqxHdkZb4Hv1f6KVheC36PREnuNv1P5HkVqkT3A6E5IzeYbIQuxLPAEQJV2ul-plFC0c6IwjVbnkhHRq4dqH5ONRp-d0p3byU3u_XdZ11Jl-6OSLnwU08KcNM59lOk_bNdVo9L9URkXdPbraDv8WfCskbfcV1pXmn1ktyZHbQczTb3vN9Iyt_2RRDCETMsUuNENDqFEXQp7hZ1NjoFoShKZk5kK_cf-1QNh1kL9rKqyg-mqyXLgK1HUdGvWKfV2KQX9_vLk1fRCqBc0nQHu-9OWBPgO_gKfzcZ-MJ14QeBPonASfRrCFnh0MY4u_Cj0oij0Z14QHYbw3Fb1xmEQTYNgQtHIm4bT2eEfZkQtCQ)
301///
302#[derive(Encode, Decode, Clone, MaxEncodedLen, TypeInfo, PartialEq, Eq)]
303#[scale_info(skip_type_params(T))]
304pub(crate) struct InitAffidavitKey<T: Config> {
305 /// Block number at which affidavit key initialization begins.
306 ///
307 /// Used for logging, diagnostics, and fork-aware coordination.
308 pub at: BlockNumberFor<T>,
309}
310
311/// Operational context for **election transaction execution**.
312///
313/// This type represents the contextual information required to attempt
314/// authors election using an affidavit key during the routine lifecycle.
315///
316/// Election attempts are **optimistic, sequential routines** that may execute
317/// repeatedly as part of a looped execution model (e.g. via offchain workers).
318/// Although election typically follows the affidavit declaration phase,
319/// explicit looping of sequential routines allows this phase to run earlier.
320/// The routine remains safe, as successful election is gated by retrievable
321/// storage state, election window constraints, and eligibility checks.
322///
323/// ## Notes
324/// - This is **not a transaction payload**.
325/// - This type is never submitted on-chain.
326/// - It is used internally during:
327/// - fetching the active-tagged affidavit key (storage-reference + keystore-pair)
328/// - election payload signing using the affidavit key pair
329/// - submission of the `elect` extrinsic
330/// - retry-driven OCW election execution
331///
332/// ## Fork Awareness
333/// - The `at` field captures the block number at which the election
334/// attempt begins.
335/// - When executed via offchain workers, this context must tolerate
336/// forks, re-orgs, and speculative execution.
337/// - Implementors are responsible for ensuring idempotency and
338/// re-entrancy safety.
339///
340/// ## Dependency: [`InitAffidavitKey`]
341///
342/// This routine depends on the affidavit key initialization phase.
343/// It assumes that a active-tagged (offchain storage referenced) affidavit key
344/// and its pair in crypto-store is available. Whenever this invariant is violated
345/// (e.g. missing key, failed signing, or inconsistent state), control is redirected
346/// to [`InitAffidavitKey`] to repair and re-validate the key before retrying the
347/// election attempt.
348///
349/// ## Election Flow
350///
351/// The routine fetches the active-tagged affidavit key-pair (referenced via
352/// offchain storage and retrieved through local keystore), then attempts
353/// author election. It short-circuits when outside the election window, when
354/// ineligible, or when already elected (to avoid redundancy). Failures or
355/// inconsistencies re-enter the affidavit initialization phase for re-validation
356/// and repair.
357///
358/// ```ignore
359/// loop {
360/// // Ensure active-tagged affidavit key is available
361/// InitAffidavitKey::ensure_active_affidavit_key();
362///
363/// // Fetch affidavit key pair (offchain storage reference + keystore-pair)
364/// let key_pair = fetch_affidavit_key_pair();
365///
366/// if !within_election_window()
367/// || !eligible_to_elect()
368/// || already_elected()
369/// {
370/// break; // proceed to declaration phase (no election required)
371/// }
372///
373/// let payload = Default::default();
374///
375/// match sign_payload_with(key_pair)
376/// .and_then(|payload| submit_elect_authors_extrinsic(payload))
377/// {
378/// Ok(_) => break, // elect-phase completed successfully
379/// Err(_) => continue, // retry via initialization phase again
380/// }
381/// }
382/// ```
383///
384/// ## Guarantees
385///
386/// This routine proceeds to the affidavit declaration phase under
387/// exactly two conditions:
388///
389/// 1. **Initialization-only path**: a active-tagged affidavit key-pair
390/// exists, but election constraints are not satisfied (outside window,
391/// ineligible, or already elected).
392///
393/// 2. **Election-complete path**: a active-tagged affidavit key-pair
394/// exists, election constraints are satisfied, and the `elect`
395/// extrinsic is successfully submitted.
396///
397/// In all other cases, the routine retries by re-entering the affidavit
398/// key initialization phase to re-validate offchain storage and
399/// keystore consistency.
400///
401/// All behavior is supplied by trait implementations operating on this type.
402///
403/// ## FlowChart
404///
405/// [](https://mermaid.live/edit#pako:eNp9VG1r2zAQ_itCMGhZ0sZ5cVMzOkKbQhmMsBTKNo-hWBdb1JGDLKdNk_z3naTYiZ0wf7Hke-65l-fOGxplHGhA52n2FiVMafL8EMpQEnymGu-_Q2rfAXlW63EKkRaZvLgM6Z8S9ukTabfbZDSfC85WQpNvsCZPUmjBUvHBDJ5MEpaDgTmXvJjFii0TC8MI__O1kcj-ebpPIHrdHHtMilkqIuv4Zaau7z6bY64zBWTChCKjFRMpm6XwNaS7I6YfsEQzBr9XwDSQa-K-GHdLxCQnY5kXSDRFOhYDIuagQEZwJims7m77PduWzOa-NzkoSN5omWunjMmo0Emm8jMNshBMsgmtJTBC0woQ9Qg6SupK2FIuqsTbphTgpNGlyxrfi5A8e8MuvwidCElK2feGeiPHqYgFtndjknRHojPnU0eOUuw0Xxv13MmBgNdhUxFLM3X4OkSesHWaMe6qWQnWGLfTGqbFbGFnyx0OTM-KyZzZs2Mbv2slZC6igIAB_WWuxQe-I-XGkpuRySSKUdhCHyBKmYKjgTSzfrofbgVsdGETqcS2-3UyLkdT9RPy7V7ksxOEZI-4vwdGh7WUTrLSzd2qUR2bwhrfbbBSyarsUtkTz5rFJerELV1LrQ_cpeuxxXAaxat_j1HfGKZFFEGObk7HhvURdxsXdFt1bm93mp9FNOwVv02LtmisBKeBVgW06ALUgpkr3RjHkOoEFqhtgEfO1GtIQ7lDnyWTv7JsUbqprIgTGsxZmuOtWHL8vzwIhhu9qL7iNnJQ91khNQ36fd-S0GBD32ngXfU7vW63e9Pvdwd-f9gbtOiaBm3P7115veHAH3Y6Pa93O7jZteiHDexdDX2v43WHnaHnebd939_9A4zO3PM)
406///
407#[derive(Encode, Decode, Clone, MaxEncodedLen, TypeInfo, RuntimeDebug, PartialEq, Eq)]
408#[scale_info(skip_type_params(T))]
409pub(crate) struct TryElection<T: Config> {
410 /// Public key authorized to sign election transactions.
411 pub by: T::Public,
412
413 /// Block number at which election execution is initiated.
414 pub at: BlockNumberFor<T>,
415}
416
417/// Operational context for **affidavit declaration and key rotation**.
418///
419/// This type represents the contextual information required to declare
420/// an affidavit using the active affidavit key and rotate it to the next key
421/// during the routine lifecycle.
422///
423/// Declaration is a **sequential, retry-driven routine** that executes as part
424/// of the looped offchain workflow. It is entered only after the initialization
425/// phase guarantees that a active-tagged affidavit key-pair is available, and
426/// after the election phase has either completed successfully or been safely
427/// skipped due to unmet constraints.
428///
429/// ## Notes
430/// - This is **not a transaction payload**.
431/// - This type is never submitted on-chain.
432/// - It is used internally during:
433/// - next affidavit key resolution
434/// - declaration payload composition (including next public key for rotation)
435/// - payload signing using the active affidavit key-pair
436/// - submission of the declare-affidavit extrinsic
437///
438/// ## Dependency: [`InitAffidavitKey`] and optimistic [`TryElection`]
439///
440/// This routine has a hard dependency on the initialization phase and a
441/// soft (optimistic) dependency on the election phase.
442///
443/// It requires that:
444/// - a *active-tagged* affidavit key exists in offchain storage and
445/// the its key-pair in local keystore (guaranteed by [`InitAffidavitKey`]), and
446/// - election has either completed successfully or has been safely skipped
447/// due to unmet constraints.
448///
449/// Election may execute before declaration as part of the global retry loop,
450/// but its outcome does not directly gate declaration correctness. However,
451/// failures during election invalidate system invariants and therefore
452/// redirect control back to [`InitAffidavitKey`] for repair and re-validation
453/// before declaration is retried.
454///
455/// ## Fork Awareness
456/// - The `at` field captures the block number at which the declaration
457/// process begins.
458/// - When executed via offchain workers, this context must tolerate
459/// forks, re-orgs, and speculative execution.
460/// - Implementors must ensure idempotency and re-entrancy safety.
461///
462/// ## Declaration Flow
463///
464/// The routine fetches the active-tagged affidavit key-pair, resolves the
465/// next affidavit key (mirroring the affidavit-key-initialization logic),
466/// verifies the declaration window and eligibility, composes the declaration
467/// payload along with the next affidavit public key, signs it with the active
468/// affidavit key-pair, and submits the declaration transaction to rotate the
469/// active affidavit key to next affidavit key.
470///
471/// Failures or inconsistencies re-enter the initialization phase to
472/// re-validate offchain storage and keystore invariants.
473///
474/// ```ignore
475/// loop {
476/// // Ensure active-tagged affidavit key-pair is available
477/// InitAffidavitKey::ensure_active_affidavit_key();
478///
479/// // Fetch affidavit key pair (offchain storage reference + keystore-pair)
480/// let key_pair = fetch_affidavit_key_pair();
481
482/// // Attempt election optimistically; failure requires repair + retry
483/// if TryElection::attempt_election_if_applicable().is_err() {
484/// continue; // re-enter initialization phase
485/// }
486///
487/// // Resolve next affidavit key using the offchain-storage references +
488/// // keystore pair consistency guarantees as InitAffidavitKey
489/// if !offchain_storage.has_next_affidavit_key()
490/// || !keystore.has_next_affidavit_key()
491/// {
492/// keystore.create_or_repair_next_affidavit_key();
493/// offchain_storage.ensure_next_affidavit_key_reference();
494/// continue; // retry until next key reaches consistency
495/// }
496///
497/// let next_key_to_rotate = fetch_next_affidavit_key();
498///
499/// if !within_affidavit_window() || !eligible_to_declare() {
500/// continue; // retry via initialization phase
501/// }
502///
503/// let payload = compose_declare_affidavit_payload(next_key_to_rotate);
504///
505/// match sign_payload_with(key_pair)
506/// .and_then(|payload| submit_declare_affidavit_extrinsic(payload)) {
507/// Ok(_) => break, // declaration + rotation completed
508/// Err(_) => continue, // retry via initialization phase
509/// }
510/// }
511/// ```
512///
513/// ## Guarantee
514///
515/// This routine declares the affidavit and rotates the active key
516/// **only when**:
517/// - a active-tagged affidavit key-pair is available,
518/// - the next affidavit key is initiated and present in the local keystore,
519/// - declaration window and eligibility constraints are satisfied,
520/// - and the declaration transaction is successfully submitted.
521///
522/// In all other cases, the routine retries by re-entering the affidavit
523/// key initialization phase to repair and re-validate offchain storage
524/// and keystore consistency.
525///
526/// All behavior is supplied by trait implementations operating on this type.
527///
528/// ## FlowChart
529///
530/// [](https://mermaid.live/edit#pako:eNqlVdtuGzcQ_RWCQAILsRLZli1bKBIYsgwYQV3DEhC0VZFQuyMt4RUpkFxbiuX3_kn_q1_S4WVv2k2QInrRkpw5Mzwzc_hMIxkDHdJFKp-ihClDplczMRMEfxOD6z9n1P0PyRVEKVNwuVjwmD1yc9CZ0b9y21evSLfbJcUh-QhbciO44SzlX5nhUlgDb6yz-VKxdeIMMMD3vFwMEn43owSih2f0iAx_hL1wv8zVu_dv7Kc2UgG5Y1yRy0fGUzZP4cOMvlSQ7mGNxxh8pIAZIO-I3yEBGlEcHhMxGQudId4EUdkS0HABCkQELbnhJd_vbuUuD2DX4cibgoj3OBungCHFklxmJpFKt_DkTDDXfdNaAuOcHG-FhI-k0EYxLowmE2RTLzjEH9y1Dj5xEcsn8u_f_yA6X3JkyC1upcELxpmImTCdGmfj6cZ2QzZfIeFfwEb5zHwiX8h4YxQXmkdFTs2b-g5y-eeF0-TAlu5eGt8jdwppU-6700LELWwsD6EVK_V_HTyhgKpx44uKntdgooS0tY-npVHjmOx1VKcO7HlE1j9xk3BRwfQn9ba7zLl2ZQq0G5nPljcuze11XcZF5nbne3nfZfOUR3a_nqf1851etvy3sEZqu8acLCQ0UW6EBicL_uOnMroHbBpwhck__0dWJdZIrtZSu6v5r5zQbgl0x7apZLEHuxFRmsWNYGWuZCFV0Ur1xCd8Kewc4F8d9JGzinq0NIsfnatyiJp9PFVMaBbVGrgySGMRo7cz4m5ekBGXZSnLLnTCNDTVeSyM2pZT5XS9JlA1awdCylgVYapo3e-gd0F6Kv6FBK2ZSXTIvXSa0VuZF6Iq9l0p0q3zQeJ2gcyGtw853YSD6SZgTrIoAq09cJ5BN8KOSAHbvR02eF_jK4Eav2tS4Wvk1enJi2ZkTcKtQsEti8W0Vrxdgz1gSRRomWYO5WDFlbJCz-vvYyqXPOp41wLLZfcr1xplc1cZ4yJiGMO9BJoY1xI1fVcbuzazsU0NX8PfTALKtojJdAsrhWC_JnFJUAlYjHMldNBKEogLq-LBrDyS1TNX7UI3w3mhna3etVPnH2ThG_kV9FZRciWxxNpZDzNjp976hGbb5UO9d9zop8r8_5ABKSPg0NNDulQ8pkOjMjikK1ArZpf02TrOKBZrhQM_xM-YqYcZnYkX9Fkz8YeUq9xNyWyZ0OGCpRpX2TrGPrriDJ_WVbGLj14MaoQVM3R4dHzWcyh0-Ew3uD7vvz09HfTwd3J60Ts5GhzSLR1e4O7g9GzQG5wcn_f7g8HLIf3q4vbeXvRxC83P-r3z_tHx4OU_ZolmWg)
531///
532#[derive(Encode, Decode, Clone, MaxEncodedLen, RuntimeDebug, TypeInfo, PartialEq, Eq)]
533#[scale_info(skip_type_params(T))]
534pub(crate) struct DeclareAffidavit<T: Config> {
535 /// Raw application public key identifying the affidavit key-pair
536 /// in the local keystore.
537 pub by: T::Public,
538
539 /// Block number at which the affidavit declaration process started.
540 ///
541 /// Used exclusively for logging and diagnostic purposes.
542 pub at: BlockNumberFor<T>,
543}
544
545/// Operational context for **affidavit key rotation**.
546///
547/// This type represents the contextual information required to observe
548/// and commence rotation of the affidavit key, promoting the previously
549/// prepared *next* key to become the active affidavit key once the
550/// declaration effects are finalized.
551///
552/// Rotation is a **sequential, retry-driven routine** that executes as part
553/// of the looped offchain workflow. It is entered only after the declaration
554/// phase has submitted the declare-affidavit transaction successfully.
555///
556/// ## Notes
557/// - This is **not a transaction payload**.
558/// - This type is never submitted on-chain.
559/// - It is used internally during:
560/// - observation of finalized declaration effects
561/// - validation of next-key availability
562/// - promotion of the next affidavit key to active
563/// - reset of inconsistent key state when rotation cannot proceed
564///
565/// ## Dependency: [`InitAffidavitKey`], [`TryElection`], and [`DeclareAffidavit`]
566///
567/// This routine depends on the prior initialization, election, and declaration
568/// phases. It assumes that:
569/// - a *active-tagged* affidavit key-pair exists (guaranteed by [`InitAffidavitKey`]),
570/// - election has either completed or been safely skipped (handled by [`TryElection`]),
571/// - a declare-affidavit transaction has been submitted (by [`DeclareAffidavit`]).
572/// - and a *next-tagged* affidavit key-pair exists,
573///
574/// Whenever these invariants are violated (e.g. missing affidavit keys,
575/// eligibility failure, or window violations), control is redirected to
576/// [`InitAffidavitKey`] to repair and re-validate storage and keystore
577/// consistency before retrying rotation observation.
578///
579/// ## Fork Awareness
580/// - The `at` field captures the block number at which rotation observation
581/// begins.
582/// - When executed via offchain workers, this context must tolerate forks,
583/// re-orgs, and speculative execution.
584/// - Implementors must ensure idempotency and re-entrancy safety.
585///
586/// ## Rotation Flow
587///
588/// The routine verifies that the next affidavit key is referenced in offchain
589/// storage and locally available as pair in keystore, then determines whether
590/// rotation is currently eligible. If so, the next key is promoted to active
591/// and the previous state is cleaned up. If rotation cannot occur within the
592/// allowed session window, both active and next keys are reset to recover from
593/// inconsistent or stale state.
594///
595/// Failures or inconsistencies at any stage re-enter the initialization
596/// phase to re-validate offchain storage and keystore invariants.
597///
598/// ```ignore
599/// loop {
600/// // --- Initialization Phase ---
601/// if !offchain_storage.has_active_affidavit_key()
602/// || !keystore.has_active_affidavit_key()
603/// {
604/// keystore.create_or_repair_active_key();
605/// offchain_storage.ensure_active_key_reference();
606/// continue;
607/// }
608///
609/// // --- Election Phase (optimistic) ---
610/// if election_constraints_satisfied() {
611/// if submit_elect_authors_extrinsic().is_err() {
612/// continue; // repair + retry via initialization
613/// }
614/// }
615///
616/// // --- Declaration Phase ---
617/// if !offchain_storage.has_next_affidavit_key()
618/// || !keystore.has_next_affidavit_key()
619/// {
620/// match keystore.create_or_repair_next_key() {
621/// Ok(_) => {
622/// offchain_storage.ensure_next_key_reference();
623/// continue;
624/// }
625/// Err(_) => continue, // fallback to initialization repair loop
626/// }
627/// }
628///
629/// if !affidavit_constraints_satisfied() {
630/// continue; // retry via initialization phase
631/// }
632///
633/// if submit_declare_affidavit_extrinsic().is_err() {
634/// continue; // declaration failed -> repair + retry
635/// }
636///
637/// // --- Rotation Observation Phase ---
638/// if !offchain_storage.has_next_affidavit_key()
639/// || !keystore.has_next_affidavit_key()
640/// {
641/// continue;
642/// }
643///
644/// if eligible_to_rotate() {
645/// promote_next_key_to_active();
646/// remove_next_key();
647/// break; // rotation completed
648/// }
649///
650/// if within_current_session_window() {
651/// continue; // wait until rotation becomes eligible
652/// // indicates declaration effects are not finalized
653/// }
654///
655/// // Window expired -> reset inconsistent state
656/// remove_active_and_next_affidavit_keys();
657/// break;
658/// }
659/// ```
660///
661/// ## Guarantee
662///
663/// The rotation phase has exactly three exit outcomes:
664///
665/// 1. **Rotation Success**:
666/// - if the next affidavit key is finalized and present in the keystore, and
667/// - rotation eligibility constraints are satisfied,
668/// then the next key is promoted to become the active affidavit key.
669///
670/// 2. **Deferred Rotation (Same Session)**:
671/// - if the next affidavit key is finalized but not yet eligible to rotate, and
672/// - the current session window in which the affidavit was declared is still active,
673/// the routine keeps retrying until eligibility is satisfied and rotation succeeds.
674///
675/// 3. **Reset & Repair (Session Elapsed)**:
676/// - if rotation is still ineligible and the declaring session window has elapsed,
677/// both active and next affidavit keys are removed, signaling that the declaration
678/// phase effectively failed to converge. The global loop then re-enters the
679/// initialization phase to repair and re-establish a consistent state.
680///
681/// ```ignore
682/// loop {
683///
684/// if eligible_to_rotate() {
685/// promote_next_key_to_active();
686/// remove_next_affidavit_key();
687/// break;
688/// }
689/// if within_declaring_session_window() {
690/// continue;
691/// // keep retrying until eligibility becomes true
692/// } else {
693/// remove_active_and_next_affidavit_keys();
694/// break;
695/// // signal reset; initialization phase will repair state
696/// }
697/// }
698/// ```
699///
700/// All behavior is supplied by trait implementations operating on this type.
701///
702/// ## Timelines & Window Semantics
703///
704/// The global retry loop operates over session-scoped time windows that
705/// determine when election, declaration, and rotation are allowed.
706///
707/// Timeline within a single session:
708///
709/// ```text
710/// |--------------------- Session N ---------------------|
711/// |--------- Affidavit Window ---------|
712/// |----- Election Window -----|
713///
714/// Session Start
715/// |- Affidavit window opens
716/// |- Election window opens (nested inside affidavit window)
717///
718/// Election window closes
719/// |- Election no longer allowed
720///
721/// Affidavit window closes
722/// |- Declaration and rotation eligibility must already be satisfied
723///
724/// Session ends -> Session N+1 begins
725/// |- Global loop continues with fresh window constraints
726/// ```
727///
728/// Properties:
729/// - The **election window** is strictly nested within the **affidavit window**.
730/// - When the affidavit window ends, the election window has already ended.
731/// - Rotation eligibility is evaluated relative to the session in which the
732/// affidavit was declared.
733/// - If rotation has not converged before the session window elapses, the
734/// routine resets keys and relies on the next session's loop iteration
735/// to re-initialize and re-attempt the full lifecycle.
736///
737/// ## FlowChart
738///
739/// [](https://mermaid.live/edit#pako:eNqtVdtu2zgQ_RWCQBctNk7tyk4coWgRxCoQLOAt7ADFblW0tDi2iEqkQVGu0zivi33en9j_6pfskLpZsl2gxfolkXjmzMzhmdEDjRQH6tNlor5EMdOG3E1CGUqCv7nB5_chdX99MlOGGbheLgVnG2F-g_unz0L6oUI_eUJ6vR6pzwkCyK0URrBEfGVGKGkBBTjLFyvN1rEDYIrvRbkcpPzd3sQQfX4I6RshLQI4uY6M2ECT-OVCP3_1qyXKjNLgGK83TCRskcDrkD7usc1gzYTGAm40YHPkOSneVKQY6-iY5CSQWY50cyRlK0DgEjTICI7Uh42-2k3Vrkpgn8ujAgqSd3QLEsCUckWucxMrnR3RykGw1i60VUBQCVSgUPQbJTOjmZAmI3NUNFsK4K9dW0_fCcnVF_Lt73-RXawEKuQepspggzyXnEnzrKVZcLe1nsgXKd7WJ7BZPrKikE8k2BotZCaiuqbDTicQJUy7-utbP2x2Clvb6xFwq93poR9s5E-5YXrSDY7yh70wqWpr-vzBu2grP2kpz50y8JFV5F31uyLVppzumXI3z6MIsmxXgo4G_QF4Pume77O8QUFRkF1t8q4Kezx326OHblw6ORDrzg7ojzvL3q3bUtb2vy8y0JtTe6dYZijnfkzr9mb_o7Nm1YW6uSznzKiyig628AEi3wkTC5zfXKO3DJnjNdlmivNOUN3PW61Shd6tLEu-_fVPtc1-QaOmatMcthueQQZ25kpQHdRu2zXcMdjs-9c461iglqPFUQvT4IquTmFsqlKtFlE5SDXNQTl7AMfhGj8wVSC5XbaS-42p3sYsA5zidJ2AgcOvXyCNvm_s5r6creXfQhdsd5rhzFr6vaV_25Es6MbX633NTJyVFTdBIZ2qYq20P6Y9JZN7F4O7pT30QTdlNahBOYV297hlURBXFfSiUo4TtKdmuG6l2PGFwFmRgSTAeGZHRFfSq2aei8hqOdQbbNYlrq9N5QaLhFKm0lbuXgJ73437q3f0jK604NQ3OoczmoJOmX2kDxYdUhNDitfv47-c6c8hDeUjxqyZ_FOptArTKl_F1F-yJMOnfM0x60Qw3EBp_RZHm4O-Ubk01L8YDl44Fuo_0C31X1xenHtX3mh8MR57nnc5GJ3Re4QNzi9HV8Nh3xteja8G_dHjGf3q8vbPx0MPoaP-xaB_6Xl97_E_dswmYg)
740///
741#[derive(Encode, Decode, Clone, MaxEncodedLen, RuntimeDebug, TypeInfo, PartialEq, Eq)]
742#[scale_info(skip_type_params(T))]
743pub(crate) struct RotateAffidavitKey<T: Config> {
744 /// Public key that is intended to become the new active affidavit key.
745 pub by: T::Public,
746
747 /// Block number at which key rotation is initiated.
748 pub at: BlockNumberFor<T>,
749}
750
751// ===============================================================================
752// `````````````````````````````` UNSIGNED PAYLOADS ``````````````````````````````
753// ===============================================================================
754
755/// Runtime-specialized payload type for affidavit declaration.
756///
757/// This is a concrete alias of [`AffidavitPayload`] using the runtime's
758/// configured signing public key.
759///
760/// ## Usage
761/// - Used by the pallet's unsigned `declare` extrinsic.
762/// - Signed offchain using the active affidavit key.
763/// - Verified on-chain via `ValidateUnsigned`.
764///
765/// ## Design Notes
766/// - Separates **signing identity** (raw public key) from
767/// **runtime identity** (account-based affidavit ID).
768/// - Ensures payloads are always consistent with the runtime's
769/// configured application crypto.
770pub type AffidavitPayloadOf<T> = AffidavitPayload<<T as SigningTypes>::Public, AffidavitId<T>>;
771
772/// Runtime-specialized payload type for affidavit key validation.
773///
774/// This is a concrete alias of [`ValidatePayload`] using the runtime's
775/// configured signing public key.
776///
777/// ## Usage
778/// - Used by the pallet's unsigned `validate` extrinsic.
779/// - Proves possession of the active affidavit key prior to
780/// affidavit declaration.
781///
782/// ## Design Notes
783/// - Contains no mutable or session-specific data.
784/// - Exists solely to authenticate the active affidavit key.
785pub type ValidatePayloadOf<T> = ValidatePayload<<T as SigningTypes>::Public>;
786
787/// Runtime-specialized payload type for author election execution.
788///
789/// This is a concrete alias of [`ElectionPayload`] using the runtime's
790/// configured signing public key.
791///
792/// ## Usage
793/// - Used by the pallet's unsigned `elect` extrinsic.
794/// - Signed using the **currently active affidavit key**, which was
795/// rotated during the latest affidavit declaration.
796///
797/// ## Design Notes
798/// - Ensures only authors who successfully completed affidavit
799/// declaration and key rotation can execute elections.
800/// - Binds election authorization strictly to the runtime's
801/// configured signing scheme.
802pub type ElectionPayloadOf<T> = ElectionPayload<<T as SigningTypes>::Public>;
803
804// ===============================================================================
805// ```````````````````````````` GENESIS CONFIG UPDATE ````````````````````````````
806// ===============================================================================
807
808/// Enumerates configurable runtime-stored parameters that may be forcibly overridden
809/// at runtime through privileged (root/governance) operations.
810#[derive(
811 Encode,
812 Decode,
813 DecodeWithMemTracking,
814 Clone,
815 RuntimeDebugNoBound,
816 PartialEq,
817 Eq,
818 MaxEncodedLen,
819 TypeInfo,
820)]
821#[scale_info(skip_type_params(T))]
822pub enum ForceGenesisConfig<T: Config> {
823 AllowAffidavits(bool),
824 /// Updates the start of the affidavit submission window.
825 AffidavitBeginsAt(Duration),
826 /// Updates the end of the affidavit submission window.
827 AffidavitEndsAt(Duration),
828 /// Updates the point within the session when election execution begins.
829 ElectionBeginsAt(Duration),
830 /// Updates the points awarded for executing the election routine.
831 ElectionRunnerPointsUpgrade(Option<T::Points>),
832 /// Updates the transaction priority for validation-related extrinsics.
833 ValidateTxPriority(TransactionPriority),
834 /// Updates the transaction priority for election execution extrinsics.
835 ElectionTxPriority(TransactionPriority),
836 /// Updates the transaction priority for affidavit submission extrinsics.
837 AffidavitTxPriority(TransactionPriority),
838 /// Updates the time-based delay (in milliseconds) before operations are considered final.
839 FinalityAfter(Moment<T>),
840 /// Updates the block-based confirmation threshold for finality.
841 FinalityTicks(BlockNumberFor<T>),
842}
843
844// ===============================================================================
845// ``````````````````````````````` SESSION WINDOWS ```````````````````````````````
846// ===============================================================================
847
848/// Represents the **affidavit submission window** for the current session.
849///
850/// Defines the inclusive block range during which authors are permitted
851/// to submit affidavits for the **next upcoming session**.
852///
853/// ### Semantics
854///
855/// - `start`: First block at which affidavit submission is allowed.
856/// - `end`: Last block (inclusive) after which submissions are rejected.
857#[derive(
858 Encode,
859 Decode,
860 DecodeWithMemTracking,
861 Clone,
862 RuntimeDebugNoBound,
863 PartialEq,
864 Eq,
865 MaxEncodedLen,
866 TypeInfo,
867)]
868/// Affidavit Window for the current session
869pub struct AffidavitWindow<T: Config> {
870 /// Block number at which affidavit submission begins.
871 pub start: BlockNumberFor<T>,
872 /// Block number at which affidavit submission ends.
873 pub end: BlockNumberFor<T>,
874}
875
876/// Represents the **election execution window** for the current session.
877///
878/// Defines the block range during which election logic is expected
879/// to be executed for determining the **next session's validator set**.
880///
881/// ### Semantics
882///
883/// - `start`: First block at which election execution may begin.
884/// - `end`: Final block for election execution.
885#[derive(
886 Encode,
887 Decode,
888 DecodeWithMemTracking,
889 Clone,
890 RuntimeDebugNoBound,
891 PartialEq,
892 Eq,
893 MaxEncodedLen,
894 TypeInfo,
895)]
896pub struct ElectionWindow<T: Config> {
897 /// Block number at which election execution begins.
898 pub start: BlockNumberFor<T>,
899 /// Block number at which election execution ends.
900 pub end: BlockNumberFor<T>,
901}