pallet-chain-manager 0.1.1

A session-driven orchestration pallet coordinating validator selection, participation, and settlement using offchain workers and pluggable models
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
// SPDX-License-Identifier: MPL-2.0
//
// Part of Auguth Labs open-source softwares.
// Built for the Substrate framework.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2026 Auguth Labs (OPC) Pvt Ltd, India

// ===============================================================================
// ````````````````````````````` CHAIN MANAGER TYPES `````````````````````````````
// ===============================================================================

//! **Core types and aliases for the Chain Manager system.**
//!
//! This module primarily defines **type aliases**, **public structs**, and
//! **runtime-specialized unsigned payloads** used across
//! [`pallet_chain_manager`](crate).
//!
//! The Chain Manager relies on external trait adapters such as:
//! - [`Config::RoleAdapter`]
//! - [`Config::ElectionAdapter`]
//! - [`Config::Asset`] (fungible-adapter)
//! - [`Config::PointsAdapter`]
//!
//! These abstractions delegate core logic to other pallets/framework layers,
//! while the types in this module provide a **unified, runtime-bound view**
//! and are used in the pallet's **public APIs**.
//!
//! Raw unsigned payload types are defined in [`crate::crypto`], but it is
//! recommended to use the aliases here to ensure correct runtime binding
//! to offchain signing types.
//!
//! ## Example
//!
//! ```ignore
//! use pallet_chain_manager::types::ElectionPayloadOf;
//!
//! let payload = ElectionPayloadOf::<T> { ... };
//! SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(
//!     Call::elect { payload }.into()
//! );
//! ```

// ===============================================================================
// ``````````````````````````````````` IMPORTS ```````````````````````````````````
// ===============================================================================

// --- Local crate imports ---
use crate::{crypto::*, Config};

// --- Scale-codec crates ---
use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
use scale_info::TypeInfo;

// --- FRAME Suite ---
use frame_suite::{elections::*, roles::*, routines::Moment};

// --- FRAME Support ---
use frame_support::{
    pallet_prelude::TransactionPriority, traits::fungible::Inspect, RuntimeDebugNoBound,
};

// --- FRAME System ---
use frame_system::{offchain::SigningTypes, pallet_prelude::BlockNumberFor};

// --- Substrate primitives ---
use sp_core::RuntimeDebug;
use sp_runtime::{Perbill, Permill, Vec};

// ===============================================================================
// ``````````````````````````````````` ALIASES ```````````````````````````````````
// ===============================================================================

/// The `AccountId` type representing an author in this runtime.
///
/// Acts as the primary key for tracking points, rewards, penalties, and election data.
pub type AuthorOf<T> = <T as frame_system::pallet::Config>::AccountId;

/// The asset type associated with an author-role.
///
/// Used for funding, collateral, rewarding or penalizing authors and backers.
pub type AssetOf<T> = <<T as Config>::RoleAdapter as RoleManager<AuthorOf<T>>>::Asset;

/// Timestamp associated with an author role for various operations
/// such as deffered rewards and penalities
pub type AuthorTimeStampOf<T> = <<T as Config>::RoleAdapter as RoleManager<AuthorOf<T>>>::TimeStamp;

/// Type representing an entity or account backing an author, as managed by [`FundRoles`].
///
/// - Typically used to track external funding, sponsorship, or support for authors.
/// - Allows pallets to query or interact with the backing source of an author.
pub type BackerOf<T> = <<T as Config>::RoleAdapter as FundRoles<AuthorOf<T>>>::Backer;

/// The concrete fungible balance type of the asset associated with an author.
///
/// Represents the fungible units that can be rewarded, or penalized.
///
/// This is ensured to be [`AssetOf`] where `AssetOf == ActualAsset` enforced
/// via [`Config::Asset`]
pub type ActualAsset<T> = <<T as Config>::Asset as Inspect<AuthorOf<T>>>::Balance;

/// Represents a singular election weight of numerous weights holded by the author.
///
/// Raw or intermediate election metric type
pub type ElectionWeight<T> =
    <<T as Config>::ElectionAdapter as ElectionManager<AuthorOf<T>>>::ElectionWeight;

/// Type representing the election weight of an author.
///
/// - Used to rank, score, or prioritize authors in elections.
/// - Typically derived from participation, stake, or other metrics.
/// - Serves as the primary metric for electing authors.
pub type ElectionVia<T> =
    <<T as Config>::ElectionAdapter as ElectionManager<AuthorOf<T>>>::ElectionWeightOf;

