pallet_chain_manager/
routines.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// ````````````````````````````````` OCW ROUTINES ````````````````````````````````
14// ===============================================================================
15
16//! Offchain routines orchestrating the affidavit lifecycle and election execution.
17//!
18//! This module implements a coordinated set of Offchain Worker (OCW) routines
19//! that drive the lifecycle of authors from affidavit key initialization to
20//! election participation and key rotation.
21//!
22//! ## Lifecycle Pipeline
23//!
24//! The system operates as a continuous OCW-driven pipeline:
25//!
26//! ```text
27//! InitAffidavitKey -> TryElection -> DeclareAffidavit -> RotateAffidavitKey
28//! ```
29//!
30//! Each stage is independently executable and relies on repeated OCW execution
31//! across blocks to eventually converge to a consistent state.
32//!
33//! ## Responsibilities
34//!
35//! ### 1. Affidavit Key Initialization (`InitAffidavitKey`)
36//! - Generates an ephemeral affidavit key pair using application crypto.
37//! - Persists the public identifier in [`Finalized`] offchain storage.
38//! - Ensures exactly one active affidavit key exists per node.
39//!
40//! ### 2. Election Execution (`TryElection`)
41//! - Opportunistically attempts to run the election for the upcoming session.
42//! - Uses the currently active affidavit key for authorization.
43//! - Ensures at-most-once execution per author per session.
44//! - Designed to be non-blocking and retry-safe.
45//!
46//! ### 3. Affidavit Declaration (`DeclareAffidavit`)
47//! - Submits a signed affidavit to signal participation in the next
48//!   session's election.
49//! - Prepares and finalizes the next affidavit key for rotation.
50//! - Ensures eligibility and timing constraints via runtime checks.
51//!
52//! ### 4. Key Rotation (`RotateAffidavitKey`)
53//! - Finalizes transition from next -> active affidavit key.
54//! - Confirms successful affidavit submission via runtime state.
55//! - Performs cleanup and ensures lifecycle continuity.
56//!
57//! ## Storage & Finality
58//!
59//! Uses layered offchain storage:
60//! - [`ForkAware`]: fork-safe speculative state  
61//! - [`Persistent`]: durable observation ledger  
62//! - [`Finalized`]: stable values via [`Confidence`]
63//!
64//! Finality is governed by [`FinalizedPolicy`] using:
65//! - time delay ([`FinalityAfter`])
66//! - observation count ([`FinalityTicks`])
67//!
68//! ## Execution Model
69//!
70//! - **Idempotent**: All routines can run repeatedly without side effects.
71//! - **Non-blocking**: Routines exit early when prerequisites are unmet.
72//! - **Opportunistic**: Actions may be attempted before full readiness.
73//! - **Eventually consistent**: Correct state is reached through repetition.
74//!
75//! ## Security Model
76//!
77//! - Uses **ephemeral affidavit keys** instead of long-term authority keys.
78//! - Enforces **key rotation per lifecycle**.
79//! - Limits signing scope to specific operations (affidavit/election).
80//! - Reduces attack surface and key exposure risk.
81//!
82//! ## Failure Handling
83//!
84//! - Storage inconsistencies trigger **hard stops** to prevent unsafe execution.
85//! - Failed extrinsics are logged and retried in future OCW runs.
86//! - Missing runtime reflection (e.g. failed affidavit) triggers **state reset**.
87//!
88//! This ensures the system never remains in a partially inconsistent state.
89
90// ===============================================================================
91// ``````````````````````````````````` IMPORTS ```````````````````````````````````
92// ===============================================================================
93
94// --- Local crate imports ---
95use crate::{
96    crypto::*, types::*, AffidavitKeys, Config, CurrentSession, ElectsPreparedBy, Error,
97    FinalityAfter, FinalityTicks, Internals, Pallet, SessionStartAt,
98};
99
100// --- FRAME Suite ---
101use frame_suite::{ForksHandler, blockchain::*, routines::*};
102
103// --- FRAME Support ---
104use frame_support::traits::EstimateNextSessionRotation;
105
106// --- FRAME System ---
107use frame_system::{
108    offchain::{AppCrypto, SendSignedTransaction, SignedPayload, Signer},
109    pallet_prelude::BlockNumberFor,
110};
111
112// --- Substrate primitives ---
113use sp_runtime::{
114    DispatchError, RuntimeAppPublic, traits::{IdentifyAccount, One, Saturating}
115};
116
117//--- Scale-info ---
118use scale_info::prelude::{format, string::String};
119
120// ===============================================================================
121// ```````````````````````````````` LOG CONSTANTS ````````````````````````````````
122// ===============================================================================
123
124/// Log target (classifier) for affidavit logging.
125///
126/// All pallet-specific offchain logs (affidavits) should
127/// use this target to allow fine-grained filtering at the node level.
128pub const LOG_TARGET_AFDT: Option<&'static str> = Some("AFFIDAVIT");
129
130/// Log target (classifier) for elections logging.
131///
132/// All pallet-specific offchain logs (elections) should
133/// use this target to allow fine-grained filtering at the node level.
134pub const LOG_TARGET_ELEC: Option<&'static str> = Some("ELECTION");
135
136// ===============================================================================
137// ```````````````````````` INITIATE AFFIDAVIT KEY (OCW) `````````````````````````
138// ===============================================================================
139
140// --- Keys ---
141
142/// Offchain key identifier for the **active affidavit key**.
143///
144/// Used as the base identifier for storing and retrieving the
145/// currently active affidavit key from offchain storage.
146///
147/// The value stored under this key must survive fork re-orgs and
148/// confidence evaluation before it is considered safe for usage.
149pub const ACTIVE_AFDT_KEY: &'static [u8] = b"ACTIVE_AFDT_KEY";
150
151// ===============================================================================
152// ```````````````````````````````` LOG FORMATTER ````````````````````````````````
153// ===============================================================================
154
155/// Emoji indicator mapped to each [`LogLevel`] for visual log scanning.
156const EMOJI_DEBUG: &str = "๐Ÿ›";
157const EMOJI_ERROR: &str = "๐Ÿšจ";
158const EMOJI_INFO:  &str = "๐Ÿ“ฃ";
159const EMOJI_WARN:  &str = "โš ๏ธ";
160
161/// Returns the emoji indicator associated with a given [`LogLevel`].
162///
163/// Used internally by [`std_fmt`] to embed a visual severity cue
164/// into the formatted log line.
165#[inline(always)]
166fn level_emoji(level: &LogLevel) -> &'static str {
167    match level {
168        LogLevel::Debug => EMOJI_DEBUG,
169        LogLevel::Error => EMOJI_ERROR,
170        LogLevel::Info  => EMOJI_INFO,
171        LogLevel::Warn  => EMOJI_WARN,
172    }
173}
174
175/// Standard log formatter for OCW routines.
176///
177/// Produces a consistently structured, human-readable log line that
178/// embeds block context, severity, routing target, and message body.
179///
180/// ### Output format
181///
182/// ```text
183/// ๐Ÿงฑ [<block>] <emoji> [<LEVEL>] ๐ŸŽฏ [<target>] ๐Ÿงพ <message>
184/// ```
185///
186/// ### Example
187///
188/// ```text
189/// ๐Ÿงฑ [312] ๐Ÿ“ฃ [Info] ๐ŸŽฏ [AFFIDAVIT] ๐Ÿงพ Module(9): InitAffidavitKeyRoutineSuccess
190/// ```
191pub fn std_fmt<T: Config>(
192    timestamp: BlockNumberFor<T>,
193    level: &LogLevel,
194    target: &str,
195    message: &str,
196) -> String {
197    format!(
198        "๐Ÿงฑ [{:?}] {} [{:?}] ๐ŸŽฏ [{}] ๐Ÿงพ {}",
199        timestamp,
200        level_emoji(level),
201        level,
202        target,
203        message
204    )
205}
206
207// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
208// ``````````````````````````````` ERROR PROVIDERS ```````````````````````````````
209// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
210
211/// Error mapping for **fork-aware speculative storage** access
212/// during affidavit key initialization.
213///
214/// This implementation provides pallet-specific error variants
215/// expected to be convertible into [`DispatchError`](sp_runtime::DispatchError).
216///
217/// ## Scope
218/// - Applies to speculative, fork-aware storage keyed by a hash.
219/// - Focuses on failures related to the speculative hash of the
220///   finalized affidavit key value.
221impl<T: Config> OffchainStorageError<ForkAware<T, ValueHash, InitAffidavitKey<T>, Pallet<T>>>
222    for InitAffidavitKey<T>
223{
224    type Error = Error<T>;
225
226    /// Speculative hash decoding failed.
227    fn decode_failed() -> Self::Error {
228        Error::<T>::ActiveAfdtKeySpeculativeHashDecodeFail
229    }
230
231    /// Concurrent mutation detected while accessing fork-aware storage.
232    fn concurrent_mutation() -> Self::Error {
233        Error::<T>::ActiveAfdtKeySpeculativeHashConcurrentMutation
234    }
235}
236
237/// Error mapping for **persistent finalized offchain storage**
238/// during affidavit key initialization.
239///
240/// This implementation handles failures when interacting with the
241/// persistent ledger that stores finalized affidavit key values,
242/// wrapped in [`Confidence`] to reflect finality guarantees.
243///
244/// ## Scope
245/// - Applies to persistent, non-speculative storage.
246/// - Covers decoding and concurrent mutation failures.
247impl<T: Config> OffchainStorageError<Persistent<T, Ledger<T, AffidavitId<T>>, InitAffidavitKey<T>>>
248    for InitAffidavitKey<T>
249{
250    type Error = Error<T>;
251    /// Finalized value decoding failed.
252    fn decode_failed() -> Self::Error {
253        Error::<T>::ActiveAfdtKeyFinalizedValueDecodeFail
254    }
255    /// Concurrent mutation detected while accessing persistent storage.
256    fn concurrent_mutation() -> Self::Error {
257        Error::<T>::ActiveAfdtKeyFinalizedValueConcurrentMutation
258    }
259}
260
261/// Invariant enforcement for **finalized offchain storage**.
262///
263/// This implementation defines errors for high-level coordination
264/// failures between speculative and persistent storage layers.
265///
266/// Cleanups will be implicitly handled by the storage itself.
267impl<T: Config> FinalizedOffchainStorageError<T, AffidavitId<T>> for InitAffidavitKey<T> {
268    type Error = Error<T>;
269
270    /// A speculative hash **must not exist** without a
271    /// corresponding persistent value.
272    fn hanging_hash() -> Self::Error {
273        Error::<T>::ActiveAfdtKeySpeculativeHangingHash
274    }
275
276    /// A persistent value **must not exist** without holding its corresponding
277    /// speculative hash's value.
278    fn hanging_value() -> Self::Error {
279        Error::<T>::ActiveAfdtKeyFinalizedHangingValue
280    }
281}
282
283// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
284// `````````````````````````````` FINALIZED POLICY ```````````````````````````````
285// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
286
287/// This policy defines when a finalized offchain storage value
288/// is considered **safe for irreversible side effects**, such as:
289/// - key promotion,
290/// - state transitions,
291/// - or cleanup of speculative storage.
292///
293/// The policy is consumed by the [`Finalized`] storage abstraction
294/// in conjunction with [`Confidence`] to determine optimal-finality.
295impl<T: Config> FinalizedPolicy<T> for InitAffidavitKey<T> {
296    /// Returns the wall-clock time after which a value is considered final.
297    fn finality_after() -> <T as pallet_timestamp::Config>::Moment {
298        FinalityAfter::<T>::get()
299    }
300
301    /// Returns the number of block confirmations required to reach finality after
302    /// the wall-clock time reached.
303    fn finality_ticks() -> BlockNumberFor<T> {
304        FinalityTicks::<T>::get()
305    }
306}
307
308// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
309// `````````````````````````````````` ROUTINES ```````````````````````````````````
310// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
311
312/// An Offchain Worker (OCW) routine responsible for initializing the
313/// **active affidavit key** for the local node.
314///
315/// This routine bootstraps an affidavit application key **per node**,
316/// regardless of whether the node is acting as an author i.e.,
317/// validator node.
318///
319/// The affidavit key is a **rotated operational key** used exclusively
320/// for affidavit-related signing. Only a single affidavit key is expected
321/// to be active at any given time, and the runtime relies on this invariant
322/// being upheld.
323impl<T: Config> Routines<BlockNumberFor<T>> for InitAffidavitKey<T> {
324    /// Determines whether the affidavit key initialization routine
325    /// should run.
326    ///
327    /// Initialization **must not run** if:
328    /// - an active affidavit key is already stored in the offchain storage, and
329    /// - the corresponding key pair exists in the node's affidavit keystore (app crypto).
330    ///
331    /// Any storage inconsistency (e.g. corrupted or undecodable data)
332    /// is treated as a **hard stop** and causes the routine to refuse
333    /// execution, since proceeding could violate runtime expectations.
334    fn can_run(&self) -> Result<(), Self::Logger> {
335        // Optimistically retrieve the currently active affidavit key
336        let result =
337            Finalized::<T, AffidavitId<T>, Self, Pallet<T>>::get(ACTIVE_AFDT_KEY, LOG_TARGET_AFDT, None);
338
339        // Only allow confident and safe storage values which are finalized as per our policy.
340        let afdt_key = match result {
341            Ok(None) => return Ok(()),
342            Ok(Some(Confidence::Safe(key))) => key,
343            Ok(Some(_)) => {
344                return Err(<Self as Logging<BlockNumberFor<T>>>::debug(
345                    &Error::<T>::ActiveAfdtKeyNotYetFinalized.into(),
346                    self.at,
347                    LOG_TARGET_AFDT,
348                    Some(std_fmt::<T>),
349                ))
350            }
351            Err(_) => {
352                return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
353                    &Error::<T>::OCWStorageDecisionHalt.into(),
354                    self.at,
355                    LOG_TARGET_AFDT,
356                    Some(std_fmt::<T>),
357                ));
358            }
359        };
360
361        // Retrieve all affidavit keys currently available in the node keystore
362        let all_keys =
363            <<T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::RuntimeAppPublic
364                as RuntimeAppPublic>::all();
365
366        // Fast path: no keys exist in the keystore
367        if all_keys.is_empty() {
368            return Ok(());
369        }
370
371        // Check whether the active affidavit key is already available for signing
372        for key in all_keys.into_iter() {
373            let generic_pub:
374                <T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::GenericPublic =
375                key.into();
376            let public: T::Public = generic_pub.into();
377            let account: AffidavitId<T> = public.clone().into_account().into();
378
379            if account == afdt_key {
380                // Active affidavit key already exists and is usable
381                return Err(<Self as Logging<BlockNumberFor<T>>>::debug(
382                    &Error::<T>::AffidavitKeyExists.into(),
383                    self.at,
384                    LOG_TARGET_AFDT,
385                    Some(std_fmt::<T>),
386                ));
387            }
388        }
389
390        Ok(())
391    }
392
393    /// Initializes a new affidavit key pair and marks it as the
394    /// **active affidavit key** for the node.
395    ///
396    /// This routine:
397    /// 1. Generates a new affidavit application key pair in the local keystore.
398    /// 2. Extracts the public key and derives its corresponding `AffidavitId`.
399    /// 3. Stores the public identifier as the active affidavit key in
400    ///    the offchain storage.
401    ///
402    /// Affidavit keys are **rotated regularly** (e.g. per session). The node's
403    /// long-term authority or author role i.e., stash key is never used directly
404    /// for affidavit signing, reducing operational risk.
405    ///
406    /// If storing the active affidavit key fails, the generated key pair
407    /// becomes unreachable and is effectively discarded. The routine will
408    /// retry on subsequent block OCW executions until initialization succeeds.
409    fn run_service(&self) -> Result<(), Self::Logger> {
410        if let Err(e) = Self::can_run(&self) {
411            // Fast Path if initialization is not required
412            if e == Error::<T>::AffidavitKeyExists.into() {
413                return Ok(());
414            }
415            return Err(e);
416        }
417
418        // Generate a new affidavit application key pair
419        let key =
420            <<T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::RuntimeAppPublic
421                as RuntimeAppPublic>::generate_pair(None);
422
423        // Raw conversions
424        let generic_pub: <T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::GenericPublic =
425            key.into();
426        let public: T::Public = generic_pub.into();
427        let account: AffidavitId<T> = public.clone().into_account().into();
428
429        // Stabilize the public identifier as the active affidavit key
430        if Finalized::<T, AffidavitId<T>, Self, Pallet<T>>::insert(
431            ACTIVE_AFDT_KEY,
432            &account,
433            LOG_TARGET_AFDT,
434            None,
435        )
436        .is_err()
437        {
438            let block = self.at;
439            return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
440                &Error::<T>::SetNewAffidavitKeyFailed.into(),
441                block,
442                LOG_TARGET_AFDT,
443                Some(std_fmt::<T>),
444            ));
445        }
446
447        Ok(())
448    }
449
450    /// Logs a `info` message on a successful [`InitAffidavitKey`] routine.
451    fn on_ran_service(&self) {
452        <Self as Logging<BlockNumberFor<T>>>::debug(
453            &Error::<T>::InitAffidavitKeyRoutineSuccess.into(),
454            self.at,
455            LOG_TARGET_AFDT,
456            Some(std_fmt::<T>),
457        );
458    }
459}
460
461// ===============================================================================
462// ````````````````````````````` TRY ELECTION (OCW) ``````````````````````````````
463// ===============================================================================
464
465// `TryElection` reuses `DeclareAffidavit` offchain storage for key coordination
466// and state tracking, avoiding duplication.
467// No additional offchain key-value storage is defined for this routine.
468
469// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
470// ````````````````````````````````` ROUTINE OF ``````````````````````````````````
471// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
472
473/// Authorization layer for the **election execution routine**.
474///
475/// This implementation resolves the **affidavit public key** authorized
476/// to run the election flow. It deliberately reuses the key-resolution
477/// logic from [`DeclareAffidavit`] to enforce strict lifecycle ordering:
478///
479/// ```text
480/// Affidavit Declaration -> Key Rotation -> Election
481/// ```
482///
483/// By delegating authorization instead of duplicating it, this layer
484/// guarantees that elections are executed only by authors who have
485/// successfully completed the affidavit and key-rotation process.
486impl<T: Config> RoutineOf<T::Public, BlockNumberFor<T>> for TryElection<T> {
487    /// Determines the affidavit public key authorized to run the election routine.
488    ///
489    /// ## Semantics
490    /// - Reuses the **currently active affidavit key** resolved by
491    ///   [`DeclareAffidavit`].
492    /// - Ensures that election execution is authorized by the same
493    ///   operational key that is eligible for affidavit declaration.
494    ///
495    /// ## Rationale
496    /// Elections are permitted **only after** a successful affidavit
497    /// declaration and key-rotation cycle. By delegating to
498    /// `DeclareAffidavit::who`, this routine enforces a strict
499    /// lifecycle ordering without duplicating key-resolution logic.
500    ///
501    /// ## Key Resolution Note
502    /// Although this appears syntactically as the *active affidavit key*,
503    /// it semantically represents the **recently rotated next affidavit key**
504    /// that was promoted to active status by the previous OCW execution's
505    /// final routine ([`RotateAffidavitKey`]).
506    fn who(at: &BlockNumberFor<T>) -> Result<T::Public, Self::Logger> {
507        // Returns only if the Active Affidavit Key is Initialized, Stored and Finalized
508        let who = <DeclareAffidavit<T> as RoutineOf<T::Public, BlockNumberFor<T>>>::who(at)?;
509        Ok(who)
510    }
511}
512
513// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
514// `````````````````````````````````` ROUTINES ```````````````````````````````````
515// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
516
517/// Offchain routine responsible for **opportunistic election execution**.
518///
519/// This routine attempts to submit the `elect` extrinsic for the
520/// upcoming session using the **currently active affidavit key**.
521///
522/// It is intentionally designed to be:
523/// - **Non-blocking**: exits silently when prerequisites are unmet.
524/// - **Idempotent**: safe to run repeatedly across blocks and forks.
525/// - **Pre-emptive**: elections may be attempted before the OCW pipeline
526///   fully converges, succeeding in later executions.
527///
528/// The routine participates in the OCW execution pipeline:
529///
530/// ```text
531/// InitAffidavitKey -> TryElection -> DeclareAffidavit -> RotateAffidavitKey
532/// ```
533///
534/// and relies on repeated OCW invocations to eventually satisfy all
535/// temporal and state-dependent constraints.
536impl<T: Config> Routines<BlockNumberFor<T>> for TryElection<T> {
537    /// Checks whether an election can be processed in the current block.
538    ///
539    /// ## Semantics
540    /// - Delegates election window validation to
541    ///   [`ElectAuthors::can_process_election`].
542    /// - Does **not** treat an unavailable election window as an error.
543    ///
544    /// ## Behavior
545    /// - If the election window is not open, the routine exits early
546    ///   with an informational log.
547    /// - Hard failures (e.g. invalid configuration) are surfaced
548    ///   as logged errors.
549    ///
550    /// This design allows the OCW orchestrator to continue executing
551    /// subsequent routines (e.g. affidavit declaration) in the same block.
552    fn can_run(&self) -> Result<(), Self::Logger> {
553        if let Err(e) =
554            <Internals<T> as ElectAuthors<AuthorOf<T>, ElectionVia<T>>>::can_process_election(&None)
555        {
556            return Err(<Self as Logging<BlockNumberFor<T>>>::debug(
557                &e,
558                self.at,
559                LOG_TARGET_ELEC,
560                Some(std_fmt::<T>),
561            ));
562        }
563        Ok(())
564    }
565
566    /// Attempts to submit the election transaction for the upcoming session.
567    ///
568    /// ## Execution Strategy
569    /// This routine is **opportunistic and non-blocking**:
570    ///
571    /// - If the election window is not open, execution passes silently to next routine.
572    /// - If the author is not eligible, execution exits silently.
573    /// - If the author already acted as the election runner, execution exits silently.
574    ///
575    /// This behavior is intentional and allows the OCW pipeline to be
576    /// orchestrated in the following order:
577    ///
578    /// ```text
579    /// InitAffidavitKey -> TryElection -> DeclareAffidavit -> RotateAffidavitKey
580    /// ```
581    ///
582    /// Elections are therefore attempted *pre-emptively* and may succeed
583    /// in a later OCW invocation once all prerequisites converge.
584    ///
585    /// ## Semantics
586    /// - Uses the **currently active affidavit key** to authorize the election.
587    /// - Submits an unsigned `elect` extrinsic signed offchain.
588    /// - Ensures that each author runs the election at most once per session.
589    ///
590    /// ## Failure Handling
591    /// - All signing or submission failures are logged as errors.
592    /// - No retries are attempted in the same block.
593    /// - Subsequent OCW executions may retry automatically.
594    fn run_service(&self) -> Result<(), Self::Logger> {
595        // Exit early if election window is unavailable
596        // And try the next routine of declaring affidavit
597        if let Err(_) = Self::can_run(&self) {
598            return Ok(());
599        }
600
601        let for_session = CurrentSession::<T>::get().saturating_add(One::one());
602
603        // Resolve author from affidavit key registered for election (session + 2)
604        let afdt_pub: AffidavitId<T> = self.by.clone().into_account().into();
605        let Some(author) =
606            AffidavitKeys::<T>::get((for_session.saturating_add(One::one()), afdt_pub))
607        else {
608            // The active affidavit key is not for elections
609            // but for declaring affidavit
610            <Self as Logging<BlockNumberFor<T>>>::debug(
611                &Error::<T>::AffidavitKeyForDeclaration.into(),
612                self.at,
613                LOG_TARGET_ELEC,
614                Some(std_fmt::<T>),
615            );
616            return Ok(());
617        };
618
619        // Prevent duplicate election execution by the same author
620        // Until this reflects, repeated OCW executions may submit
621        // duplicate transactions which is expected to be filtered by
622        // `ValidateUnsigned`'s `ValidTransaction::and_provides()`
623        if let Some((runner, _)) = ElectsPreparedBy::<T>::get(for_session) {
624            if author == runner {
625                // Already ran election
626                // Try declaring affidavit during the upcoming session
627                return Ok(());
628            }
629        }
630
631        let payload = ElectionPayload {
632            public: self.by.clone(),
633        };
634
635        // Sign election payload using affidavit key
636        let Some(signature) =
637            <ElectionPayload<T::Public> as SignedPayload<T>>::sign::<T::AffidavitCrypto>(&payload)
638        else {
639            return Err(<Self as Logging<BlockNumberFor<T>>>::error(
640                &Error::<T>::CannotSignElectionTxPayload.into(),
641                self.at,
642                LOG_TARGET_ELEC,
643                Some(std_fmt::<T>),
644            ));
645        };
646
647        // Submit election extrinsic
648        let signer = Signer::<T, T::AffidavitCrypto>::any_account();
649        let result = signer.send_signed_transaction(|_| {
650            <T as crate::Config>::RuntimeCall::from(crate::Call::elect {
651                payload: payload.clone(),
652                signature: signature.clone(),
653            })
654            .into()
655        });
656
657        match result {
658            Some((_, Ok(_))) => Ok(()),
659
660            Some((_, Err(_))) => Err(<Self as Logging<BlockNumberFor<T>>>::error(
661                &Error::<T>::ExtrinsicFailedToElectAuthors.into(),
662                self.at,
663                LOG_TARGET_ELEC,
664                Some(std_fmt::<T>),
665            )),
666
667            None => Err(<Self as Logging<BlockNumberFor<T>>>::error(
668                &Error::<T>::CannotSubmitElectionTx.into(),
669                self.at,
670                LOG_TARGET_ELEC,
671                Some(std_fmt::<T>),
672            )),
673        }
674    }
675
676    /// Logs a `info` message on a successful [`TryElection`] routine.
677    fn on_ran_service(&self) {
678        <Self as Logging<BlockNumberFor<T>>>::debug(
679            &Error::<T>::TryElectionRoutineSuccess.into(),
680            self.at,
681            LOG_TARGET_ELEC,
682            Some(std_fmt::<T>),
683        );
684    }
685}
686
687// ===============================================================================
688// ``````````````````````````` DECLARE AFFIDAVIT (OCW) ```````````````````````````
689// ===============================================================================
690
691// --- Keys ---
692
693/// Offchain storage key identifying the **next affidavit key**.
694///
695/// This key represents the affidavit public identifier that:
696/// - is declared during the current affidavit window,
697/// - undergoes finality evaluation via [`Finalized`] storage semantics,
698/// - and is later promoted to the **active affidavit key**
699///   by the [`RotateAffidavitKey`] routine.
700///
701/// The value stored under this key is **session-forward looking** and
702/// must survive fork re-orgs and confidence evaluation before it is
703/// considered safe for activation.
704pub const NEXT_AFDT_KEY: &'static [u8] = b"NEXT_AFDT_KEY";
705
706// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
707// ``````````````````````````````` ERROR PROVIDERS ```````````````````````````````
708// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
709
710/// Error policy for **fork-aware speculative storage** of the next affidavit key.
711///
712/// This implementation defines how storage-layer failures originating
713/// from fork-aware offchain storage are surfaced as
714/// routine-specific [`DispatchError`](sp_runtime::DispatchError) values.
715///
716/// These errors relate exclusively to the **speculative identity**
717/// (`ValueHash`) used to track the next affidavit key across forks.
718///
719/// Any failure reported here:
720/// - is logged exactly once by the storage layer,
721/// - and returned unchanged to the caller.
722impl<T: Config> OffchainStorageError<ForkAware<T, ValueHash, DeclareAffidavit<T>, Pallet<T>>>
723    for DeclareAffidavit<T>
724{
725    type Error = Error<T>;
726
727    /// Returned when decoding the speculative hash fails.
728    ///
729    /// Indicates corrupted or unexpected fork-local storage state.
730    fn decode_failed() -> Self::Error {
731        Error::<T>::NextAfdtKeySpeculativeHashDecodeFail
732    }
733
734    /// Returned when a concurrent mutation of the speculative hash is detected.
735    ///
736    /// Indicates overlapping OCW executions or race conditions.
737    fn concurrent_mutation() -> Self::Error {
738        Error::<T>::NextAfdtKeySpeculativeHashConcurrentMutation
739    }
740}
741
742/// Error policy for **persistent finalized storage** of the next affidavit key.
743///
744/// This implementation defines error signaling for failures that occur
745/// while interacting with the persistent observation ledger backing
746/// the [`Finalized`] storage model.
747///
748/// These errors concern the **finalized value and its observation history**,
749/// not speculative fork-local state.
750impl<T: Config> OffchainStorageError<Persistent<T, Ledger<T, AffidavitId<T>>, DeclareAffidavit<T>>>
751    for DeclareAffidavit<T>
752{
753    type Error = Error<T>;
754
755    /// Returned when decoding the persistent ledger entry fails.
756    ///
757    /// Indicates corrupted or incompatible persisted offchain data.
758    fn decode_failed() -> Self::Error {
759        Error::<T>::NextAfdtKeyFinalizedValueDecodeFail
760    }
761
762    /// Returned when a concurrent mutation of the persistent ledger is detected.
763    ///
764    /// Indicates contention between multiple OCW executions.
765    fn concurrent_mutation() -> Self::Error {
766        Error::<T>::NextAfdtKeyFinalizedValueConcurrentMutation
767    }
768}
769
770/// Finality-specific invariant errors for the next affidavit key.
771///
772/// These errors are emitted when semantic inconsistencies are detected
773/// between fork-aware and persistent storage layers.
774///
775/// Such conditions indicate **partial or invalid state**, and the
776/// storage layer automatically performs cleanup before returning
777/// these errors.
778impl<T: Config> FinalizedOffchainStorageError<T, AffidavitId<T>> for DeclareAffidavit<T> {
779    type Error = Error<T>;
780
781    /// Emitted when a speculative fork-aware hash exists
782    /// without a corresponding persistent ledger entry.
783    fn hanging_hash() -> Self::Error {
784        Error::<T>::NextAfdtKeySpeculativeHangingHash
785    }
786
787    /// Emitted when **persistent storage contains no value** corresponding to
788    /// an existing speculative (fork-aware) hash.
789    fn hanging_value() -> Self::Error {
790        Error::<T>::NextAfdtKeyFinalizedHangingValue
791    }
792}
793
794// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
795// `````````````````````````````` FINALIZED POLICY ```````````````````````````````
796// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
797
798/// Finality evaluation policy for the **next affidavit key**.
799///
800/// This implementation **reuses the finality parameters defined by
801/// [`InitAffidavitKey`]**, ensuring that both the *active* and *next*
802/// affidavit keys are evaluated under **identical confidence guarantees**.
803///
804/// ## Design Rationale
805///
806/// Every routine that uses [`Finalized`] storage:
807/// - must define exactly **one finality policy**, and
808/// - that policy is **scoped to the routine**, not to the storage backend.
809///
810/// Since the *next affidavit key* participates in the **same operational
811/// lifecycle** as the active affidavit key (generation -> observation -> rotation),
812/// it is intentionally governed by the same time- and observation-based
813/// confidence thresholds.
814///
815/// ## Invariants
816///
817/// - [`Finalized`] storage is **strictly constrained**:
818///   - one logical value per routine,
819///   - one finality policy per value.
820/// - Unlike [`ForkAware`] or [`Persistent`] storage backends, [`Finalized`]
821///   does **not** allow multiple independent values or heterogeneous policies.
822///
823/// Reusing the policy from [`InitAffidavitKey`] preserves these invariants
824/// while avoiding duplicated configuration and potential divergence.
825impl<T: Config> FinalizedPolicy<T> for DeclareAffidavit<T> {
826    /// Wall-clock delay required before confidence evaluation begins.
827    fn finality_after() -> <T as pallet_timestamp::Config>::Moment {
828        <InitAffidavitKey<T> as FinalizedPolicy<T>>::finality_after()
829    }
830
831    /// Number of block-scoped observations required to reach strong confidence.
832    fn finality_ticks() -> BlockNumberFor<T> {
833        <InitAffidavitKey<T> as FinalizedPolicy<T>>::finality_ticks()
834    }
835}
836
837// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
838// `````````````````````````````````` ROUTINE OF `````````````````````````````````
839// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
840
841/// Declares the authorization requirements for the [`DeclareAffidavit`] routine.
842///
843/// This implementation specifies **who is permitted to execute** the routine
844/// at a given point in time.
845///
846/// The routine is restricted to the node's **active affidavit key**. This
847/// ensures that affidavit declarations are signed only by the currently
848/// designated, rotated operational key, rather than by long-term authority
849/// or stash keys.
850///
851/// The returned `T::Public` value represents the concrete public key that
852/// must be used to sign the affidavit payload at the given block number.
853impl<T: Config> RoutineOf<T::Public, BlockNumberFor<T>> for DeclareAffidavit<T> {
854    /// Determines which public key is authorized to execute this routine.
855    ///
856    /// ## Why this check exists
857    ///
858    /// Affidavit declarations are security-sensitive operations. To reduce
859    /// the blast radius of key compromise and to support regular key rotation,
860    /// only the **currently active affidavit key** is permitted to authorize
861    /// this routine.
862    ///
863    /// The active affidavit key:
864    /// - is stored and ensured by [`Finalized`] offchain storage,
865    /// - is expected to have a corresponding key pair in the node's keystore,
866    /// - and must be explicitly initialized before this routine can run.
867    ///
868    /// ## Failure semantics
869    ///
870    /// - Any storage inconsistency is treated as a **hard error**, since it
871    ///   indicates corrupted or unexpected node state.
872    /// - If no active affidavit key is configured, the caller is considered
873    ///   misconfigured and execution is refused.
874    /// - If the active affidavit key exists but the corresponding key pair
875    ///   is missing from the keystore, execution is refused.
876    fn who(at: &BlockNumberFor<T>) -> Result<T::Public, Self::Logger> {
877        // Initialized by `InitAffidavitKey`; reused here to avoid duplicating implementations
878        let result = Finalized::<T, AffidavitId<T>, InitAffidavitKey<T>, Pallet<T>>::get(
879            ACTIVE_AFDT_KEY,
880            LOG_TARGET_AFDT,
881            None,
882        );
883
884        let afdt_key = match result {
885            Ok(Some(Confidence::Safe(key))) => key,
886            Ok(None) => {
887                return Err(<Self as Logging<BlockNumberFor<T>>>::error(
888                    &Error::<T>::ExpectedToHoldActiveAffidavitKey.into(),
889                    *at,
890                    LOG_TARGET_AFDT,
891                    Some(std_fmt::<T>),
892                ))
893            }
894            Ok(Some(_)) => {
895                return Err(<Self as Logging<BlockNumberFor<T>>>::debug(
896                    &Error::<T>::ActiveAfdtKeyNotYetFinalized.into(),
897                    *at,
898                    LOG_TARGET_AFDT,
899                    Some(std_fmt::<T>),
900                ))
901            }
902            Err(_) => {
903                return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
904                    &Error::<T>::OCWStorageDecisionHalt.into(),
905                    *at,
906                    LOG_TARGET_AFDT,
907                    Some(std_fmt::<T>),
908                ));
909            }
910        };
911
912        // Retrieve all affidavit keys currently available in the local keystore
913        let all_keys =
914            <<T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::RuntimeAppPublic
915                as RuntimeAppPublic>::all();
916
917        // Ensure the active affidavit key has a corresponding key pair
918        for key in all_keys.into_iter() {
919            let generic_pub:
920                <T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::GenericPublic =
921                key.into();
922            let public: T::Public = generic_pub.into();
923            let account: AffidavitId<T> = public.clone().into_account().into();
924
925            if account == afdt_key {
926                // Authorized signer found
927                return Ok(public);
928            }
929        }
930
931        // Active affidavit key exists but is not usable for signing
932        Err(<Self as Logging<BlockNumberFor<T>>>::error(
933            &Error::<T>::ExpectedActiveAffidavitKeyPairNotFound.into(),
934            *at,
935            LOG_TARGET_AFDT,
936            Some(std_fmt::<T>),
937        ))
938    }
939}
940
941// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
942// ``````````````````````````````````` ROUTINES ``````````````````````````````````
943// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
944
945/// Offchain routine responsible for **affidavit declaration** and
946/// **preparing key rotation for the next election cycle**.
947///
948/// ## What an affidavit represents
949///
950/// Declaring an affidavit signals that an author:
951/// - is **ready to participate in the upcoming election**, and
952/// - satisfies all protocol-defined requirements (e.g. backing, support).
953///
954/// An affidavit:
955/// - is submitted via an **unsigned extrinsic**,
956/// - is allowed **only within a bounded affidavit window**, and
957/// - is restricted to **valid authors** holding the correct operational role.
958///
959/// ## Responsibilities of this routine
960///
961/// This OCW routine performs the **offchain coordination** required to:
962///
963/// 1. Verify that affidavit submission is currently permitted.
964/// 2. Ensure a **next affidavit key** exists and is finalized.
965/// 3. Submit the `declare` extrinsic using the **active affidavit key**.
966/// 4. Attach the **next affidavit key** for rotation into the upcoming session.
967///
968/// ## Key separation and security
969///
970/// - Long-term authority / stash keys are **never used** here.
971/// - All signing is performed using **ephemeral affidavit keys**
972///   managed via application crypto and rotated regularly.
973/// - This minimizes the blast radius of key compromise and
974///   enables strict lifecycle enforcement.
975///
976/// ## Execution model
977///
978/// This routine is designed to be **optimistic and non-blocking**:
979///
980/// - It may be executed before the node has fully completed validation
981/// via `validate` extrinsic.
982/// - Runtime-side checks ultimately decide whether the extrinsic succeeds.
983/// - Failures are logged and retried automatically in later OCW executions.
984///
985/// This makes the routine safe to run repeatedly without risking
986/// inconsistent on-chain state.
987impl<T: Config> Routines<BlockNumberFor<T>> for DeclareAffidavit<T> {
988    /// Determines whether the affidavit declaration routine may proceed.
989    ///
990    /// ## Semantics
991    ///
992    /// - Ensures that a **next affidavit key** exists in finalized offchain
993    ///   storage, else initiates and finalizes one.
994    /// - Verifies that the **current affidavit key** is eligible to submit
995    ///   an affidavit in the runtime.
996    ///
997    /// ## Key handling
998    ///
999    /// - The active affidavit key (`self.by`) **must already exist** in the
1000    ///   node's keystore.
1001    /// - Author primary keys are **never consulted**.
1002    ///
1003    /// ## Optimistic execution
1004    ///
1005    /// This function may be called **before** the author has successfully
1006    /// executed the on-chain `validate`.
1007    ///
1008    /// That is safe because:
1009    /// - Runtime-side checks enforce correctness.
1010    /// - This routine merely prepares and submits the transaction.
1011    ///
1012    /// If the author has not yet validated their affidavit key on-chain,
1013    /// the submission will be rejected harmlessly.
1014    fn can_run(&self) -> Result<(), Self::Logger> {
1015        let afdt_pub = &self.by;
1016        let block = self.at;
1017
1018        // Ensure a next affidavit key exists (or create one)
1019        let result =
1020            Finalized::<T, AffidavitId<T>, Self, Pallet<T>>::get(NEXT_AFDT_KEY, LOG_TARGET_AFDT, None);
1021
1022        match result {
1023            // No next key yet -> generate and persist one
1024            Ok(None) => {
1025                let new_key =
1026                    <<T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::RuntimeAppPublic
1027                        as RuntimeAppPublic>::generate_pair(None);
1028
1029                let public: T::Public = {
1030                    let generic_pub:
1031                        <T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::GenericPublic =
1032                        new_key.into();
1033                    generic_pub.into()
1034                };
1035
1036                let new_afdt_key = public.clone().into_account();
1037
1038                if Finalized::<T, AffidavitId<T>, Self, Pallet<T>>::insert(
1039                    NEXT_AFDT_KEY,
1040                    &new_afdt_key,
1041                    LOG_TARGET_AFDT,
1042                    None,
1043                )
1044                .is_err()
1045                {
1046                    return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1047                        &Error::<T>::SetNextAffidavitKeyFailed.into(),
1048                        block,
1049                        LOG_TARGET_AFDT,
1050                        Some(std_fmt::<T>),
1051                    ));
1052                }
1053                return Err(<Self as Logging<BlockNumberFor<T>>>::debug(
1054                    &Error::<T>::NextAfdtKeyNotYetFinalized.into(),
1055                    block,
1056                    LOG_TARGET_AFDT,
1057                    Some(std_fmt::<T>),
1058                ));
1059            }
1060
1061            // Next key exists and finalized
1062            Ok(Some(Confidence::Safe(_))) => {}
1063
1064            Ok(Some(_)) => {
1065                return Err(<Self as Logging<BlockNumberFor<T>>>::debug(
1066                    &Error::<T>::NextAfdtKeyNotYetFinalized.into(),
1067                    block,
1068                    LOG_TARGET_AFDT,
1069                    Some(std_fmt::<T>),
1070                ))
1071            }
1072
1073            // Storage inconsistency -> hard stop
1074            Err(_) => {
1075                return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1076                    &Error::<T>::OCWStorageDecisionHalt.into(),
1077                    block,
1078                    LOG_TARGET_AFDT,
1079                    Some(std_fmt::<T>),
1080                ));
1081            }
1082        }
1083
1084        // Check runtime-level affidavit eligibility
1085        if let Err(e) =
1086            <Pallet<T> as ElectionAffidavits<AffidavitId<T>, ElectionVia<T>>>::can_submit_affidavit(
1087                (&afdt_pub.clone().into_account()).into(),
1088            )
1089        {
1090            return Err(<Self as Logging<BlockNumberFor<T>>>::debug(
1091                &e,
1092                block,
1093                LOG_TARGET_AFDT,
1094                Some(std_fmt::<T>),
1095            ));
1096        }
1097
1098        Ok(())
1099    }
1100
1101    /// Submits the `declare` extrinsic.
1102    ///
1103    /// ## Preconditions
1104    ///
1105    /// - The active affidavit key is authorized and present in the keystore.
1106    /// - The next affidavit key exists and has reached sufficient finality.
1107    ///
1108    /// ## Behavior
1109    ///
1110    /// - Signs the affidavit payload using the **current affidavit key**.
1111    /// - Includes the **next affidavit key** for rotation.
1112    /// - Submits the extrinsic to the transaction pool.
1113    ///
1114    /// ## Important notes
1115    ///
1116    /// - This routine **does not apply any on-chain state changes itself**.
1117    /// - It only submits a transaction; actual effects occur later
1118    ///   during block execution.
1119    /// - Any failure is logged and retried in future OCW runs.
1120    fn run_service(&self) -> Result<(), Self::Logger> {
1121        Self::can_run(self)?;
1122
1123        let afdt_key = &self.by;
1124        let block = self.at;
1125
1126        let result =
1127            Finalized::<T, AffidavitId<T>, Self, Pallet<T>>::get(NEXT_AFDT_KEY, LOG_TARGET_AFDT, None);
1128
1129        let next_afdt_key = match result {
1130            Ok(Some(Confidence::Safe(key))) => key,
1131            Ok(Some(_)) => {
1132                return Err(<Self as Logging<BlockNumberFor<T>>>::error(
1133                    &Error::<T>::ExpectedToHoldFinalizedNextAffidavitKey.into(),
1134                    block,
1135                    LOG_TARGET_AFDT,
1136                    Some(std_fmt::<T>),
1137                ))
1138            }
1139            Ok(None) => {
1140                return Err(<Self as Logging<BlockNumberFor<T>>>::error(
1141                    &Error::<T>::ExpectedToHoldFinalizedNextAffidavitKey.into(),
1142                    block,
1143                    LOG_TARGET_AFDT,
1144                    Some(std_fmt::<T>),
1145                ))
1146            }
1147            Err(_) => {
1148                return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1149                    &Error::<T>::OCWStorageDecisionHalt.into(),
1150                    block,
1151                    LOG_TARGET_AFDT,
1152                    Some(std_fmt::<T>),
1153                ))
1154            }
1155        };
1156
1157        let payload = AffidavitPayload {
1158            public: afdt_key.clone(),
1159            rotate: next_afdt_key.clone(),
1160        };
1161
1162        let Some(signature) =
1163            <AffidavitPayload<T::Public, AffidavitId<T>> as SignedPayload<T>>::sign::<
1164                T::AffidavitCrypto,
1165            >(&payload)
1166        else {
1167            return Err(<Self as Logging<BlockNumberFor<T>>>::error(
1168                &Error::<T>::CannotSignAffidavitTxPayload.into(),
1169                block,
1170                LOG_TARGET_AFDT,
1171                Some(std_fmt::<T>),
1172            ));
1173        };
1174
1175        let signer = Signer::<T, T::AffidavitCrypto>::any_account();
1176
1177        // If repeated OCW executions, this may result in duplicate transactions which
1178        // shall be filtered out by `ValidateUnsigned`'s `ValidTransaction::and_provides()`
1179        let result = signer.send_signed_transaction(|_| {
1180            <T as crate::Config>::RuntimeCall::from(crate::Call::<T>::declare {
1181                payload: payload.clone(),
1182                signature: signature.clone(),
1183            })
1184            .into()
1185        });
1186
1187        match result {
1188            Some((_, Ok(_))) => Ok(()),
1189
1190            Some((_, Err(_))) => Err(<Self as Logging<BlockNumberFor<T>>>::error(
1191                &Error::<T>::FailedToDeclareAffidavit.into(),
1192                block,
1193                LOG_TARGET_AFDT,
1194                Some(std_fmt::<T>),
1195            )),
1196
1197            None => Err(<Self as Logging<BlockNumberFor<T>>>::error(
1198                &Error::<T>::CannotSubmitAffidavitTx.into(),
1199                block,
1200                LOG_TARGET_AFDT,
1201                Some(std_fmt::<T>),
1202            )),
1203        }
1204    }
1205
1206    /// Logs a `info` message on a successful [`DeclareAffidavit`] routine.
1207    fn on_ran_service(&self) {
1208        <Self as Logging<BlockNumberFor<T>>>::debug(
1209            &Error::<T>::DeclarAffidavitRoutineSuccess.into(),
1210            self.at,
1211            LOG_TARGET_AFDT,
1212            Some(std_fmt::<T>),
1213        );
1214    }
1215}
1216// ===============================================================================
1217// ````````````````````````` ROTATE AFFIDAVIT KEY (OCW) ``````````````````````````
1218// ===============================================================================
1219
1220// `RotateAffidavitKey` reuses `DeclareAffidavit` and `InitAffidavitKey` offchain
1221// storage for key coordination and state tracking, avoiding duplication.
1222// No additional offchain key-value storage is defined for this routine.
1223
1224// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1225// ````````````````````````````````` ROUTINE OF ``````````````````````````````````
1226// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1227
1228/// Authorization layer for affidavit key rotation.
1229///
1230/// Resolves the **finalized next affidavit key** prepared by
1231/// [`DeclareAffidavit`] and ensures it is locally usable for signing.
1232///
1233/// This enforces that rotation is performed only with a key that:
1234/// - has reached finality, and
1235/// - exists in the node's keystore.
1236impl<T: Config> RoutineOf<T::Public, BlockNumberFor<T>> for RotateAffidavitKey<T> {
1237    /// Determines the next affidavit public key authorized to **finalize key rotation**.
1238    ///
1239    /// ## Semantics
1240    ///
1241    /// - Resolves the **next affidavit key** previously prepared and finalized
1242    ///   by the [`DeclareAffidavit`] routine.
1243    /// - Requires the key to be in a [`Confidence::Safe`] state, ensuring it has
1244    ///   survived fork re-orgs and met finality requirements.
1245    ///
1246    /// ## Lifecycle position
1247    ///
1248    /// Reaching this routine implies:
1249    ///
1250    /// - The `declare` extrinsic has already been **submitted**, and
1251    /// - The node is now waiting to observe whether that transaction has been
1252    ///   **accepted and reflected in runtime storage**.
1253    ///
1254    /// This routine therefore does **not generate or mutate keys**. It only:
1255    /// - re-reads the finalized *next* affidavit key, and
1256    /// - verifies that the corresponding key pair still exists in the local keystore.
1257    ///
1258    /// ## Failure semantics
1259    ///
1260    /// - Missing or non-finalized next affidavit key is treated as a hard stop.
1261    /// - Storage inconsistencies indicate OCW coordination failure and halt execution.
1262    /// - If the key exists in storage but not in the keystore, the node is considered
1263    ///   misconfigured.
1264    fn who(at: &BlockNumberFor<T>) -> Result<T::Public, Self::Logger> {
1265        let result = Finalized::<T, AffidavitId<T>, DeclareAffidavit<T>, Pallet<T>>::get(
1266            NEXT_AFDT_KEY,
1267            LOG_TARGET_AFDT,
1268            None,
1269        );
1270
1271        let afdt_key = match result {
1272            Ok(Some(Confidence::Safe(key))) => key,
1273
1274            Ok(None) => {
1275                return Err(<Self as Logging<BlockNumberFor<T>>>::error(
1276                    &Error::<T>::ExpectedToHoldFinalizedNextAffidavitKey.into(),
1277                    *at,
1278                    LOG_TARGET_AFDT,
1279                    Some(std_fmt::<T>),
1280                ))
1281            }
1282
1283            Ok(Some(_)) => {
1284                return Err(<Self as Logging<BlockNumberFor<T>>>::info(
1285                    &Error::<T>::ExpectedToHoldFinalizedNextAffidavitKey.into(),
1286                    *at,
1287                    LOG_TARGET_AFDT,
1288                    Some(std_fmt::<T>),
1289                ))
1290            }
1291
1292            Err(_) => {
1293                return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1294                    &Error::<T>::OCWStorageDecisionHalt.into(),
1295                    *at,
1296                    LOG_TARGET_AFDT,
1297                    Some(std_fmt::<T>),
1298                ));
1299            }
1300        };
1301
1302        // Ensure the finalized next affidavit key exists in the local keystore
1303        let all_keys =
1304            <<T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::RuntimeAppPublic
1305                as RuntimeAppPublic>::all();
1306
1307        for key in all_keys {
1308            let generic_pub:
1309                <T::AffidavitCrypto as AppCrypto<T::Public, T::Signature>>::GenericPublic =
1310                key.into();
1311            let public: T::Public = generic_pub.into();
1312            let account: AffidavitId<T> = public.clone().into_account().into();
1313
1314            if account == afdt_key {
1315                return Ok(public);
1316            }
1317        }
1318
1319        // Finalized key exists, but no signing key is available locally
1320        Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1321            &Error::<T>::ExpectedNextAffidavitKeyPairNotFound.into(),
1322            *at,
1323            LOG_TARGET_AFDT,
1324            Some(std_fmt::<T>),
1325        ))
1326    }
1327}
1328
1329// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1330// `````````````````````````````````` ROUTINES ```````````````````````````````````
1331// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1332
1333/// Offchain routine responsible for **finalizing affidavit key rotation**.
1334///
1335/// Completes the lifecycle by promoting the finalized next affidavit key
1336/// to active status once the runtime reflects successful affidavit submission.
1337///
1338/// This routine:
1339/// - waits for on-chain confirmation of the rotated key,
1340/// - performs a safe transition from next -> active key,
1341/// - resets state on failure to avoid inconsistent lifecycle progression.
1342///
1343/// Designed to be idempotent and driven by repeated OCW execution.
1344impl<T: Config> Routines<BlockNumberFor<T>> for RotateAffidavitKey<T> {
1345    /// Determines whether affidavit key rotation may be finalized.
1346    ///
1347    /// ## Semantics
1348    ///
1349    /// - Checks whether the **next affidavit key** has been successfully
1350    ///   registered in runtime storage for the **session after next**
1351    ///   (`current_session + 2`) (for which next election will be conducted).
1352    /// - Presence of this key in [`AffidavitKeys`] is treated as confirmation
1353    ///   that the `declare` extrinsic was accepted.
1354    ///
1355    /// ## Waiting behavior
1356    ///
1357    /// - If the key is not yet visible, the routine waits passively.
1358    /// - While the affidavit window is still open, this is logged as
1359    ///   an informational "awaiting status" condition.
1360    ///
1361    /// ## Failure and recovery
1362    ///
1363    /// If the affidavit window has **closed** and:
1364    /// - the next affidavit key is still not registered, then
1365    /// - the system assumes the affidavit transaction failed or was dropped.
1366    ///
1367    /// In that case:
1368    /// - All affidavit-related offchain state is cleared.
1369    /// - Active validation is considered stopped.
1370    /// - The node must restart the lifecycle via `validate` extrinsic in a later block.
1371    ///
1372    /// This aggressive reset prevents the OCW from getting stuck
1373    /// in a half-rotated or inconsistent state.
1374    fn can_run(&self) -> Result<(), Self::Logger> {
1375        let current_session = CurrentSession::<T>::get();
1376        let for_session = current_session.saturating_add(2);
1377        let next_afdt_pub: AffidavitId<T> = self.by.clone().into_account().into();
1378
1379        if !AffidavitKeys::<T>::contains_key((for_session, next_afdt_pub)) {
1380            // Determine end of session
1381            let session_start = SessionStartAt::<T>::get();
1382            let avg_session_len =
1383                <<T as crate::Config>::NextSessionRotation as EstimateNextSessionRotation<
1384                    BlockNumberFor<T>,
1385                >>::average_session_length();
1386            let end_block = session_start.saturating_add(avg_session_len);
1387
1388            // If window expired, perform hard recovery
1389            if self.at >= end_block {
1390                Finalized::<T, AffidavitId<T>, DeclareAffidavit<T>, Pallet<T>>::remove(
1391                    NEXT_AFDT_KEY,
1392                    LOG_TARGET_AFDT,
1393                    None,
1394                )
1395                .map_err(|_| {
1396                    <Self as Logging<BlockNumberFor<T>>>::warn(
1397                        &Error::<T>::OCWStorageDecisionHalt.into(),
1398                        self.at,
1399                        LOG_TARGET_AFDT,
1400                        Some(std_fmt::<T>),
1401                    )
1402                })?;
1403
1404                Finalized::<T, AffidavitId<T>, InitAffidavitKey<T>, Pallet<T>>::remove(
1405                    ACTIVE_AFDT_KEY,
1406                    LOG_TARGET_AFDT,
1407                    None,
1408                )
1409                .map_err(|_| {
1410                    <Self as Logging<BlockNumberFor<T>>>::warn(
1411                        &Error::<T>::OCWStorageDecisionHalt.into(),
1412                        self.at,
1413                        LOG_TARGET_AFDT,
1414                        Some(std_fmt::<T>),
1415                    )
1416                })?;
1417
1418                return Err(<T as Logging<BlockNumberFor<T>>>::error(
1419                    &Error::<T>::ValidationStopped.into(),
1420                    self.at,
1421                    LOG_TARGET_AFDT,
1422                    Some(std_fmt::<T>),
1423                ));
1424            }
1425
1426            // Still waiting for runtime reflection
1427            return Err(<T as Logging<BlockNumberFor<T>>>::debug(
1428                &Error::<T>::AffidavitTxAwaitingStatus.into(),
1429                self.at,
1430                LOG_TARGET_AFDT,
1431                Some(std_fmt::<T>),
1432            ));
1433        }
1434
1435        Ok(())
1436    }
1437
1438    /// Finalizes affidavit key rotation after successful affidavit acceptance.
1439    ///
1440    /// ## Behavior
1441    ///
1442    /// Once the runtime reflects the rotated affidavit key:
1443    ///
1444    /// 1. The **next affidavit key** is removed from finalized offchain storage.
1445    /// 2. The **active affidavit key** is updated to the rotated key.
1446    ///
1447    /// This completes the affidavit lifecycle for the current session and
1448    /// enables subsequent OCW executions to:
1449    /// - attempt elections via [`TryElection`], and
1450    /// - later begin a new affidavit cycle.
1451    ///
1452    /// ## Guarantees
1453    ///
1454    /// - Rotation is performed **exactly once** per successful affidavit.
1455    /// - Any storage failure is treated as a coordination halt.
1456    fn run_service(&self) -> Result<(), Self::Logger> {
1457        Self::can_run(self)?;
1458
1459        Finalized::<T, AffidavitId<T>, DeclareAffidavit<T>, Pallet<T>>::remove(
1460            NEXT_AFDT_KEY,
1461            LOG_TARGET_AFDT,
1462            None,
1463        )
1464        .map_err(|_| {
1465            <Self as Logging<BlockNumberFor<T>>>::warn(
1466                &Error::<T>::OCWStorageDecisionHalt.into(),
1467                self.at,
1468                LOG_TARGET_AFDT,
1469                Some(std_fmt::<T>),
1470            )
1471        })?;
1472
1473        Finalized::<T, AffidavitId<T>, InitAffidavitKey<T>, Pallet<T>>::mutate(
1474            ACTIVE_AFDT_KEY,
1475            |_| Ok(self.by.clone().into_account().into()),
1476            LOG_TARGET_AFDT,
1477            None,
1478        )
1479        .map_err(|_| {
1480            <Self as Logging<BlockNumberFor<T>>>::warn(
1481                &Error::<T>::OCWStorageDecisionHalt.into(),
1482                self.at,
1483                LOG_TARGET_AFDT,
1484                Some(std_fmt::<T>),
1485            )
1486        })?;
1487
1488        Ok(())
1489    }
1490
1491    /// Logs a `info` message on a successful [`RotateAffidavitKey`] routine.
1492    fn on_ran_service(&self) {
1493        <Self as Logging<BlockNumberFor<T>>>::debug(
1494            &Error::<T>::RotateAffidavitKeyRoutineSuccess.into(),
1495            self.at,
1496            LOG_TARGET_AFDT,
1497            Some(std_fmt::<T>),
1498        );
1499    }
1500}
1501
1502// ===============================================================================
1503// ``````````````````````````````` ROUTINES HANDLER ``````````````````````````````
1504// ===============================================================================
1505
1506/// Implements the fork graph management for this pallet's offchain worker.
1507///
1508/// Binds the pallet to the [`ForksHandler`] trait using [`ForkLocalDepot`]
1509/// as the scope type, wiring fork graph constants and error variants defined
1510/// in [`Config`] and [`Error`] into the fork resolution and recovery logic.
1511///
1512/// This impl is the prerequisite for calling [`ForksHandler::start`] inside
1513/// [`Hooks::offchain_worker`](frame_support::traits::Hooks::offchain_worker), 
1514/// which resolves the current fork branch before any routine executes.
1515impl<T: Config> ForksHandler<T, ForkLocalDepot> for Pallet<T> {
1516    const TAG: &[u8] = b"pallet_chain_manager";
1517
1518    const MAX_FORKS: u32 = T::MAX_FORKS;
1519
1520    const MAX_RECOVER_TRAVERSAL: u32 = T::MAX_FORK_RECOVERY_TRAVERSAL;
1521
1522    fn max_forks_error() -> DispatchError {
1523        Error::<T>::MaxOCWForksAttained.into()
1524    }
1525    
1526    fn forks_not_enabled() -> DispatchError {
1527        Error::<T>::OCWForksNotEnabled.into()
1528    }
1529    
1530    fn inconsistent_forks() -> DispatchError {
1531        Error::<T>::OCWForksInconsistent.into()
1532    }
1533}
1534
1535// ===============================================================================
1536// ```````````````````````````````` ROUTINES TESTS ```````````````````````````````
1537// ===============================================================================
1538
1539#[cfg(test)]
1540pub mod tests {
1541
1542    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1543    // ```````````````````````````````````` IMPORTS ``````````````````````````````````
1544    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1545
1546    // --- Local crate imports ---
1547    use crate::mock::*;
1548
1549    // --- Scale-codec crates ---
1550    use codec::Encode;
1551
1552    // --- FRAME Benchmarking ---
1553    use frame_benchmarking::account;
1554
1555    // --- FRAME Suite ---
1556    use frame_suite::routines::*;
1557
1558    // --- FRAME Support ---
1559    use frame_support::{assert_err, assert_ok, traits::{EstimateNextSessionRotation}};
1560
1561    // --- Substrate primitives ---
1562    use sp_core::blake2_256;
1563    
1564    // --- std ---
1565    use std::collections::BTreeMap;
1566
1567    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1568    // `````````````````````````````` INIT-AFFIDAVIT-KEY `````````````````````````````
1569    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1570
1571    #[test]
1572    fn init_affidavit_key_can_run_return_err_affidavit_key_exists() {
1573        let mut env = new_ocw_env();
1574        env.ext.execute_with(|| {
1575            init_fork_graph();
1576            let aff_id = generate_affidavit_id();
1577            insert_active_afdt_key(aff_id).unwrap();
1578            run_to_block(20);
1579            let routine = InitAffidavitKey { at: 20 };
1580
1581            assert_err!(routine.can_run(), Error::AffidavitKeyExists);
1582        })
1583    }
1584
1585    #[test]
1586    fn init_affidavit_key_can_run_return_err_active_afdt_key_not_yet_finalized() {
1587        let mut env = new_ocw_env();
1588        env.ext.execute_with(|| {
1589            init_fork_graph();
1590            let aff_id = generate_affidavit_id();
1591            insert_active_afdt_key(aff_id).unwrap();
1592            run_to_block(10);
1593            let routine = InitAffidavitKey { at: 10 };
1594            assert_err!(routine.can_run(), Error::ActiveAfdtKeyNotYetFinalized);
1595        })
1596    }
1597
1598    #[test]
1599    fn init_affidavit_key_can_run_return_ok_since_aff_key_dose_not_exists_in_keystore() {
1600        let mut env = new_ocw_env();
1601        env.ext.execute_with(|| {
1602            init_fork_graph();
1603            let aff_id: AffidavitId = account("dummy", 1, 1);
1604            insert_active_afdt_key(aff_id).unwrap();
1605            run_to_block(20);
1606            let routine = InitAffidavitKey { at: 20 };
1607            assert_ok!(routine.can_run());
1608        })
1609    }
1610
1611    #[test]
1612    fn init_affidavit_key_run_service_returns_ok_since_affidavit_key_already_exists() {
1613        let mut env = new_ocw_env();
1614        env.ext.execute_with(|| {
1615            init_fork_graph();
1616            let aff_id = generate_affidavit_id();
1617            insert_active_afdt_key(aff_id).unwrap();
1618            run_to_block(20);
1619            let routine = InitAffidavitKey { at: 20 };
1620            assert_ok!(routine.run_service());
1621        })
1622    }
1623
1624    #[test]
1625    fn init_affidavit_key_run_service_returns_ok_after_successful_initialization() {
1626        let mut env = new_ocw_env();
1627        env.ext.execute_with(|| {
1628            init_fork_graph();
1629            let routine = InitAffidavitKey { at: 10 }; 
1630            assert_ok!(routine.can_run());
1631            let aff_key = get_afdt_key();
1632            assert!(aff_key.is_none());
1633            assert_eq!(affidavit_key_count(), 0);
1634            assert_ok!(routine.run_service());
1635            assert_err!(routine.can_run(), Error::ActiveAfdtKeyNotYetFinalized);
1636            run_to_block(30);
1637            assert_err!(routine.can_run(), Error::AffidavitKeyExists);
1638            let aff_key = get_finalized_afdt_key();
1639            assert!(aff_key.is_some());
1640            assert_eq!(affidavit_key_count(), 1);
1641        })
1642    }
1643
1644    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1645    // ````````````````````````````````` TRY-ELECTION ````````````````````````````````
1646    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1647
1648    #[test]
1649    fn try_election_can_run_returns_ok() {
1650        let mut env = new_ocw_env();
1651        env.ext.execute_with(|| {
1652            init_fork_graph();
1653            let aff_id = generate_affidavit_id();
1654            insert_active_afdt_key(aff_id.clone()).unwrap();
1655            let pub_afdt = get_public_key(aff_id.clone()).unwrap();
1656            run_to_block(300);
1657            let election_routine = TryElection {
1658                by: pub_afdt,
1659                at: 300,
1660            };
1661            assert_ok!(election_routine.can_run());
1662        })
1663    }
1664
1665    #[test]
1666    fn try_election_can_run_returns_err_not_affidavit_period() {
1667        let mut env = new_ocw_env();
1668        env.ext.execute_with(|| {
1669            init_fork_graph();
1670            let aff_id = generate_affidavit_id();
1671            insert_active_afdt_key(aff_id.clone()).unwrap();
1672            let pub_afdt = get_public_key(aff_id.clone()).unwrap();
1673            run_to_block(250);
1674            let election_routine = TryElection {
1675                by: pub_afdt,
1676                at: 250,
1677            };
1678            assert_err!(election_routine.can_run(), Error::NotElectionPeriod);
1679        })
1680    }
1681
1682    #[test]
1683    fn try_election_run_service_returns_ok_not_election_window() {
1684        let mut env = new_ocw_env();
1685        env.ext.execute_with(|| {
1686            init_fork_graph();
1687            let aff_id = generate_affidavit_id();
1688            insert_active_afdt_key(aff_id.clone()).unwrap();
1689            let pub_afdt = get_public_key(aff_id.clone()).unwrap();
1690            run_to_block(250);
1691            let election_routine = TryElection {
1692                by: pub_afdt,
1693                at: 250,
1694            };
1695            assert_ok!(election_routine.run_service());
1696        })
1697    }
1698
1699    #[test]
1700    fn try_election_run_service_returns_ok_for_duplicate_election_execution() {
1701        let mut env = new_ocw_env();
1702        env.ext.execute_with(|| {
1703            CurrentSession::put(1);
1704            SessionStartsAt::put(1);
1705            init_fork_graph();
1706            run_to_block(10);
1707            let aff_id = generate_affidavit_id();
1708            insert_active_afdt_key(aff_id.clone()).unwrap();
1709            let pub_afdt = get_public_key(aff_id.clone()).unwrap();
1710
1711            set_default_user_balance_and_hold(ALICE).unwrap();
1712            set_default_user_balance_and_hold(ALAN).unwrap();
1713
1714            enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
1715            direct_fund_author(ALAN, ALICE, 500).unwrap();
1716
1717            // Simulate declared affidavit
1718            let for_session = CurrentSession::get() + 2;
1719            let afdt_key = get_afdt_key().unwrap();
1720            AffidavitKeys::insert((for_session, afdt_key), ALICE);
1721            // Simulate election already executed
1722            let for_session = CurrentSession::get() + 1;
1723            ElectsPreparedBy::insert(for_session, (ALICE, 310));
1724
1725            run_to_block(350);
1726            let election_routine = TryElection {
1727                by: pub_afdt,
1728                at: 350,
1729            };
1730            assert_ok!(election_routine.run_service());
1731            let txs_len = env.pool_state.read().transactions.len();
1732            assert_eq!(txs_len, 0);
1733        })
1734    }
1735
1736    #[test]
1737    fn try_election_run_service_returns_ok_when_extrinsic_submitted_succesfully() {
1738        let mut env = new_ocw_env();
1739        env.ext.execute_with(|| {
1740            CurrentSession::put(1);
1741            SessionStartsAt::put(1);
1742            init_fork_graph();
1743            run_to_block(10);
1744            let aff_id = generate_affidavit_id();
1745            insert_active_afdt_key(aff_id.clone()).unwrap();
1746            let pub_afdt = get_public_key(aff_id.clone()).unwrap();
1747
1748            set_default_user_balance_and_hold(ALICE).unwrap();
1749            set_default_user_balance_and_hold(ALAN).unwrap();
1750
1751            enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
1752            direct_fund_author(ALAN, ALICE, 500).unwrap();
1753
1754            let aff_window = compute_affidavit_window().unwrap();
1755            let aff_begin = aff_window.start;
1756            run_to_block(aff_begin);
1757            AllowAffidavits::put(true);
1758            let for_session = CurrentSession::get() + 2;
1759            let afdt_key = get_finalized_afdt_key().unwrap();
1760            // declare affidavit simulation
1761            AffidavitKeys::insert((for_session, afdt_key), ALICE);
1762
1763            run_to_block(350);
1764            let election_routine = TryElection {
1765                by: pub_afdt,
1766                at: 350,
1767            };
1768
1769            let tx_len = env.pool_state.read().transactions.len();
1770            assert_eq!(tx_len, 0);
1771            assert_ok!(election_routine.run_service());
1772            let tx_len = env.pool_state.read().transactions.len();
1773            assert_eq!(tx_len, 1);
1774        })
1775    }
1776
1777    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1778    // `````````````````````````````` DECLARE-AFFIDAVIT ``````````````````````````````
1779    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1780
1781    #[test]
1782    fn declare_affidavit_who_returns_public_key() {
1783        let mut env = new_ocw_env();
1784        env.ext.execute_with(|| {
1785            init_fork_graph();
1786            let init_routine = InitAffidavitKey { at: 10 };
1787            init_routine.run_service().unwrap();
1788            run_to_block(30);
1789            let afdt_key = get_finalized_afdt_key().unwrap();
1790            let public_key = get_public_key(afdt_key);
1791            assert!(public_key.is_some());
1792            let pub_key = public_key.unwrap();
1793
1794            let who = DeclareAffidavit::who(&30).unwrap();
1795            assert_eq!(who, pub_key);
1796        })
1797    }
1798
1799    #[test]
1800    fn declare_affidavit_who_returns_err_expected_to_hold_active_affidavit_key() {
1801        let mut env = new_ocw_env();
1802        env.ext.execute_with(|| {
1803            init_fork_graph();
1804            let who = DeclareAffidavit::who(&10);
1805            assert!(who.is_err());
1806            assert_err!(who, Error::ExpectedToHoldActiveAffidavitKey);
1807        })
1808    }
1809
1810    #[test]
1811    fn declare_affidavit_who_returns_err_active_afdt_key_not_yet_finalized() {
1812        let mut env = new_ocw_env();
1813        env.ext.execute_with(|| {
1814            init_fork_graph();
1815            FinalityAfter::put(60_000);
1816            let init_routine = InitAffidavitKey { at: 10 };
1817            init_routine.run_service().unwrap();
1818            run_to_block(15);
1819            let who = DeclareAffidavit::who(&10);
1820            assert!(who.is_err());
1821            assert_err!(who, Error::ActiveAfdtKeyNotYetFinalized);
1822        })
1823    }
1824
1825    #[test]
1826    fn declare_affidavit_who_returns_err_expected_active_affidavit_key_pair_not_found() {
1827        let mut env = new_ocw_env();
1828        env.ext.execute_with(|| {
1829            init_fork_graph();
1830            let aff_id: AffidavitId = account("dummy", 1, 1);
1831            insert_active_afdt_key(aff_id).unwrap();
1832            run_to_block(20);
1833            let who = DeclareAffidavit::who(&10);
1834            assert!(who.is_err());
1835            assert_err!(who, Error::ExpectedActiveAffidavitKeyPairNotFound);
1836        })
1837    }
1838
1839    #[test]
1840    fn declare_affidavit_can_run_returns_ok() {
1841        let mut env = new_ocw_env();
1842        env.ext.execute_with(|| {
1843            SessionStartsAt::put(1);
1844            init_fork_graph();
1845            let init_routine = InitAffidavitKey { at: 10 };
1846            init_routine.run_service().unwrap();
1847            run_to_block(30);
1848            let afdt_key = get_finalized_afdt_key().unwrap();
1849            let public_key = get_public_key(afdt_key.clone());
1850            assert!(public_key.is_some());
1851            let pub_key = public_key.unwrap();
1852
1853            set_default_user_balance_and_hold(ALICE).unwrap();
1854            set_default_user_balance_and_hold(ALAN).unwrap();
1855
1856            enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
1857            direct_fund_author(ALAN, ALICE, 500).unwrap();
1858
1859            let aff_window = compute_affidavit_window().unwrap();
1860            let aff_begin = aff_window.start;
1861            run_to_block(aff_begin);
1862            AllowAffidavits::put(true);
1863            let declare_routine = DeclareAffidavit {
1864                by: pub_key,
1865                at: aff_begin + 5,
1866            };
1867
1868            run_to_block(aff_begin + 5);
1869            assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
1870            let for_session = CurrentSession::get() + 1;
1871            // Validate
1872            AffidavitKeys::insert((for_session, afdt_key), ALICE);
1873            run_to_block(aff_begin + 30);
1874            assert_ok!(declare_routine.can_run());
1875        })
1876    }
1877
1878    #[test]
1879    fn declate_affidavit_run_service_submits_the_extrinsic_and_returns_ok() {
1880        let mut env = new_ocw_env();
1881        env.ext.execute_with(|| {
1882            init_fork_graph();
1883            SessionStartsAt::put(1);
1884            let init_routine = InitAffidavitKey { at: 10 };
1885            init_routine.run_service().unwrap();
1886            run_to_block(30);
1887            let afdt_key = get_finalized_afdt_key().unwrap();
1888            let public_key = get_public_key(afdt_key.clone());
1889            assert!(public_key.is_some());
1890            let pub_key = public_key.unwrap();
1891
1892            set_default_user_balance_and_hold(ALICE).unwrap();
1893            set_default_user_balance_and_hold(ALAN).unwrap();
1894
1895            enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
1896            direct_fund_author(ALAN, ALICE, 500).unwrap();
1897
1898            let aff_window = compute_affidavit_window().unwrap();
1899            let aff_begin = aff_window.start;
1900            run_to_block(aff_begin);
1901            AllowAffidavits::put(true);
1902            let declare_routine = DeclareAffidavit {
1903                by: pub_key,
1904                at: aff_begin + 5,
1905            };
1906
1907            run_to_block(aff_begin + 5);
1908            assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
1909            let for_session = CurrentSession::get() + 1;
1910            // Validate
1911            AffidavitKeys::insert((for_session, afdt_key), ALICE);
1912            run_to_block(aff_begin + 30);
1913            let txs_len = env.pool_state.read().transactions.len();
1914            assert_eq!(txs_len, 0);
1915            assert_ok!(declare_routine.run_service());
1916            let txs_len = env.pool_state.read().transactions.len();
1917            assert_eq!(txs_len, 1);
1918        })
1919    }
1920
1921    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1922    // ```````````````````````````` ROTATE-AFFIDAVIT-KEY `````````````````````````````
1923    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1924
1925    #[test]
1926    fn rotate_affidavit_key_who_returns_public_key() {
1927        let mut env = new_ocw_env();
1928        env.ext.execute_with(|| {
1929            SessionStartsAt::put(1);
1930            init_fork_graph();
1931            let init_routine = InitAffidavitKey { at: 10 };
1932            init_routine.run_service().unwrap();
1933            run_to_block(30);
1934            let afdt_key = get_finalized_afdt_key().unwrap();
1935            let public_key = get_public_key(afdt_key.clone());
1936            assert!(public_key.is_some());
1937            let pub_key = public_key.unwrap();
1938
1939            set_default_user_balance_and_hold(ALICE).unwrap();
1940            set_default_user_balance_and_hold(ALAN).unwrap();
1941
1942            enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
1943            direct_fund_author(ALAN, ALICE, 500).unwrap();
1944
1945            let aff_window = compute_affidavit_window().unwrap();
1946            let aff_begin = aff_window.start;
1947            run_to_block(aff_begin);
1948            AllowAffidavits::put(true);
1949            let declare_routine = DeclareAffidavit {
1950                by: pub_key,
1951                at: aff_begin + 5,
1952            };
1953
1954            run_to_block(aff_begin + 5);
1955            assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
1956            let for_session = CurrentSession::get() + 1;
1957            // Validate
1958            AffidavitKeys::insert((for_session, afdt_key), ALICE);
1959            run_to_block(aff_begin + 30);
1960            let txs_len = env.pool_state.read().transactions.len();
1961            assert_eq!(txs_len, 0);
1962            assert_ok!(declare_routine.run_service());
1963            let txs_len = env.pool_state.read().transactions.len();
1964            assert_eq!(txs_len, 1);
1965
1966            let rotate_afdt_key = get_finalized_next_afdt_key();
1967            assert!(rotate_afdt_key.is_some());
1968            let rotate_afdt_key = rotate_afdt_key.unwrap();
1969            let rotate_pub_key = get_public_key(rotate_afdt_key).unwrap();
1970
1971            let rotate_at = aff_begin + 35;
1972            let _rotate_routine = RotateAffidavitKey {
1973                by: rotate_pub_key.clone(),
1974                at: rotate_at,
1975            };
1976            run_to_block(rotate_at);
1977            let actual_rotate_pub_key = RotateAffidavitKey::who(&rotate_at).unwrap();
1978            assert_eq!(actual_rotate_pub_key, rotate_pub_key);
1979        })
1980    }
1981
1982    #[test]
1983    fn rotate_affidavit_key_who_returns_err_expected_to_hold_finalized_next_afdt_key() {
1984        let mut env = new_ocw_env();
1985        env.ext.execute_with(|| {
1986            SessionStartsAt::put(1);
1987            init_fork_graph();
1988            let init_routine = InitAffidavitKey { at: 10 };
1989            init_routine.run_service().unwrap();
1990            run_to_block(30);
1991            let afdt_key = get_finalized_afdt_key().unwrap();
1992            let public_key = get_public_key(afdt_key.clone());
1993            assert!(public_key.is_some());
1994            let pub_key = public_key.unwrap();
1995
1996            set_default_user_balance_and_hold(ALICE).unwrap();
1997            set_default_user_balance_and_hold(ALAN).unwrap();
1998
1999            enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
2000            direct_fund_author(ALAN, ALICE, 500).unwrap();
2001
2002            let aff_window = compute_affidavit_window().unwrap();
2003            let aff_begin = aff_window.start;
2004            run_to_block(aff_begin);
2005            AllowAffidavits::put(true);
2006            let declare_routine = DeclareAffidavit {
2007                by: pub_key,
2008                at: aff_begin + 5,
2009            };
2010
2011            run_to_block(aff_begin + 5);
2012            assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
2013            let for_session = CurrentSession::get() + 1;
2014            // Validate
2015            AffidavitKeys::insert((for_session, afdt_key), ALICE);
2016
2017            let rotate_afdt_key = get_next_afdt_key();
2018            assert!(rotate_afdt_key.is_some());
2019            let rotate_afdt_key = rotate_afdt_key.unwrap();
2020            let rotate_pub_key = get_public_key(rotate_afdt_key).unwrap();
2021
2022            let rotate_at = aff_begin + 10;
2023            let _rotate_routine = RotateAffidavitKey {
2024                by: rotate_pub_key.clone(),
2025                at: rotate_at,
2026            };
2027            run_to_block(rotate_at);
2028            assert_err!(
2029                RotateAffidavitKey::who(&rotate_at),
2030                Error::ExpectedToHoldFinalizedNextAffidavitKey
2031            );
2032        })
2033    }
2034
2035    #[test]
2036    fn rotate_affidavit_key_can_run_returns_ok() {
2037        let mut env = new_ocw_env();
2038        env.ext.execute_with(|| {
2039            SessionStartsAt::put(1);
2040            init_fork_graph();
2041            let init_routine = InitAffidavitKey { at: 10 };
2042            init_routine.run_service().unwrap();
2043            run_to_block(30);
2044            let afdt_key = get_finalized_afdt_key().unwrap();
2045            let public_key = get_public_key(afdt_key.clone());
2046            assert!(public_key.is_some());
2047            let pub_key = public_key.unwrap();
2048
2049            set_default_user_balance_and_hold(ALICE).unwrap();
2050            set_default_user_balance_and_hold(ALAN).unwrap();
2051
2052            enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
2053            direct_fund_author(ALAN, ALICE, 500).unwrap();
2054
2055            let aff_window = compute_affidavit_window().unwrap();
2056            let aff_begin = aff_window.start;
2057            run_to_block(aff_begin);
2058            AllowAffidavits::put(true);
2059            let declare_routine = DeclareAffidavit {
2060                by: pub_key,
2061                at: aff_begin + 5,
2062            };
2063
2064            run_to_block(aff_begin + 5);
2065            assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
2066            let for_session = CurrentSession::get() + 1;
2067            // Validate
2068            AffidavitKeys::insert((for_session, afdt_key), ALICE);
2069            run_to_block(aff_begin + 30);
2070            let txs_len = env.pool_state.read().transactions.len();
2071            assert_eq!(txs_len, 0);
2072            assert_ok!(declare_routine.run_service());
2073            let txs_len = env.pool_state.read().transactions.len();
2074            assert_eq!(txs_len, 1);
2075            let rotate_afdt_key = get_finalized_next_afdt_key();
2076            assert!(rotate_afdt_key.is_some());
2077            let rotate_afdt_key = rotate_afdt_key.unwrap();
2078            let rotate_pub_key = get_public_key(rotate_afdt_key.clone()).unwrap();
2079
2080            let rotate_at = aff_begin + 35;
2081            let rotate_routine = RotateAffidavitKey {
2082                by: rotate_pub_key.clone(),
2083                at: rotate_at,
2084            };
2085            run_to_block(rotate_at);
2086            let for_session = CurrentSession::get() + 2;
2087            // Declare affidavit extrinsic executed simulation
2088            AffidavitKeys::insert((for_session, rotate_afdt_key), ALICE);
2089            assert_ok!(rotate_routine.can_run());
2090        })
2091    }
2092
2093    #[test]
2094    fn rotate_affidavit_key_can_run_returns_err_affidavit_tx_awaiting_status() {
2095        let mut env = new_ocw_env();
2096        env.ext.execute_with(|| {
2097            SessionStartsAt::put(1);
2098            init_fork_graph();
2099            let init_routine = InitAffidavitKey { at: 10 };
2100            init_routine.run_service().unwrap();
2101            run_to_block(30);
2102            let afdt_key = get_finalized_afdt_key().unwrap();
2103            let public_key = get_public_key(afdt_key.clone());
2104            assert!(public_key.is_some());
2105            let pub_key = public_key.unwrap();
2106
2107            set_default_user_balance_and_hold(ALICE).unwrap();
2108            set_default_user_balance_and_hold(ALAN).unwrap();
2109
2110            enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
2111            direct_fund_author(ALAN, ALICE, 500).unwrap();
2112
2113            let aff_window = compute_affidavit_window().unwrap();
2114            let aff_begin = aff_window.start;
2115            run_to_block(aff_begin);
2116            AllowAffidavits::put(true);
2117            let declare_routine = DeclareAffidavit {
2118                by: pub_key,
2119                at: aff_begin + 5,
2120            };
2121
2122            run_to_block(aff_begin + 5);
2123            assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
2124            let for_session = CurrentSession::get() + 1;
2125            // Validate
2126            AffidavitKeys::insert((for_session, afdt_key), ALICE);
2127            run_to_block(aff_begin + 30);
2128            let txs_len = env.pool_state.read().transactions.len();
2129            assert_eq!(txs_len, 0);
2130            assert_ok!(declare_routine.run_service());
2131            let txs_len = env.pool_state.read().transactions.len();
2132            assert_eq!(txs_len, 1);
2133            let rotate_afdt_key = get_finalized_next_afdt_key();
2134            assert!(rotate_afdt_key.is_some());
2135            let rotate_afdt_key = rotate_afdt_key.unwrap();
2136            let rotate_pub_key = get_public_key(rotate_afdt_key.clone()).unwrap();
2137
2138            let rotate_at = aff_begin + 35;
2139            let rotate_routine = RotateAffidavitKey {
2140                by: rotate_pub_key.clone(),
2141                at: rotate_at,
2142            };
2143            run_to_block(rotate_at);
2144            // Declare affidavit not yet executed
2145            assert_err!(rotate_routine.can_run(), Error::AffidavitTxAwaitingStatus);
2146        })
2147    }
2148
2149    #[test]
2150    fn rotate_affidavit_key_can_run_returns_err_validation_stopped_when_window_expired() {
2151        let mut env = new_ocw_env();
2152        env.ext.execute_with(|| {
2153            SessionStartsAt::put(1);
2154            init_fork_graph();
2155            let init_routine = InitAffidavitKey { at: 10 };
2156            init_routine.run_service().unwrap();
2157            run_to_block(30);
2158            let afdt_key = get_finalized_afdt_key().unwrap();
2159            let public_key = get_public_key(afdt_key.clone());
2160            assert!(public_key.is_some());
2161            let pub_key = public_key.unwrap();
2162
2163            set_default_user_balance_and_hold(ALICE).unwrap();
2164            set_default_user_balance_and_hold(ALAN).unwrap();
2165
2166            enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
2167            direct_fund_author(ALAN, ALICE, 500).unwrap();
2168
2169            let aff_window = compute_affidavit_window().unwrap();
2170            let aff_begin = aff_window.start;
2171            run_to_block(aff_begin);
2172            AllowAffidavits::put(true);
2173            let declare_routine = DeclareAffidavit {
2174                by: pub_key,
2175                at: aff_begin + 5,
2176            };
2177
2178            run_to_block(aff_begin + 5);
2179            assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
2180            let for_session = CurrentSession::get() + 1;
2181            // Validate
2182            AffidavitKeys::insert((for_session, afdt_key), ALICE);
2183            run_to_block(aff_begin + 30);
2184            let txs_len = env.pool_state.read().transactions.len();
2185            assert_eq!(txs_len, 0);
2186            assert_ok!(declare_routine.run_service());
2187            let txs_len = env.pool_state.read().transactions.len();
2188            assert_eq!(txs_len, 1);
2189            let rotate_afdt_key = get_finalized_next_afdt_key();
2190            assert!(rotate_afdt_key.is_some());
2191            let rotate_afdt_key = rotate_afdt_key.unwrap();
2192            let rotate_pub_key = get_public_key(rotate_afdt_key.clone()).unwrap();
2193
2194            let avg_session_len: BlockNumber = NextSessionRotation::average_session_length();
2195            let rotate_at = avg_session_len + 10;
2196            let rotate_routine = RotateAffidavitKey {
2197                by: rotate_pub_key.clone(),
2198                at: rotate_at,
2199            };
2200            run_to_block(rotate_at);
2201            // Declare affidavit not yet executed and the session window expired
2202            assert_err!(rotate_routine.can_run(), Error::ValidationStopped);
2203            let aff_key = get_afdt_key();
2204            assert!(aff_key.is_none());
2205            let next_aff_key = get_next_afdt_key();
2206            assert!(next_aff_key.is_none());
2207        })
2208    }
2209
2210    #[test]
2211    fn rotate_affidavit_key_run_service_returns_ok() {
2212        let mut env = new_ocw_env();
2213        env.ext.execute_with(|| {
2214            SessionStartsAt::put(1);
2215            init_fork_graph();
2216            let init_routine = InitAffidavitKey { at: 10 };
2217            init_routine.run_service().unwrap();
2218            run_to_block(30);
2219            let afdt_key = get_finalized_afdt_key().unwrap();
2220            let public_key = get_public_key(afdt_key.clone());
2221            assert!(public_key.is_some());
2222            let pub_key = public_key.unwrap();
2223
2224            set_default_user_balance_and_hold(ALICE).unwrap();
2225            set_default_user_balance_and_hold(ALAN).unwrap();
2226
2227            enroll_authors_with_default_collateral(vec![ALICE]).unwrap();
2228            direct_fund_author(ALAN, ALICE, 500).unwrap();
2229
2230            let aff_window = compute_affidavit_window().unwrap();
2231            let aff_begin = aff_window.start;
2232            run_to_block(aff_begin);
2233            AllowAffidavits::put(true);
2234            let declare_routine = DeclareAffidavit {
2235                by: pub_key,
2236                at: aff_begin + 5,
2237            };
2238
2239            run_to_block(aff_begin + 5);
2240            assert_err!(declare_routine.can_run(), Error::NextAfdtKeyNotYetFinalized);
2241            let for_session = CurrentSession::get() + 1;
2242            // Validate
2243            AffidavitKeys::insert((for_session, afdt_key), ALICE);
2244            run_to_block(aff_begin + 30);
2245            let txs_len = env.pool_state.read().transactions.len();
2246            assert_eq!(txs_len, 0);
2247            assert_ok!(declare_routine.run_service());
2248            let txs_len = env.pool_state.read().transactions.len();
2249            assert_eq!(txs_len, 1);
2250            let rotate_afdt_key = get_finalized_next_afdt_key();
2251            assert!(rotate_afdt_key.is_some());
2252            let rotate_afdt_key = rotate_afdt_key.unwrap();
2253            let rotate_pub_key = get_public_key(rotate_afdt_key.clone()).unwrap();
2254
2255            let rotate_at = aff_begin + 35;
2256            let rotate_routine = RotateAffidavitKey {
2257                by: rotate_pub_key.clone(),
2258                at: rotate_at,
2259            };
2260            run_to_block(rotate_at);
2261            let for_session = CurrentSession::get() + 2;
2262            // Declare affidavit extrinsic executed simulation
2263            AffidavitKeys::insert((for_session, rotate_afdt_key.clone()), ALICE);
2264
2265            assert_ok!(rotate_routine.run_service());
2266            let next_afdt_key = get_next_afdt_key();
2267            assert!(next_afdt_key.is_none());
2268            let afdt_key = get_afdt_key();
2269            assert!(afdt_key.is_some());
2270            assert_eq!(afdt_key.unwrap(), rotate_afdt_key);
2271        })
2272    }
2273
2274    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2275    // `````````````````````````` FINALIZED (OFFCHAIN-STORE) `````````````````````````
2276    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2277    #[test]
2278    fn finalized_insert_success() {
2279        let mut env = new_ocw_env();
2280        env.ext.execute_with(|| {
2281            init_fork_graph();
2282            let key = b"ACTIVE_KEY";
2283            let value: AccountId = account("dummyid", 1, 1);
2284            assert_ok!(FinalizedInitAfdtKey::insert(key, &value, None, None));
2285
2286            let fork_aware_value = ForkAwareInitAfdtKey::get(key, None, None).unwrap();
2287            assert!(fork_aware_value.is_some());
2288            let value_hash = fork_aware_value.unwrap();
2289
2290            let persistent_value = PersistentInitAfdtKey::get(key, None, None).unwrap();
2291            assert!(persistent_value.is_some());
2292            let ledger = persistent_value.unwrap();
2293            let observation = ledger.0.get(&value_hash).unwrap();
2294            assert_eq!(observation.first_seen, 12000);
2295            assert_eq!(observation.last_seen, 12000);
2296            assert_eq!(observation.blocks_seen, 0);
2297            assert_eq!(observation.value, value);
2298        })
2299    }
2300
2301    #[test]
2302    fn finalized_get_success() {
2303        let mut env = new_ocw_env();
2304        env.ext.execute_with(|| {
2305            let key = b"ACTIVE_KEY";
2306            init_fork_graph();
2307            let value: AccountId = account("dummyid", 1, 1);
2308            assert_ok!(FinalizedInitAfdtKey::insert(key, &value, None, None));
2309
2310            // since, the first_seen + finalty_after > last_seen and obs_block < finalty_ticks
2311            // confidance = Unsafe(value)
2312            let finalized_get = FinalizedInitAfdtKey::get(key, None, None).unwrap();
2313            assert!(finalized_get.is_some());
2314            let confidance_value = finalized_get.unwrap();
2315            assert_eq!(confidance_value, Confidence::Unsafe(value.clone()));
2316
2317            // since, the first_seen + finalty_after < last_seen and obs_block < finalty_ticks
2318            // confidance = Risky(value)
2319            run_to_block_with_finalized_key(12, key);
2320            let finalized_get = FinalizedInitAfdtKey::get(key, None, None).unwrap();
2321            assert!(finalized_get.is_some());
2322            let confidance_value = finalized_get.unwrap();
2323            assert_eq!(confidance_value, Confidence::Risky(value.clone()));
2324
2325            // since, the first_seen + finalty_after < last_seen and obs_block >= finalty_ticks
2326            // confidance = Safe(value)
2327            run_to_block_with_finalized_key(17, key);
2328            let finalized_get = FinalizedInitAfdtKey::get(key, None, None).unwrap();
2329            assert!(finalized_get.is_some());
2330            let confidance_value = finalized_get.unwrap();
2331            assert_eq!(confidance_value, Confidence::Safe(value));
2332        })
2333    }
2334
2335    #[test]
2336    fn finalized_get_returns_err_due_to_hanging_value() {
2337        let mut env = new_ocw_env();
2338        env.ext.execute_with(|| {
2339            init_fork_graph();
2340            let key = b"ACTIVE_KEY";
2341            let value: AccountId = account("dummyid", 1, 1);
2342            let hash = blake2_256(&value.encode());
2343            let value_hash = ValueHash::new(hash);
2344            assert_ok!(ForkAwareInitAfdtKey::insert(key, &value_hash, None, None));
2345
2346            let finalized_get = FinalizedInitAfdtKey::get(key, None, None);
2347            assert!(finalized_get.is_err());
2348            let e = finalized_get.unwrap_err();
2349            assert_eq!(e, Error::ActiveAfdtKeyFinalizedHangingValue.into());
2350
2351            // forkaware entry cleaned due to hanging value
2352            let forkaware_lookup = ForkAwareInitAfdtKey::get(key, None, None).unwrap();
2353            assert!(forkaware_lookup.is_none());
2354        })
2355    }
2356
2357    #[test]
2358    fn finalized_get_returns_err_due_to_hanging_hash() {
2359        let mut env = new_ocw_env();
2360        env.ext.execute_with(|| {
2361            init_fork_graph();
2362            let key = b"ACTIVE_KEY";
2363            let value: AccountId = account("dummyid", 1, 1);
2364            let hash = blake2_256(&value.encode());
2365            let value_hash = ValueHash::new(hash);
2366
2367            assert_ok!(ForkAwareInitAfdtKey::insert(key, &value_hash, None, None));
2368
2369            let other_value: AccountId = account("otherdummyid", 1, 1);
2370            let other_hash = blake2_256(&other_value.encode());
2371            let other_value_hash = ValueHash::new(other_hash);
2372
2373            let observation = Observation::<Test, AccountId> {
2374                first_seen: 6000,
2375                last_seen: 6000,
2376                blocks_seen: 0,
2377                value: other_value,
2378            };
2379
2380            let mut map = BTreeMap::new();
2381            map.insert(other_value_hash, observation);
2382
2383            let ledger = Ledger::<Test, AccountId>(map);
2384
2385            assert_ok!(PersistentInitAfdtKey::insert(
2386                key,
2387                &ledger,
2388                None,
2389                None
2390            ));
2391
2392            let finalized_get = FinalizedInitAfdtKey::get(key, None, None);
2393            assert!(finalized_get.is_err());
2394
2395            let e = finalized_get.unwrap_err();
2396            assert_eq!(e, Error::ActiveAfdtKeySpeculativeHangingHash.into());
2397
2398            let forkaware_lookup = ForkAwareInitAfdtKey::get(key, None, None).unwrap();
2399            assert!(forkaware_lookup.is_none());
2400            let persistent = PersistentInitAfdtKey::get(key, None, None).unwrap();
2401            assert!(persistent.is_some());
2402        })
2403    }
2404
2405    #[test]
2406    fn finalized_remove_success() {
2407        let mut env = new_ocw_env();
2408        env.ext.execute_with(|| {
2409            init_fork_graph();
2410            let key = b"ACTIVE_KEY";
2411            let value: AccountId = account("dummyid", 1, 1);
2412            assert_ok!(FinalizedInitAfdtKey::insert(key, &value, None, None));
2413
2414            let finalized_inspect = FinalizedInitAfdtKey::get(key, None, None).unwrap();
2415            assert!(finalized_inspect.is_some());
2416
2417            assert_ok!(FinalizedInitAfdtKey::remove(key, None, None));
2418
2419            let finalized_inspect = FinalizedInitAfdtKey::get(key, None, None).unwrap();
2420            assert!(finalized_inspect.is_none());
2421        })
2422    }
2423
2424    #[test]
2425    fn finalized_mutate_success() {
2426        let mut env = new_ocw_env();
2427        env.ext.execute_with(|| {
2428            init_fork_graph();
2429            let key = b"ACTIVE_KEY";
2430            let value: AccountId = account("dummyid", 1, 1);
2431            assert_ok!(FinalizedInitAfdtKey::insert(key, &value, None, None));
2432
2433            let new_val: AccountId = account("newdummyid", 1, 1);
2434            assert_ok!(FinalizedInitAfdtKey::mutate(
2435                key,
2436                |val| {
2437                    match val {
2438                        Ok(Some(_v)) => Ok(new_val.clone()),
2439                        Ok(None) => Ok(new_val.clone()),
2440                        Err(e) => Err(e),
2441                    }
2442                },
2443                None,
2444                None
2445            ));
2446
2447            let finalized_get = FinalizedInitAfdtKey::get(key, None, None).unwrap();
2448            let new_finalized_value = match finalized_get {
2449                Some(new_val) => match new_val {
2450                    Confidence::Unsafe(id) => id,
2451                    _ => value,
2452                },
2453                None => value,
2454            };
2455
2456            assert_eq!(new_finalized_value, new_val);
2457            let persistent = PersistentInitAfdtKey::get(key, None, None).unwrap().unwrap();
2458            let (_, obs) = persistent.0.iter().next().unwrap();
2459            assert_eq!(obs.blocks_seen, 0);
2460            assert_eq!(obs.value, new_val);
2461        })
2462    }
2463}
2464
2465// ===============================================================================
2466// ````````````````````````````````` SERIAL TESTS ````````````````````````````````
2467// ===============================================================================
2468
2469// These tests are isolated in a dedicated module because they rely on a **global logger state**.
2470// Rust tests run in parallel by default, which causes race conditions and flaky failures when
2471// multiple tests attempt to read/write from the same global logger.
2472//
2473// To avoid this, each test in this module is:
2474//   - Annotated with `#[serial]` (from the `serial_test` crate) to enforce sequential execution
2475//   - Marked with `#[ignore]` to prevent accidental execution during standard test runs
2476//
2477// Running these tests:
2478// --------------------
2479// Since they are ignored by default, you must run them explicitly and ensure single-threaded
2480// execution:
2481//
2482// `cargo test serial_tests -- --ignored --test-threads=1`
2483//
2484#[cfg(test)]
2485mod serial_tests {
2486    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2487    // ``````````````````````````````````` IMPORTS ```````````````````````````````````
2488    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2489    // --- Local crate imports ---
2490    use crate::mock::*;
2491
2492    // --- Test Utils ---
2493    use serial_test::serial;
2494
2495    // --- FRAME Suite ---
2496    use frame_suite::routines::*;
2497
2498    // --- FRAME Support ---
2499    use frame_support::assert_ok;
2500
2501    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2502    // ``````````````````````````````````` LOGGING ```````````````````````````````````
2503    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2504
2505    #[serial]
2506    #[test]
2507    #[ignore = "relies on global logger; fails under parallel test execution"]
2508    fn init_affidavit_key_on_ran_service() {
2509        chain_manager_test_ext().execute_with(|| {
2510            let logger = init_logger();
2511
2512            System::set_block_number(105);
2513            let init_afdt_routine = InitAffidavitKey { at: 105 };
2514            InitAffidavitKey::on_ran_service(&init_afdt_routine);
2515
2516            let record = logger.last().unwrap();
2517            assert_eq!(record.target(), "AFFIDAVIT");
2518            assert_eq!(record.level(), log::Level::Debug);
2519            let expected_msg = format!(
2520                "๐Ÿงฑ [105] ๐Ÿ› [Debug] ๐ŸŽฏ [AFFIDAVIT] ๐Ÿงพ Module(9): InitAffidavitKeyRoutineSuccess"
2521            );
2522            let actual_msg = record.args().to_string();
2523            assert_eq!(actual_msg, expected_msg);
2524        })
2525    }
2526
2527    #[serial]
2528    #[test]
2529    #[ignore = "relies on global logger; fails under parallel test execution"]
2530    fn try_election_on_ran_service() {
2531        let mut env = new_ocw_env();
2532        env.ext.execute_with(|| {
2533            let logger = init_logger();
2534
2535            System::set_block_number(105);
2536            let by = generate_affidavit_keypair();
2537            let try_election_routine = TryElection { by: by, at: 105 };
2538            TryElection::on_ran_service(&try_election_routine);
2539
2540            let record = logger.last().unwrap();
2541            assert_eq!(record.target(), "ELECTION");
2542            assert_eq!(record.level(), log::Level::Debug);
2543            let expected_msg =
2544                format!("๐Ÿงฑ [105] ๐Ÿ› [Debug] ๐ŸŽฏ [ELECTION] ๐Ÿงพ Module(9): TryElectionRoutineSuccess");
2545            let actual_msg = record.args().to_string();
2546            assert_eq!(actual_msg, expected_msg);
2547        })
2548    }
2549
2550    #[serial]
2551    #[test]
2552    #[ignore = "relies on global logger; fails under parallel test execution"]
2553    fn declare_affidavit_on_ran_service() {
2554        let mut env = new_ocw_env();
2555        env.ext.execute_with(|| {
2556            let logger = init_logger();
2557
2558            System::set_block_number(105);
2559            let by = generate_affidavit_keypair();
2560            let declare_afdt_routine = DeclareAffidavit { by, at: 105 };
2561            DeclareAffidavit::on_ran_service(&declare_afdt_routine);
2562
2563            let record = logger.last().unwrap();
2564            assert_eq!(record.target(), "AFFIDAVIT");
2565            assert_eq!(record.level(), log::Level::Debug);
2566            let expected_msg = format!(
2567                "๐Ÿงฑ [105] ๐Ÿ› [Debug] ๐ŸŽฏ [AFFIDAVIT] ๐Ÿงพ Module(9): DeclarAffidavitRoutineSuccess"
2568            );
2569            let actual_msg = record.args().to_string();
2570            assert_eq!(actual_msg, expected_msg);
2571        })
2572    }
2573
2574    #[serial]
2575    #[test]
2576    #[ignore = "relies on global logger; fails under parallel test execution"]
2577    fn rotate_affidavit_key_on_ran_service() {
2578        let mut env = new_ocw_env();
2579        env.ext.execute_with(|| {
2580            let logger = init_logger();
2581
2582            System::set_block_number(105);
2583            let by = generate_affidavit_keypair();
2584            let rotate_afdt_routine = RotateAffidavitKey { by, at: 105 };
2585            RotateAffidavitKey::on_ran_service(&rotate_afdt_routine);
2586
2587            let record = logger.last().unwrap();
2588            assert_eq!(record.target(), "AFFIDAVIT");
2589            assert_eq!(record.level(), log::Level::Debug);
2590            let expected_msg = format!(
2591                "๐Ÿงฑ [105] ๐Ÿ› [Debug] ๐ŸŽฏ [AFFIDAVIT] ๐Ÿงพ Module(9): RotateAffidavitKeyRoutineSuccess"
2592            );
2593            let actual_msg = record.args().to_string();
2594            assert_eq!(actual_msg, expected_msg);
2595        })
2596    }
2597
2598    #[serial]
2599    #[test]
2600    #[ignore = "relies on global logger; fails under parallel test execution"]
2601    fn try_election_run_service_returns_ok_when_active_afdt_key_is_not_declared_yet() {
2602        let mut env = new_ocw_env();
2603        env.ext.execute_with(|| {
2604            init_fork_graph();
2605            let log_record = init_logger();
2606            let aff_id = generate_affidavit_id();
2607            insert_active_afdt_key(aff_id.clone()).unwrap();
2608            let pub_afdt = get_public_key(aff_id.clone()).unwrap();
2609            run_to_block(300);
2610            let election_routine = TryElection {
2611                by: pub_afdt,
2612                at: 300,
2613            };
2614            assert_ok!(election_routine.run_service());
2615
2616            let last_log = log_record.last().unwrap();
2617            assert_eq!(last_log.level(), log::Level::Debug);
2618            assert!(last_log
2619                .args()
2620                .to_string()
2621                .contains("AffidavitKeyForDeclaration"));
2622            assert_eq!(last_log.target(), "ELECTION");
2623        })
2624    }
2625}