/// Parameters for configuring an election i.e, the input authors and their
/// corresponding election weight.
pub type ElectionParams<T> =
    <<T as Config>::ElectionAdapter as ElectionManager<AuthorOf<T>>>::Params;

/// Set of authors successfully elected by the author-role election module.
///
/// - Can be iterated over to assign points, rewards, or responsibilities.
/// - Typically used to determine which authors are active for a reward cycle
///   or session.
pub type ElectionElects<T> =
    <<T as Config>::ElectionAdapter as ElectionManager<AuthorOf<T>>>::Elected;

/// Represents a **collection of authors and their ephemeral points**
/// (e.g., block producer points) for a single reward cycle.
///
/// - Each entry is `(Author, Points)`.
/// - Serves as input to the [`Config::RewardModel`] plugin to compute per-author payouts.
/// - Points are temporary and cleared after the cycle.
pub type PayoutFor<T> = Vec<(AuthorOf<T>, <T as Config>::Points)>;

/// Represents a **collection of authors and their final rewards**
/// for a given reward cycle.
///
/// - Each entry is `(Author, Asset)`.
/// - Produced by the [`Config::RewardModel`] plugin after distributing total payout
///   based on ephemeral points.
/// - Used to execute the actual reward transfers or minting.
pub type PayeeList<T> = Vec<(AuthorOf<T>, AssetOf<T>)>;

/// Represents a **single penalty as a proportion** of a total value.
///
/// - Uses [`PerThing`](sp_runtime::PerThing) to allow fine-grained fractional penalties.
/// - Ideal for proportional deductions from author-risked assets for block-production.
/// - Ensures consistency and flexibility across different asset scales.
pub type PenaltyOf<T> = <<T as Config>::RoleAdapter as CompensateRoles<AuthorOf<T>>>::Ratio;

/// Collection of authors and their proportional penalties for a given cycle.
///
/// - Each entry represents `(Author, PenaltyOf)`.
/// - Input for [`Config::PenaltyModel`] plugin and output for transformed penalties.
/// - Supports multiple penalties applied in a single cycle.
pub type PenaltyFor<T> = Vec<(AuthorOf<T>, PenaltyOf<T>)>;

/// Represents the index of a block production session.
///
/// - Typically increments with each session in the runtime.
/// - Used to track author activity, points, rewards, or penalties per session.
pub type SessionIndex = sp_staking::SessionIndex;

/// Type alias for the **Validator ID** used by [`pallet_session`].
///
/// In the context of elections, candidate authors are mapped to this type
/// to interact with the session pallet (e.g., for validator set queries or election participation).
pub type SessionId<T> = <T as pallet_session::Config>::ValidatorId;

/// Type alias representing an **offending validator** in session history.
pub type Offender<T> = pallet_session::historical::IdentificationTuple<T>;

/// Type alias representing the **reporting account** that detected the offence.
pub type OffenceReporter<T> = <T as frame_system::Config>::AccountId;

/// The **runtime-storable identifier** of an affidavit key.
///
/// This represents the public identity of an affidavit key **as stored on-chain**.
/// While application crypto operates on raw public keys, the runtime persists
/// this identifier in the runtime's `AccountId` format for consistency and
/// interoperability with other pallets.
pub type AffidavitId<T> = <T as frame_system::pallet::Config>::AccountId;

/// Type representing **relative session duration**.
///
/// Used to define timing of affidavit and election phases
/// as a fraction of the current session.
///
/// Interpreted as a percentage ([`PerThing`](sp_runtime::PerThing)) of session length:
///
/// `block = session_start + (Duration * session_length)`
pub type Duration = Permill;

/// Type representing the **penalty ratio** applied to a author for
/// bad-behaviour.
///
/// Expressed as a [`Perbill`], aligning with
/// [`OnOffenceHandler`](sp_staking::offence::OnOffenceHandler)
/// which applies penalties directly using per-bill fractions.
pub type PenaltyRatio = Perbill;

// ===============================================================================
// `````````````````````````````````` ROUTINES ```````````````````````````````````
// ===============================================================================

/// Operational context for **affidavit key initialization**.
///
/// This type represents the contextual information required to initialize
/// or recover an affidavit key during the key lifecycle.
///
/// Affidavit keys are **ephemeral, operational keys** that are rotated
/// independently of long-term authority, stash, or consensus keys.
/// Initialization may execute sequentially multiple times as a looped
/// routine (e.g. via offchain workers), and therefore requires an explicit,
/// lightweight context object.
///
/// ## Notes
/// - This is **not a transaction payload**.
/// - This type is never submitted on-chain.
/// - It is used internally during:
///   - affidavit key generation
///   - key recovery
///   - keystore initialization or repair
///
/// ## Fork Awareness
/// - The `at` field captures the block number at which the initialization
///   process begins.
/// - When executed via offchain workers, this context must tolerate
///   forks, re-orgs, and speculative execution.
/// - Implementors are responsible for ensuring idempotency and re-entrancy safety.
///
/// ## Initialization Flow
///
/// The process repeatedly attempts to resolve a affidavit key-pair. It
/// self-heals by creating and inserting keys when missing, and retries
/// on missing or error states until a consistent state is reached.
///
/// ## Pseudocode
///
/// ```ignore
/// loop {
///     // Fetch the tagged active affidavit from offchain storage
///     match offchain_storage.fetch_active_affidavit() {
///         Ok(None) => {
///             // No active-tagged affidavit-key exists -> create a new key-pair locally
///             keystore.create_affidavit_key();
///
///             // Publish the key reference to offchain storage
///             offchain_storage.insert_affidavit_key();
///             continue;
///         }
///         Ok(Some(affidavit)) => {
///             // A active-tagged affidavit exists -> ensure the local key-pair is present
///             match keystore.get_affidavit_key() {
///                 Some(key) => break key,
///                 None => {
///                     // Storage provided public key, but its actual key-pair
///                     // is missing locally -> repair
///                     keystore.create_affidavit_key();
///                     continue;
///                 }
///             }
///         }
///         Ok(Some(_other_status)) => continue,
///         Err(_storage_error) => continue, // transient storage error -> retry
///     }
/// }
/// ```
///
/// ## Guarantee
///
/// This process yields an active affidavit key **only when** its tagged/referenced
/// via an offchain storage and its corresponding the key-pair exists in the
/// local keystore. Otherwise, it creates/repairs the key and keeps retrying
/// until the affidavit becomes tagged and the keystore is consistent.
///
/// ```ignore
/// loop {
///     if offchain_storage.has_affidavit_key()
///         && keystore.has_affidavit_key()
///     {
///         break;
///     }
///
///     keystore.create_or_repair_affidavit_key();
///     offchain_storage.ensure_affidavit_key_reference();
///     // retry until next key reaches consistency
/// }
/// ```
///
/// All behavior is supplied by trait implementations operating on this type.
///
/// ## FlowChart
///
/// [![](https://mermaid.ink/img/pako:eNqFUsFu2zAM_RWBpwxIMseNPUeHAVnaDsWwtWh72ryDYjO2MFsOZDldmuTfR1lxWjfAqoNEkXyP5JN2kFQpAodVUT0ludCGPV7GKlaM1oOh-68Y2pOzGyXNfLWSqdhI8w23gw8x_O5y62aZabHOWQynHEZJLUqKQj4LIysVg0u3K5UaE-tkj19evNdokpyKtiebU8IG2Qvl4MFUWmTI7pplIRNbwrXR4RcahUEicAb7gU-s39FgobdrUzHLhH3wjaqxHdkZb4Hv1f6KVheC36PREnuNv1P5HkVqkT3A6E5IzeYbIQuxLPAEQJV2ul-plFC0c6IwjVbnkhHRq4dqH5ONRp-d0p3byU3u_XdZ11Jl-6OSLnwU08KcNM59lOk_bNdVo9L9URkXdPbraDv8WfCskbfcV1pXmn1ktyZHbQczTb3vN9Iyt_2RRDCETMsUuNENDqFEXQp7hZ1NjoFoShKZk5kK_cf-1QNh1kL9rKqyg-mqyXLgK1HUdGvWKfV2KQX9_vLk1fRCqBc0nQHu-9OWBPgO_gKfzcZ-MJ14QeBPonASfRrCFnh0MY4u_Cj0oij0Z14QHYbw3Fb1xmEQTYNgQtHIm4bT2eEfZkQtCQ?type=png)](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)
///
#[derive(Encode, Decode, Clone, MaxEncodedLen, TypeInfo, PartialEq, Eq)]
#[scale_info(skip_type_params(T))]
pub(crate) struct InitAffidavitKey<T: Config> {
    /// Block number at which affidavit key initialization begins.
    ///
    /// Used for logging, diagnostics, and fork-aware coordination.
    pub at: BlockNumberFor<T>,
}

/// Operational context for **election transaction execution**.
///
/// This type represents the contextual information required to attempt
/// authors election using an affidavit key during the routine lifecycle.
///
/// Election attempts are **optimistic, sequential routines** that may execute
/// repeatedly as part of a looped execution model (e.g. via offchain workers).
/// Although election typically follows the affidavit declaration phase,
/// explicit looping of sequential routines allows this phase to run earlier.
/// The routine remains safe, as successful election is gated by retrievable
/// storage state, election window constraints, and eligibility checks.
///
/// ## Notes
/// - This is **not a transaction payload**.
/// - This type is never submitted on-chain.
/// - It is used internally during:
///   - fetching the active-tagged affidavit key (storage-reference + keystore-pair)
///   - election payload signing using the affidavit key pair
///   - submission of the `elect` extrinsic
///   - retry-driven OCW election execution
///
/// ## Fork Awareness
/// - The `at` field captures the block number at which the election
///   attempt begins.
/// - When executed via offchain workers, this context must tolerate
///   forks, re-orgs, and speculative execution.
/// - Implementors are responsible for ensuring idempotency and
///   re-entrancy safety.
///
/// ## Dependency: [`InitAffidavitKey`]
///
/// This routine depends on the affidavit key initialization phase.
/// It assumes that a active-tagged (offchain storage referenced) affidavit key
/// and its pair in crypto-store is available. Whenever this invariant is violated
/// (e.g. missing key, failed signing, or inconsistent state), control is redirected
/// to [`InitAffidavitKey`] to repair and re-validate the key before retrying the
/// election attempt.
///
/// ## Election Flow
///
/// The routine fetches the active-tagged affidavit key-pair (referenced via
/// offchain storage and retrieved through local keystore), then attempts
/// author election. It short-circuits when outside the election window, when
/// ineligible, or when already elected (to avoid redundancy). Failures or
/// inconsistencies re-enter the affidavit initialization phase for re-validation
/// and repair.
///
/// ```ignore
/// loop {
///     // Ensure active-tagged affidavit key is available
///     InitAffidavitKey::ensure_active_affidavit_key();
///
///     // Fetch affidavit key pair (offchain storage reference + keystore-pair)
///     let key_pair = fetch_affidavit_key_pair();
///
///     if !within_election_window()
///         || !eligible_to_elect()
///         || already_elected()
///     {
///         break; // proceed to declaration phase (no election required)
///     }
///
///     let payload = Default::default();
///
///     match sign_payload_with(key_pair)
///         .and_then(|payload| submit_elect_authors_extrinsic(payload))
///     {
///         Ok(_) => break,     // elect-phase completed successfully
///         Err(_) => continue, // retry via initialization phase again
///     }
/// }
/// ```
///
/// ## Guarantees
///
/// This routine proceeds to the affidavit declaration phase under
/// exactly two conditions:
///
/// 1. **Initialization-only path**: a active-tagged affidavit key-pair
///    exists, but election constraints are not satisfied (outside window,
///    ineligible, or already elected).
///
/// 2. **Election-complete path**: a active-tagged affidavit key-pair
///    exists, election constraints are satisfied, and the `elect`
///    extrinsic is successfully submitted.
///
/// In all other cases, the routine retries by re-entering the affidavit
/// key initialization phase to re-validate offchain storage and
/// keystore consistency.
///
/// All behavior is supplied by trait implementations operating on this type.
///
/// ## FlowChart
///
/// [![](https://mermaid.ink/img/pako:eNp9VG1r2zAQ_itCMGhZ0sZ5cVMzOkKbQhmMsBTKNo-hWBdb1JGDLKdNk_z3naTYiZ0wf7Hke-65l-fOGxplHGhA52n2FiVMafL8EMpQEnymGu-_Q2rfAXlW63EKkRaZvLgM6Z8S9ukTabfbZDSfC85WQpNvsCZPUmjBUvHBDJ5MEpaDgTmXvJjFii0TC8MI__O1kcj-ebpPIHrdHHtMilkqIuv4Zaau7z6bY64zBWTChCKjFRMpm6XwNaS7I6YfsEQzBr9XwDSQa-K-GHdLxCQnY5kXSDRFOhYDIuagQEZwJims7m77PduWzOa-NzkoSN5omWunjMmo0Emm8jMNshBMsgmtJTBC0woQ9Qg6SupK2FIuqsTbphTgpNGlyxrfi5A8e8MuvwidCElK2feGeiPHqYgFtndjknRHojPnU0eOUuw0Xxv13MmBgNdhUxFLM3X4OkSesHWaMe6qWQnWGLfTGqbFbGFnyx0OTM-KyZzZs2Mbv2slZC6igIAB_WWuxQe-I-XGkpuRySSKUdhCHyBKmYKjgTSzfrofbgVsdGETqcS2-3UyLkdT9RPy7V7ksxOEZI-4vwdGh7WUTrLSzd2qUR2bwhrfbbBSyarsUtkTz5rFJerELV1LrQ_cpeuxxXAaxat_j1HfGKZFFEGObk7HhvURdxsXdFt1bm93mp9FNOwVv02LtmisBKeBVgW06ALUgpkr3RjHkOoEFqhtgEfO1GtIQ7lDnyWTv7JsUbqprIgTGsxZmuOtWHL8vzwIhhu9qL7iNnJQ91khNQ36fd-S0GBD32ngXfU7vW63e9Pvdwd-f9gbtOiaBm3P7115veHAH3Y6Pa93O7jZteiHDexdDX2v43WHnaHnebd939_9A4zO3PM?type=png)](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)
///
#[derive(Encode, Decode, Clone, MaxEncodedLen, TypeInfo, RuntimeDebug, PartialEq, Eq)]
#[scale_info(skip_type_params(T))]
pub(crate) struct TryElection<T: Config> {
    /// Public key authorized to sign election transactions.
    pub by: T::Public,

    /// Block number at which election execution is initiated.
    pub at: BlockNumberFor<T>,
}

/// Operational context for **affidavit declaration and key rotation**.
///
/// This type represents the contextual information required to declare
/// an affidavit using the active affidavit key and rotate it to the next key
/// during the routine lifecycle.
///
/// Declaration is a **sequential, retry-driven routine** that executes as part
/// of the looped offchain workflow. It is entered only after the initialization
/// phase guarantees that a active-tagged affidavit key-pair is available, and
/// after the election phase has either completed successfully or been safely
/// skipped due to unmet constraints.
///
/// ## Notes
/// - This is **not a transaction payload**.
/// - This type is never submitted on-chain.
/// - It is used internally during:
///   - next affidavit key resolution
///   - declaration payload composition (including next public key for rotation)
///   - payload signing using the active affidavit key-pair
///   - submission of the declare-affidavit extrinsic
///
/// ## Dependency: [`InitAffidavitKey`] and optimistic [`TryElection`]
///
/// This routine has a hard dependency on the initialization phase and a
/// soft (optimistic) dependency on the election phase.
///
/// It requires that:
/// - a *active-tagged* affidavit key exists in offchain storage and
///   the its key-pair  in local keystore (guaranteed by [`InitAffidavitKey`]), and
/// - election has either completed successfully or has been safely skipped
///   due to unmet constraints.
///
/// Election may execute before declaration as part of the global retry loop,
/// but its outcome does not directly gate declaration correctness. However,
/// failures during election invalidate system invariants and therefore
/// redirect control back to [`InitAffidavitKey`] for repair and re-validation
/// before declaration is retried.
///
/// ## Fork Awareness
/// - The `at` field captures the block number at which the declaration
///   process begins.
/// - When executed via offchain workers, this context must tolerate
///   forks, re-orgs, and speculative execution.
/// - Implementors must ensure idempotency and re-entrancy safety.
///
/// ## Declaration Flow
///
/// The routine fetches the active-tagged affidavit key-pair, resolves the
/// next affidavit key (mirroring the affidavit-key-initialization logic),
/// verifies the declaration window and eligibility, composes the declaration
/// payload along with the next affidavit public key, signs it with the active
/// affidavit key-pair, and submits the declaration transaction to rotate the
/// active affidavit key to next affidavit key.
///
/// Failures or inconsistencies re-enter the initialization phase to
/// re-validate offchain storage and keystore invariants.
///
/// ```ignore
/// loop {
///     // Ensure active-tagged affidavit key-pair is available
///     InitAffidavitKey::ensure_active_affidavit_key();
///
///     // Fetch affidavit key pair (offchain storage reference + keystore-pair)
///     let key_pair = fetch_affidavit_key_pair();

///     // Attempt election optimistically; failure requires repair + retry
///     if TryElection::attempt_election_if_applicable().is_err() {
///         continue; // re-enter initialization phase
///     }
///
///     // Resolve next affidavit key using the offchain-storage references +
///     // keystore pair consistency guarantees as InitAffidavitKey
///     if !offchain_storage.has_next_affidavit_key()
///         || !keystore.has_next_affidavit_key()
///     {
///         keystore.create_or_repair_next_affidavit_key();
///         offchain_storage.ensure_next_affidavit_key_reference();
///         continue; // retry until next key reaches consistency
///     }
///
///     let next_key_to_rotate = fetch_next_affidavit_key();
///
///     if !within_affidavit_window() || !eligible_to_declare() {
///         continue; // retry via initialization phase
///     }
///
///     let payload = compose_declare_affidavit_payload(next_key_to_rotate);
///
///     match sign_payload_with(key_pair)
///         .and_then(|payload| submit_declare_affidavit_extrinsic(payload)) {
///         Ok(_) => break,     // declaration + rotation completed
///         Err(_) => continue, // retry via initialization phase
///     }
/// }
/// ```
///
/// ## Guarantee
///
/// This routine declares the affidavit and rotates the active key
/// **only when**:
/// - a active-tagged affidavit key-pair is available,
/// - the next affidavit key is initiated and present in the local keystore,
/// - declaration window and eligibility constraints are satisfied,
/// - and the declaration transaction is successfully submitted.
///
/// In all other cases, the routine retries by re-entering the affidavit
/// key initialization phase to repair and re-validate offchain storage
/// and keystore consistency.
///
/// All behavior is supplied by trait implementations operating on this type.
///
/// ## FlowChart
///
/// [![](https://mermaid.ink/img/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?type=png)](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)
///
#[derive(Encode, Decode, Clone, MaxEncodedLen, RuntimeDebug, TypeInfo, PartialEq, Eq)]
#[scale_info(skip_type_params(T))]
pub(crate) struct DeclareAffidavit<T: Config> {
    /// Raw application public key identifying the affidavit key-pair
    /// in the local keystore.
    pub by: T::Public,

    /// Block number at which the affidavit declaration process started.
    ///
    /// Used exclusively for logging and diagnostic purposes.
    pub at: BlockNumberFor<T>,
}

/// Operational context for **affidavit key rotation**.
///
/// This type represents the contextual information required to observe
/// and commence rotation of the affidavit key, promoting the previously
/// prepared *next* key to become the active affidavit key once the
/// declaration effects are finalized.
///
/// Rotation is a **sequential, retry-driven routine** that executes as part
/// of the looped offchain workflow. It is entered only after the declaration
/// phase has submitted the declare-affidavit transaction successfully.
///
/// ## Notes
/// - This is **not a transaction payload**.
/// - This type is never submitted on-chain.
/// - It is used internally during:
///   - observation of finalized declaration effects
///   - validation of next-key availability
///   - promotion of the next affidavit key to active
///   - reset of inconsistent key state when rotation cannot proceed
///
/// ## Dependency: [`InitAffidavitKey`], [`TryElection`], and [`DeclareAffidavit`]
///
/// This routine depends on the prior initialization, election, and declaration
/// phases. It assumes that:
/// - a *active-tagged* affidavit key-pair exists (guaranteed by [`InitAffidavitKey`]),
/// - election has either completed or been safely skipped (handled by [`TryElection`]),
/// - a declare-affidavit transaction has been submitted (by [`DeclareAffidavit`]).
/// - and a *next-tagged* affidavit key-pair exists,
///
/// Whenever these invariants are violated (e.g. missing affidavit keys,
/// eligibility failure, or window violations), control is redirected to
/// [`InitAffidavitKey`] to repair and re-validate storage and keystore
/// consistency before retrying rotation observation.
///
/// ## Fork Awareness
/// - The `at` field captures the block number at which rotation observation
///   begins.
/// - When executed via offchain workers, this context must tolerate forks,
///   re-orgs, and speculative execution.
/// - Implementors must ensure idempotency and re-entrancy safety.
///
/// ## Rotation Flow
///
/// The routine verifies that the next affidavit key is referenced in offchain
/// storage and locally available as pair in keystore, then determines whether
/// rotation is currently eligible. If so, the next key is promoted to active
/// and the previous state is cleaned up. If rotation cannot occur within the
/// allowed session window, both active and next keys are reset to recover from
/// inconsistent or stale state.
///
/// Failures or inconsistencies at any stage re-enter the initialization
/// phase to re-validate offchain storage and keystore invariants.
///
/// ```ignore
/// loop {
///     // --- Initialization Phase ---
///     if !offchain_storage.has_active_affidavit_key()
///         || !keystore.has_active_affidavit_key()
///     {
///         keystore.create_or_repair_active_key();
///         offchain_storage.ensure_active_key_reference();
///         continue;
///     }
///
///     // --- Election Phase (optimistic) ---
///     if election_constraints_satisfied() {
///         if submit_elect_authors_extrinsic().is_err() {
///             continue; // repair + retry via initialization
///         }
///     }
///
///     // --- Declaration Phase ---
///     if !offchain_storage.has_next_affidavit_key()
///         || !keystore.has_next_affidavit_key()
///     {
///         match keystore.create_or_repair_next_key() {
///             Ok(_) => {
///                 offchain_storage.ensure_next_key_reference();
///                 continue;
///             }
///             Err(_) => continue, // fallback to initialization repair loop
///         }
///     }
///
///     if !affidavit_constraints_satisfied() {
///         continue; // retry via initialization phase
///     }
///
///     if submit_declare_affidavit_extrinsic().is_err() {
///         continue; // declaration failed -> repair + retry
///     }
///
///     // --- Rotation Observation Phase ---
///     if !offchain_storage.has_next_affidavit_key()
///         || !keystore.has_next_affidavit_key()
///     {
///         continue;
///     }
///
///     if eligible_to_rotate() {
///         promote_next_key_to_active();
///         remove_next_key();
///         break; // rotation completed
///     }
///
///     if within_current_session_window() {
///         continue; // wait until rotation becomes eligible
///                   // indicates declaration effects are not finalized
///     }
///
///     // Window expired -> reset inconsistent state
///     remove_active_and_next_affidavit_keys();
///     break;
/// }
/// ```
///
/// ## Guarantee
///
/// The rotation phase has exactly three exit outcomes:
///
/// 1. **Rotation Success**:
///    - if the next affidavit key is finalized and present in the keystore, and
///    - rotation eligibility constraints are satisfied,
///    then the next key is promoted to become the active affidavit key.
///
/// 2. **Deferred Rotation (Same Session)**:
///    - if the next affidavit key is finalized but not yet eligible to rotate, and
///    - the current session window in which the affidavit was declared is still active,
///    the routine keeps retrying until eligibility is satisfied and rotation succeeds.
///
/// 3. **Reset & Repair (Session Elapsed)**:
///    - if rotation is still ineligible and the declaring session window has elapsed,
///    both active and next affidavit keys are removed, signaling that the declaration
///    phase effectively failed to converge. The global loop then re-enters the
///    initialization phase to repair and re-establish a consistent state.
///
/// ```ignore
/// loop {
///
///     if eligible_to_rotate() {
///         promote_next_key_to_active();
///         remove_next_affidavit_key();
///         break;
///     }
///     if within_declaring_session_window() {
///         continue;
///         // keep retrying until eligibility becomes true
///     } else {
///         remove_active_and_next_affidavit_keys();
///         break;
///         // signal reset; initialization phase will repair state
///     }
/// }
/// ```
///
/// All behavior is supplied by trait implementations operating on this type.
///
/// ## Timelines & Window Semantics
///
/// The global retry loop operates over session-scoped time windows that
/// determine when election, declaration, and rotation are allowed.
///
/// Timeline within a single session:
///
/// ```text
/// |--------------------- Session N ---------------------|
///        |--------- Affidavit Window ---------|
///                 |----- Election Window -----|
///
/// Session Start
///     |- Affidavit window opens
///          |- Election window opens (nested inside affidavit window)
///
/// Election window closes
///     |- Election no longer allowed
///
/// Affidavit window closes
///     |- Declaration and rotation eligibility must already be satisfied
///
/// Session ends -> Session N+1 begins
///     |- Global loop continues with fresh window constraints
/// ```
///
/// Properties:
/// - The **election window** is strictly nested within the **affidavit window**.
/// - When the affidavit window ends, the election window has already ended.
/// - Rotation eligibility is evaluated relative to the session in which the
///   affidavit was declared.
/// - If rotation has not converged before the session window elapses, the
///   routine resets keys and relies on the next session's loop iteration
///   to re-initialize and re-attempt the full lifecycle.
///
/// ## FlowChart
///
/// [![](https://mermaid.ink/img/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?type=png)](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)
///
#[derive(Encode, Decode, Clone, MaxEncodedLen, RuntimeDebug, TypeInfo, PartialEq, Eq)]
#[scale_info(skip_type_params(T))]
pub(crate) struct RotateAffidavitKey<T: Config> {
    /// Public key that is intended to become the new active affidavit key.
    pub by: T::Public,

    /// Block number at which key rotation is initiated.
    pub at: BlockNumberFor<T>,
}

// ===============================================================================
// `````````````````````````````` UNSIGNED PAYLOADS ``````````````````````````````
// ===============================================================================

/// Runtime-specialized payload type for affidavit declaration.
///
/// This is a concrete alias of [`AffidavitPayload`] using the runtime's
/// configured signing public key.
///
/// ## Usage
/// - Used by the pallet's unsigned `declare` extrinsic.
/// - Signed offchain using the active affidavit key.
/// - Verified on-chain via `ValidateUnsigned`.
///
/// ## Design Notes
/// - Separates **signing identity** (raw public key) from
///   **runtime identity** (account-based affidavit ID).
/// - Ensures payloads are always consistent with the runtime's
///   configured application crypto.
pub type AffidavitPayloadOf<T> = AffidavitPayload<<T as SigningTypes>::Public, AffidavitId<T>>;

/// Runtime-specialized payload type for affidavit key validation.
///
/// This is a concrete alias of [`ValidatePayload`] using the runtime's
/// configured signing public key.
///
/// ## Usage
/// - Used by the pallet's unsigned `validate` extrinsic.
/// - Proves possession of the active affidavit key prior to
///   affidavit declaration.
///
/// ## Design Notes
/// - Contains no mutable or session-specific data.
/// - Exists solely to authenticate the active affidavit key.
pub type ValidatePayloadOf<T> = ValidatePayload<<T as SigningTypes>::Public>;

/// Runtime-specialized payload type for author election execution.
///
/// This is a concrete alias of [`ElectionPayload`] using the runtime's
/// configured signing public key.
///
/// ## Usage
/// - Used by the pallet's unsigned `elect` extrinsic.
/// - Signed using the **currently active affidavit key**, which was
///   rotated during the latest affidavit declaration.
///
/// ## Design Notes
/// - Ensures only authors who successfully completed affidavit
///   declaration and key rotation can execute elections.
/// - Binds election authorization strictly to the runtime's
///   configured signing scheme.
pub type ElectionPayloadOf<T> = ElectionPayload<<T as SigningTypes>::Public>;

// ===============================================================================
// ```````````````````````````` GENESIS CONFIG UPDATE ````````````````````````````
// ===============================================================================

/// Enumerates configurable runtime-stored parameters that may be forcibly overridden
/// at runtime through privileged (root/governance) operations.
#[derive(
    Encode,
    Decode,
    DecodeWithMemTracking,
    Clone,
    RuntimeDebugNoBound,
    PartialEq,
    Eq,
    MaxEncodedLen,
    TypeInfo,
)]
#[scale_info(skip_type_params(T))]
pub enum ForceGenesisConfig<T: Config> {
    AllowAffidavits(bool),
    /// Updates the start of the affidavit submission window.
    AffidavitBeginsAt(Duration),
    /// Updates the end of the affidavit submission window.
    AffidavitEndsAt(Duration),
    /// Updates the point within the session when election execution begins.
    ElectionBeginsAt(Duration),
    /// Updates the points awarded for executing the election routine.
    ElectionRunnerPointsUpgrade(Option<T::Points>),
    /// Updates the transaction priority for validation-related extrinsics.
    ValidateTxPriority(TransactionPriority),
    /// Updates the transaction priority for election execution extrinsics.
    ElectionTxPriority(TransactionPriority),
    /// Updates the transaction priority for affidavit submission extrinsics.
    AffidavitTxPriority(TransactionPriority),
    /// Updates the time-based delay (in milliseconds) before operations are considered final.
    FinalityAfter(Moment<T>),
    /// Updates the block-based confirmation threshold for finality.
    FinalityTicks(BlockNumberFor<T>),
}

// ===============================================================================
// ``````````````````````````````` SESSION WINDOWS ```````````````````````````````
// ===============================================================================

/// Represents the **affidavit submission window** for the current session.
///
/// Defines the inclusive block range during which authors are permitted
/// to submit affidavits for the **next upcoming session**.
///
/// ### Semantics
///
/// - `start`: First block at which affidavit submission is allowed.
/// - `end`: Last block (inclusive) after which submissions are rejected.
#[derive(
    Encode,
    Decode,
    DecodeWithMemTracking,
    Clone,
    RuntimeDebugNoBound,
    PartialEq,
    Eq,
    MaxEncodedLen,
    TypeInfo,
)]
/// Affidavit Window for the current session
pub struct AffidavitWindow<T: Config> {
    /// Block number at which affidavit submission begins.
    pub start: BlockNumberFor<T>,
    /// Block number at which affidavit submission ends.
    pub end: BlockNumberFor<T>,
}

/// Represents the **election execution window** for the current session.
///
/// Defines the block range during which election logic is expected
/// to be executed for determining the **next session's validator set**.
///
/// ### Semantics
///
/// - `start`: First block at which election execution may begin.
/// - `end`: Final block for election execution.
#[derive(
    Encode,
    Decode,
    DecodeWithMemTracking,
    Clone,
    RuntimeDebugNoBound,
    PartialEq,
    Eq,
    MaxEncodedLen,
    TypeInfo,
)]
pub struct ElectionWindow<T: Config> {
    /// Block number at which election execution begins.
    pub start: BlockNumberFor<T>,
    /// Block number at which election execution ends.
    pub end: BlockNumberFor<T>,
}