frame_suite/
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// ``````````````````````````` OFFCHAIN ROUTINES SUITE ```````````````````````````
14// ===============================================================================
15
16//! Best-effort execution framework for offchain routines with
17//! explicit logging and storage semantics.
18//!
19//! In FRAME, most logic is executed via dispatchable extrinsics or inherents,
20//! both of which execute transactionally and revert on failure.
21//!
22//! Offchain workers operate outside that model: they run asynchronously,
23//! without rollback, and with only best-effort guarantees.
24//!
25//! This module introduces **routines** as a structured way to write such logic,
26//! where each routine is context-driven and multiple routines can be composed
27//! and executed under best-effort guarantees.
28//!
29//! # What routines provide
30//!
31//! - A disciplined execution model via [`Routines`]
32//! - Per-routine semantics, including authorization through [`RoutineOf`]
33//!   and domain-specific error policies
34//! - Composability, allowing multiple routines to run independently under
35//!   best-effort guarantees
36//!
37//! Unlike extrinsics, routines are not atomic. Failures are local and do not
38//! prevent other routines from executing.
39//!
40//! # Logging over rollback
41//!
42//! In the absence of transactional guarantees, routines rely on [`Logging`]:
43//!
44//! - errors are recorded and returned, not used to revert execution
45//! - observability replaces rollback as the primary debugging mechanism
46//!
47//! # Storage as execution semantics
48//!
49//! Routines can integrate with [`KeyValueStore`] abstractions backed by
50//! offchain storage models such as [`Persistent`], [`ForkAware`], and [`Finalized`].
51//!
52//! These make fork behavior explicit and allow safe state handling across
53//! re-orgs and repeated execution.
54//!
55//! # Summary
56//!
57//! Routines provide a structured, context-aware model for offchain execution:
58//! - best-effort instead of transactional
59//! - logging-driven instead of rollback-driven
60//! - explicit in both execution and storage semantics
61
62// ===============================================================================
63// ``````````````````````````````````` IMPORTS ```````````````````````````````````
64// ===============================================================================
65
66// --- Local crate imports ---
67use crate::{Accrete, ForksHandler, base::{Elastic, Portable, Probe, RuntimeEnum, RuntimeError, Time}};
68
69// --- Scale-codec crates ---
70use codec::{Decode, Encode, MaxEncodedLen};
71use scale_info::{
72    prelude::{
73        format,
74        string::{String, ToString},
75    },
76    TypeInfo,
77};
78
79// --- Core / Std ---
80use core::marker::PhantomData;
81
82// --- FRAME System ---
83use frame_system::{pallet_prelude::BlockNumberFor};
84
85// --- Substrate primitives ---
86use sp_core::blake2_256;
87use sp_runtime::{
88    offchain::storage::{MutateStorageError, StorageValueRef},
89    traits::{Debug, One, Saturating, Zero},
90    DispatchError,
91};
92
93// --- Substrate std (no_std helpers) ---
94use sp_std::{collections::{btree_map::BTreeMap, btree_set::BTreeSet}, vec::Vec};
95
96// ===============================================================================
97// ``````````````````````````````````` LOGGING ```````````````````````````````````
98// ===============================================================================
99
100/// Defines the function signature that can be passed to the logging system
101/// to **customize how log messages are formatted**.
102///
103/// ## Params
104/// - `TS`: The type of the timestamp (e.g., block number, system time, or any type
105/// implementing [`Debug`]).
106/// - `L`: The type representing log level (e.g., [`LogLevel`]).
107/// - `target` (`&str`): the logging target, typically the module or subsystem.
108/// - `message` (`&str`): the main log message.
109///
110/// It returns a `String` containing the fully formatted log line.
111///
112/// This allows the caller to completely customize the log output format, e.g.,
113/// changing the order, adding emojis, colors, or any additional context.
114pub type LogFormatter<TS, L> = fn(timestamp: TS, level: &L, target: &str, message: &str) -> String;
115
116/// Trait for structured logging in detached, asynchronous routines.
117///
118/// This trait is intended for use in detached, asynchronous [`Routines`] or functions
119/// where errors are handled gracefully rather than propagated. The logging system
120/// records errors, warnings, info, or debug messages without affecting control flow.
121///
122/// ## Type Parameters
123/// - `Timestamp`: The type used for timestamps in logs.
124pub trait Logging<Timestamp>
125where
126    Timestamp: Time,
127{
128    /// The error/logging type propagated through the API.
129    ///
130    /// Logging responsibility is directional:
131    ///
132    /// - If a `Logger` is returned from the provider (i.e., received by the caller),
133    ///   it has already been logged.
134    /// - If a `Logger` is constructed by the caller and returned to the provider,
135    ///   it is expected that the provider will perform the logging.
136    type Logger: Elastic + RuntimeEnum;
137
138    /// The log level type (Info/Warn/Error/Debug)
139    type Level: RuntimeEnum + From<&'static str>;
140
141    /// Default log target if none is provided.
142    ///
143    /// The **log target** is a label that identifies the source of a log message,
144    /// typically a pallet, module, or subsystem. It helps to categorize and filter
145    /// logs, making it easier to trace where messages come from in a complex runtime.
146    ///
147    /// For example, in a log line like:
148    /// `[12345][INFO][pallet_template] Templating period has not started`
149    ///
150    /// - `12345` is the timestamp/block number  
151    /// - `INFO` is the log level  
152    /// - `pallet_template` is the **log target**  
153    /// - The rest is the message
154    ///
155    /// If the caller does not provide a target, the `FALLBACK_TARGET` constant is
156    /// used as a default to ensure all logs have a meaningful source label.
157    const FALLBACK_TARGET: &'static str;
158
159    /// Core logging function that all helpers delegate to.
160    ///
161    /// This central function ensures consistent structure and formatting
162    /// across all log messages.  
163    ///
164    /// The optional `LogFormatter` lets you override the default output style.
165    ///
166    /// A formatter could add JSON structure, include node metadata, or embed
167    /// contextual tags.
168    fn log(
169        level: Self::Level,
170        err: &Self::Logger,
171        timestamp: Timestamp,
172        target: Option<&str>,
173        fmt: Option<LogFormatter<Timestamp, Self::Level>>,
174    ) -> Self::Logger;
175
176    /// Logs an info-level message.
177    ///
178    /// Includes an optional custom formatter and log target.
179    #[inline]
180    fn info(
181        err: &Self::Logger,
182        timestamp: Timestamp,
183        target: Option<&str>,
184        fmt: Option<LogFormatter<Timestamp, Self::Level>>,
185    ) -> Self::Logger
186    where
187        Self: Sized,
188    {
189        Self::log(Self::Level::from("info"), err, timestamp, target, fmt)
190    }
191
192    /// Logs a warning-level message.
193    ///
194    /// Includes an optional custom formatter and log target.
195    #[inline]
196    fn warn(
197        err: &Self::Logger,
198        timestamp: Timestamp,
199        target: Option<&str>,
200        fmt: Option<LogFormatter<Timestamp, Self::Level>>,
201    ) -> Self::Logger
202    where
203        Self: Sized,
204    {
205        Self::log(Self::Level::from("warn"), err, timestamp, target, fmt)
206    }
207
208    /// Logs an error-level message.
209    ///
210    /// Includes an optional custom formatter and log target.
211    #[inline]
212    fn error(
213        err: &Self::Logger,
214        timestamp: Timestamp,
215        target: Option<&str>,
216        fmt: Option<LogFormatter<Timestamp, Self::Level>>,
217    ) -> Self::Logger
218    where
219        Self: Sized,
220    {
221        Self::log(Self::Level::from("error"), err, timestamp, target, fmt)
222    }
223
224    /// Logs a debug-level message.
225    ///
226    /// Includes an optional custom formatter and log target.
227    #[inline]
228    fn debug(
229        err: &Self::Logger,
230        timestamp: Timestamp,
231        target: Option<&str>,
232        fmt: Option<LogFormatter<Timestamp, Self::Level>>,
233    ) -> Self::Logger
234    where
235        Self: Sized,
236    {
237        Self::log(Self::Level::from("debug"), err, timestamp, target, fmt)
238    }
239}
240
241/// Blanket implementation of `Logging` for any runtime-type.
242impl<T, Time> Logging<Time> for T
243where
244    Time: crate::Time,
245{
246    /// The type taken and returned for logging.
247    ///
248    /// We simply return the same [`DispatchError`] that was logged,
249    /// so logging does not change control flow or error propagation.
250    ///
251    /// `DispatchError` is used because in Substrate it encompasses **all**
252    /// runtime errors - including module errors, token errors, arithmetic
253    /// issues, and transactional boundaries - making it the universal
254    /// substrate-side error representation.
255    type Logger = DispatchError;
256
257    /// The log level type.  
258    ///
259    /// We use the `LogLevel` enum to standardize severity levels
260    /// (Info, Warn, Error, Debug) across all routine logs.
261    type Level = LogLevel;
262
263    /// Default logging target if none is provided.  
264    ///
265    /// Most routines, especially offchain workers or background tasks, use this target
266    /// for simplicity.
267    ///
268    /// It allows a consistent place to look for routine logs without requiring every
269    /// call to specify a target.
270    ///
271    /// **Note**: This target is only a conveninence and may be somewhat vague.
272    /// To ensure errors can still be traced accurately, the logged messages should
273    /// include additional metadata (e.g., module name, error index, or contextual info)
274    /// so that the source of the error can be identified even if the target is generic.
275    const FALLBACK_TARGET: &str = "routine";
276
277    fn log(
278        level: Self::Level,
279        err: &Self::Logger,
280        timestamp: Time,
281        target: Option<&str>,
282        fmt: Option<LogFormatter<Time, Self::Level>>,
283    ) -> Self::Logger {
284        use log::{debug, error, info, warn};
285
286        // Determine the actual logging target
287        let actual_target = target.unwrap_or(<Self as Logging<Time>>::FALLBACK_TARGET);
288
289        // Convert the DispatchError into a human-readable message
290        let message = match err {
291            DispatchError::Other(str) => str.to_string(),
292            DispatchError::Module(module_error) => {
293                if let Some(msg) = module_error.message {
294                    format!("Module({}): {}", module_error.index, msg)
295                } else {
296                    // fallback to raw bytes if no message available
297                    format!(
298                        "Module({}) raw error: {:?}",
299                        module_error.index, module_error.error
300                    )
301                }
302            }
303            DispatchError::CannotLookup => "CannotLookup".to_string(),
304            DispatchError::BadOrigin => "BadOrigin".to_string(),
305            DispatchError::ConsumerRemaining => "ConsumerRemaining".to_string(),
306            DispatchError::NoProviders => "NoProviders".to_string(),
307            DispatchError::TooManyConsumers => "TooManyConsumers".to_string(),
308            DispatchError::Token(token_error) => match token_error {
309                sp_runtime::TokenError::FundsUnavailable => {
310                    "TokenError: FundsUnavailable".to_string()
311                }
312                sp_runtime::TokenError::OnlyProvider => "TokenError: OnlyProvider".to_string(),
313                sp_runtime::TokenError::BelowMinimum => "TokenError: BelowMinimum".to_string(),
314                sp_runtime::TokenError::CannotCreate => "TokenError: CannotCreate".to_string(),
315                sp_runtime::TokenError::UnknownAsset => "TokenError: UnknownAsset".to_string(),
316                sp_runtime::TokenError::Frozen => "TokenError: Frozen".to_string(),
317                sp_runtime::TokenError::Unsupported => "TokenError: Unsupported".to_string(),
318                sp_runtime::TokenError::CannotCreateHold => {
319                    "TokenError: CannotCreateHold".to_string()
320                }
321                sp_runtime::TokenError::NotExpendable => "TokenError: NotExpendable".to_string(),
322                sp_runtime::TokenError::Blocked => "TokenError: Blocked".to_string(),
323            },
324            DispatchError::Arithmetic(arithmetic_error) => match arithmetic_error {
325                sp_runtime::ArithmeticError::Underflow => "ArithmeticError: Underflow".to_string(),
326                sp_runtime::ArithmeticError::Overflow => "ArithmeticError: Overflow".to_string(),
327                sp_runtime::ArithmeticError::DivisionByZero => {
328                    "ArithmeticError: DivisionByZero".to_string()
329                }
330            },
331            DispatchError::Transactional(transactional_error) => match transactional_error {
332                sp_runtime::TransactionalError::LimitReached => {
333                    "TransactionalError: LimitReached".to_string()
334                }
335                sp_runtime::TransactionalError::NoLayer => {
336                    "TransactionalError: NoLayer".to_string()
337                }
338            },
339            DispatchError::Exhausted => "Exhausted".to_string(),
340            DispatchError::Corruption => "Corruption".to_string(),
341            DispatchError::Unavailable => "Unavailable".to_string(),
342            DispatchError::RootNotAllowed => "RootNotAllowed".to_string(),
343            DispatchError::Trie(trie_error) => match trie_error {
344                frame_support::traits::TrieError::InvalidStateRoot => {
345                    "TrieError: InvalidStateRoot".to_string()
346                }
347                frame_support::traits::TrieError::IncompleteDatabase => {
348                    "TrieError: IncompleteDatabase".to_string()
349                }
350                frame_support::traits::TrieError::ValueAtIncompleteKey => {
351                    "TrieError: ValueAtIncompleteKey".to_string()
352                }
353                frame_support::traits::TrieError::DecoderError => {
354                    "TrieError: DecoderError".to_string()
355                }
356                frame_support::traits::TrieError::InvalidHash => {
357                    "TrieError: InvalidHash".to_string()
358                }
359                frame_support::traits::TrieError::DuplicateKey => {
360                    "TrieError: DuplicateKey".to_string()
361                }
362                frame_support::traits::TrieError::ExtraneousNode => {
363                    "TrieError: ExtraneousNode".to_string()
364                }
365                frame_support::traits::TrieError::ExtraneousValue => {
366                    "TrieError: ExtraneousValue".to_string()
367                }
368                frame_support::traits::TrieError::ExtraneousHashReference => {
369                    "TrieError: ExtraneousHashReference".to_string()
370                }
371                frame_support::traits::TrieError::InvalidChildReference => {
372                    "TrieError: InvalidChildReference".to_string()
373                }
374                frame_support::traits::TrieError::ValueMismatch => {
375                    "TrieError: ValueMismatch".to_string()
376                }
377                frame_support::traits::TrieError::IncompleteProof => {
378                    "TrieError: IncompleteProof".to_string()
379                }
380                frame_support::traits::TrieError::RootMismatch => {
381                    "TrieError: RootMismatch".to_string()
382                }
383                frame_support::traits::TrieError::DecodeError => {
384                    "TrieError: DecodeError".to_string()
385                }
386            },
387        };
388
389        // Apply optional custom formatting or default format
390        let log_line = if let Some(f) = fmt {
391            f(timestamp, &level, actual_target, &message)
392        } else {
393            format!(
394                "[{:?}][{}][{}] {}",
395                timestamp,
396                level.as_str(),
397                actual_target,
398                message
399            )
400        };
401
402        // Emit the log using the appropriate level macro
403        match level {
404            LogLevel::Error => error!(target: actual_target, "{}", log_line),
405            LogLevel::Warn => warn!(target: actual_target, "{}", log_line),
406            LogLevel::Debug => debug!(target: actual_target, "{}", log_line),
407            LogLevel::Info => info!(target: actual_target, "{}", log_line),
408        }
409
410        // Return the original error for convenience
411        *err
412    }
413}
414
415// ===============================================================================
416// `````````````````````````````` LOGGING UTILITIES ``````````````````````````````
417// ===============================================================================
418
419/// Represents log severity levels.
420#[derive(Clone, Copy, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
421pub enum LogLevel {
422    /// Informational messages
423    Info,
424    /// Warnings
425    Warn,
426    /// Errors
427    Error,
428    /// Debug-level messages
429    Debug,
430}
431
432impl From<&'static str> for LogLevel {
433    /// Converts a string literal into a `LogLevel`.
434    /// Defaults to `Debug` for unrecognized strings.
435    fn from(s: &'static str) -> Self {
436        match s {
437            "warn" => LogLevel::Warn,
438            "error" => LogLevel::Error,
439            "debug" => LogLevel::Debug,
440            "info" => LogLevel::Info,
441            _ => LogLevel::Debug,
442        }
443    }
444}
445
446impl LogLevel {
447    /// Returns the string representation of the log level.
448    pub fn as_str(&self) -> &'static str {
449        match self {
450            LogLevel::Info => "INFO",
451            LogLevel::Warn => "WARN",
452            LogLevel::Error => "ERROR",
453            LogLevel::Debug => "DEBUG",
454        }
455    }
456}
457
458// ===============================================================================
459// ``````````````````````````````` KEY-VALUE STORE ```````````````````````````````
460// ===============================================================================
461
462/// Trait for a simple key-value storage with integrated logging.
463///
464/// This trait extends [`Logging`] to ensure that any storage operation
465/// (insert or get) automatically logs errors in a standardized way.
466///
467/// This is generic over `TimeStamp` so logs can carry either a block number,
468/// system timestamp, or any other type that implements [`Debug`].
469pub trait KeyValueStore<Value, TimeStamp>: Logging<TimeStamp>
470where
471    TimeStamp: Time,
472{
473    /// Type of the key, maybe a slice instead of a bounded array.
474    type Key: Probe + ?Sized;
475
476    /// Value of the key.
477    type Value: Portable;
478
479    /// Inserts a value into the store for a given key.
480    ///
481    /// ## Parameters
482    /// - `key`: The key under which to insert the value.
483    /// - `value`: The value to store.
484    /// - `target`: Optional log target (e.g., `"runtime::storage::balances"`).
485    /// - `fmt`: Optional custom log formatter. If `None`, the default log format is used.
486    ///
487    /// ## Returns
488    /// - `Ok(())` on success.
489    /// - `Err(Logger)` if an error occurs; already logged.
490    fn insert(
491        key: &Self::Key,
492        value: &Value,
493        target: Option<&str>,
494        fmt: Option<LogFormatter<TimeStamp, Self::Level>>,
495    ) -> Result<(), Self::Logger>;
496
497    /// Retrieves a value from the store for a given key.
498    ///
499    /// ## Parameters
500    /// - `key`: The key to look up.
501    /// - `target`: Optional log target (e.g., `"runtime::storage::balances"`).
502    /// - `fmt`: Optional custom log formatter. If `None`, the default log format is used.
503    ///
504    /// ## Returns
505    /// - `Ok(Some(value))` if key exists.
506    /// - `Ok(None)` if key does not exist.
507    /// - `Err(Logger)` if retrieval fails; already logged.
508    fn get(
509        key: &Self::Key,
510        target: Option<&str>,
511        fmt: Option<LogFormatter<TimeStamp, Self::Level>>,
512    ) -> Result<Option<Self::Value>, Self::Logger>;
513
514    /// Removes the value associated with the given key.
515    ///
516    /// If the key exists, the stored value is removed and returned.
517    /// If the key does not exist, `Ok(None)` is returned.
518    ///
519    /// ## Parameters
520    /// - `key`: The key whose associated value should be removed.
521    /// - `target`: Optional log target (e.g., `"runtime::storage::offchain"`).
522    /// - `fmt`: Optional custom log formatter. If `None`, the default log format is used.
523    ///
524    /// ## Returns
525    /// - `Ok(Some(value))` if the key existed and the value was removed.
526    /// - `Ok(None)` if the key did not exist.
527    /// - `Err(Logger)` if removal fails; already logged.
528    fn remove(
529        key: &Self::Key,
530        target: Option<&str>,
531        fmt: Option<LogFormatter<TimeStamp, Self::Level>>,
532    ) -> Result<Option<Value>, Self::Logger>;
533
534    /// Mutates the value associated with the given key.
535    ///
536    /// The mutation closure is invoked with the **current value state**:
537    ///
538    /// - `Ok(Some(value))` if the key exists and the value was successfully read.
539    /// - `Ok(None)` if the key does not exist, allowing the caller to initialize it.
540    /// - `Err(Self::Logger)` if reading or decoding the existing value fails
541    ///   (this error is already logged).
542    ///
543    /// The closure **must return a value** to be written back to storage.
544    /// Removal is **not supported** via this method; use [`Self::remove`] explicitly
545    /// if deletion is required.
546    ///
547    /// Any error returned by the closure ([`Logging::Logger`]) **must not be logged
548    /// by the caller**. This function will automatically log all errors returned from
549    /// the closure, ensuring consistent logging behavior.
550    ///
551    /// ## Parameters
552    /// - `key`: The key whose associated value should be mutated.
553    /// - `f`: A closure that receives the current value state and returns
554    ///   the new value to store, or a domain-level error.
555    /// - `target`: Optional log target for storage-related logs.
556    /// - `fmt`: Optional custom log formatter.
557    ///
558    /// ## Returns
559    /// - `Ok(())` if the mutation succeeds.
560    /// - `Err(Logger)` if mutation fails; already logged.
561    fn mutate<F>(
562        key: &Self::Key,
563        f: F,
564        target: Option<&str>,
565        fmt: Option<LogFormatter<TimeStamp, Self::Level>>,
566    ) -> Result<(), Self::Logger>
567    where
568        F: FnOnce(Result<Option<Value>, Self::Logger>) -> Result<Value, Self::Logger>;
569}
570
571// ===============================================================================
572// `````````````````````````` OFFCHAIN-STORAGE UTILITIES `````````````````````````
573// ===============================================================================
574
575/// Marker trait for Substrate offchain storage kinds (backends).
576///
577/// Used exclusively for compile-time specialization and trait bounds.
578/// This trait has no methods and implies no behavior.
579pub trait SubstrateOffchainStorage {}
580
581/// Defines how **offchain storage failures are reported to callers**.
582///
583/// Intended for **Substrate FRAME-based runtimes only**.
584///
585/// This trait assigns that responsibility to the **caller (routine)** by
586/// allowing it to define the concrete error values used to represent storage
587/// failures in its own domain.
588///
589/// The `Kind` parameter identifies the offchain storage backend this policy
590/// applies to (for example, persistent or fork-aware storage). It may carry
591/// additional type parameters, but this trait makes no assumptions about
592/// their meaning.
593///
594/// This trait defines **policy only** and introduces no runtime behavior.
595pub trait OffchainStorageError<Kind>
596where
597    Kind: SubstrateOffchainStorage,
598{
599    /// Caller-defined error type used for storage failures.
600    ///
601    /// The same value is logged and returned as a [`DispatchError`].
602    type Error: RuntimeError;
603
604    /// Error used when decoding a stored value fails.
605    fn decode_failed() -> Self::Error;
606
607    /// Error used when a concurrent mutation of the stored value is detected.
608    fn concurrent_mutation() -> Self::Error;
609}
610
611// ===============================================================================
612// `````````````````````````````` PERSISTENT STORAGE `````````````````````````````
613// ===============================================================================
614
615/// Marker type for persistent offchain storage, providing fork-independent,
616/// non-reverting state with routine-defined error and logging semantics.
617///
618/// Intended for **Substrate FRAME-based runtimes only**.
619///
620/// Persistent offchain storage is **not fork-aware**:
621/// - Values persist across block re-organizations.
622/// - Values are shared across all forks.
623/// - Values are **not reverted** if the current fork is abandoned.
624///
625/// This marker is used to specialize [`KeyValueStore`] implementations
626/// backed by [`StorageValueRef::persistent`].
627///
628/// ## Error policy requirement
629///
630/// When [`KeyValueStore`] is **used for this type**, the corresponding
631/// `Routine` **must also implement** [`OffchainStorageError`] for the
632/// *same specialized* `Persistent<Context, Value, Routine>` type.
633///
634/// This ensures that:
635/// - storage-level failures are surfaced as **caller-defined errors**,
636/// - errors are attributed to the routine's domain rather than the
637///   storage layer,
638/// - and each failure is logged exactly once.
639///
640/// ## Timestamp semantics
641///
642/// This storage backend is **explicitly bound to block numbers** as its
643/// timestamp source. It does **not** accept a generic timestamp parameter.
644///
645/// All logging and routine behavior associated with this backend uses
646/// [`BlockNumberFor`], reflecting its intended use inside
647/// FRAME-based runtimes.
648///
649/// ## Type parameters
650///
651/// - `Context`: The active runtime type (i.e. a type implementing
652///   [`frame_system::Config`]). This binds the storage to a specific
653///   runtime configuration.
654/// - `Value`: The value type stored in persistent offchain storage.
655/// - `Routine`: A routine type implementing [`Routines`] parameterized
656///   by [`BlockNumberFor`], ensuring logging, error handling,
657///   and behavior are specialized to block-based execution.
658///
659/// This type is a **marker only** and carries no runtime data.
660#[derive(Clone, Copy, Debug, Default)]
661pub struct Persistent<Context, Value, Routine>(PhantomData<(Value, Context, Routine)>)
662where
663    Context: frame_system::Config,
664    Value: Portable,
665    Routine: Routines<BlockNumberFor<Context>>;
666
667/// Default backend marker implementation for all valid [`Persistent`] specializations.
668///
669/// This blanket implementation marks every well-formed [`Persistent<Context, Value, Routine>`]
670/// type as a supported Substrate offchain storage backend.
671impl<Context, Value, Routine> SubstrateOffchainStorage for Persistent<Context, Value, Routine>
672where
673    Context: frame_system::Config,
674    Value: Portable,
675    Routine: Routines<BlockNumberFor<Context>>,
676{
677}
678
679/// **Peristent Offchain Storage Kind/Backend** Default [`KeyValueStore`]
680/// Implementation.
681///
682/// Intended for Substrate FRAME-based runtimes only.
683///
684/// The timestamp type is the runtime's block number ([`BlockNumberFor`]),
685/// ensuring that all logs are tagged with the block context in which
686/// the operation occurred.
687impl<T, Value, Routine> KeyValueStore<Value, BlockNumberFor<T>> for Persistent<T, Value, Routine>
688where
689    T: frame_system::Config,
690    Value: Portable,
691    Routine: OffchainStorageError<Self> + Routines<BlockNumberFor<T>>,
692{
693    /// Keys are raw byte slices; allows flexible usage for any encoded identifier.
694    type Key = [u8];
695
696    /// Value type implementing [`Encode`] and [`Decode`]
697    type Value = Value;
698
699    /// This writes directly to **persistent offchain storage** and is therefore
700    /// not reverted on chain re-orgs.
701    fn insert(
702        key: &Self::Key,
703        value: &Value,
704        _target: Option<&str>,
705        _fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
706    ) -> Result<(), Self::Logger> {
707        let storage_ref = StorageValueRef::persistent(key);
708        storage_ref.set(value);
709        Ok(())
710    }
711
712    /// Reads from **persistent offchain storage**, which is shared across forks
713    /// and survives re-orgs.
714    fn get(
715        key: &Self::Key,
716        target: Option<&str>,
717        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
718    ) -> Result<Option<Value>, Self::Logger> {
719        let storage_ref = StorageValueRef::persistent(key);
720        let block = frame_system::Pallet::<T>::block_number();
721
722        // Attempt to read from storage.
723        let Ok(value) = storage_ref.get() else {
724            return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
725                &<Routine as OffchainStorageError<Self>>::decode_failed().into(),
726                block,
727                target,
728                fmt,
729            ));
730        };
731
732        Ok(value)
733    }
734
735    /// Removes the value from **persistent offchain storage**.
736    ///
737    /// Since persistent storage is not fork-aware, removals are permanent and
738    /// are not reverted on chain re-orgs.
739    fn remove(
740        key: &Self::Key,
741        target: Option<&str>,
742        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
743    ) -> Result<Option<Value>, Self::Logger> {
744        let storage_ref = StorageValueRef::persistent(key);
745        let block = frame_system::Pallet::<T>::block_number();
746
747        // Read existing value first
748        let Ok(existing) = storage_ref.get::<Value>() else {
749            return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
750                &<Routine as OffchainStorageError<Self>>::decode_failed().into(),
751                block,
752                target,
753                fmt,
754            ));
755        };
756        // Remove the value
757        let mut storage_ref = storage_ref;
758        storage_ref.clear();
759
760        Ok(existing)
761    }
762
763    /// Mutates the value associated with the given key in **persistent offchain storage**.
764    ///
765    /// The closure is invoked with the current value, if any, and **must return**
766    /// the new value to store. Removal is not supported by this method.
767    ///
768    /// Persistent storage is **not fork-aware**: mutations persist across re-orgs
769    /// and are visible on all forks.
770    fn mutate<F>(
771        key: &Self::Key,
772        f: F,
773        target: Option<&str>,
774        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
775    ) -> Result<(), Self::Logger>
776    where
777        F: FnOnce(Result<Option<Value>, Self::Logger>) -> Result<Value, Self::Logger>,
778    {
779        let storage_ref = StorageValueRef::persistent(key);
780        let block = frame_system::Pallet::<T>::block_number();
781
782        let res = storage_ref.mutate::<Value, Self::Logger, _>(|current| {
783            // Decode / retrieval phase
784            let current = match current {
785                Ok(v) => Ok(v), // v = Option<Value>
786                Err(_) => Err(<Self as Logging<BlockNumberFor<T>>>::warn(
787                    &<Routine as OffchainStorageError<Self>>::decode_failed().into(),
788                    block,
789                    target,
790                    fmt,
791                )),
792            };
793
794            // Delegate domain mutation logic
795            f(current)
796        });
797
798        match res {
799            // Value successfully written
800            Ok(_) => Ok(()),
801
802            // Storage-level race
803            Err(MutateStorageError::ConcurrentModification(_)) => {
804                let logged = <Self as Logging<BlockNumberFor<T>>>::warn(
805                    &<Routine as OffchainStorageError<Self>>::concurrent_mutation().into(),
806                    block,
807                    target,
808                    fmt,
809                );
810                Err(logged)
811            }
812
813            // Closure returned a domain error
814            Err(MutateStorageError::ValueFunctionFailed(logged)) => {
815                Err(<Self as Logging<BlockNumberFor<T>>>::error(
816                    &logged, block, target, fmt,
817                ))
818            }
819        }
820    }
821}
822
823// ===============================================================================
824// `````````````````````````````` FORK-AWARE STORAGE `````````````````````````````
825// ===============================================================================
826
827/// Marker type for fork-aware offchain storage, enabling re-org-sensitive,
828/// fork-scoped state with routine-defined error and logging semantics.
829///
830/// Intended for **Substrate FRAME-based runtimes only**.
831///
832/// Fork-aware offchain storage is **re-org sensitive**:
833/// - Values are scoped to the current fork.
834/// - Values are reverted if the fork is abandoned.
835/// - Values are not shared across competing forks.
836///
837/// This marker is used to specialize [`KeyValueStore`] implementations
838/// backed by fork-aware offchain storage via [`StorageValueRef::local`].
839///
840/// ## Error policy requirement
841///
842/// When [`KeyValueStore`] is **used for this type**, the corresponding
843/// `Routine` **must also implement** [`OffchainStorageError`] for the
844/// *same specialized* `Persistent<Context, Value, Routine>` type.
845///
846/// This ensures that:
847/// - storage-level failures are surfaced as **caller-defined errors**,
848/// - errors are attributed to the routine's domain rather than the
849///   storage layer,
850/// - and each failure is logged exactly once.
851///
852/// ## Timestamp semantics
853///
854/// This storage backend is **explicitly bound to block numbers** as its
855/// timestamp source. It does **not** accept a generic timestamp parameter.
856///
857/// All logging and routine behavior associated with this backend uses
858/// [`BlockNumberFor`], reflecting its intended use inside
859/// FRAME-based runtimes.
860///
861/// ## Type parameters
862///
863/// - `Context`: The active runtime type (i.e. a type implementing
864///   [`frame_system::Config`]). This binds the storage to a specific
865///   runtime configuration.
866/// - `Value`: The value type stored in fork-aware offchain storage.
867/// - `Routine`: A routine type implementing [`Routines`] parameterized
868///   by [`BlockNumberFor`], ensuring logging, error handling,
869///   and behavior are specialized to block-based execution.
870/// - `Handler`: A type implementing [`ForksHandler`] using [`ForkLocalDepot`]
871///   that manages the fork graph and scope tracking for this storage backend.
872/// 
873/// This type is a **marker only** and carries no runtime data.
874#[derive(Clone, Copy, Debug, Default)]
875pub struct ForkAware<Context, Value, Routine, Handler>(PhantomData<(Value, Context, Routine, Handler)>)
876where
877    Context: frame_system::Config,
878    Value: Portable,
879    Routine: Routines<BlockNumberFor<Context>>, 
880    Handler: ForksHandler<Context, ForkLocalDepot>;
881
882/// Default backend marker implementation for all valid [`ForkAware`] specializations.
883///
884/// This blanket implementation marks every well-formed [`ForkAware<Context, Value, Routine>`]
885/// type as a supported Substrate offchain storage backend.
886impl<Context, Value, Routine, Handler> SubstrateOffchainStorage for ForkAware<Context, Value, Routine, Handler>
887where
888    Context: frame_system::Config,
889    Value: Portable,
890    Routine: Routines<BlockNumberFor<Context>>,
891    Handler: ForksHandler<Context, ForkLocalDepot>,
892{
893}
894
895/// **Fork-Aware Offchain Storage Kind/Backend** Default [`KeyValueStore`]
896/// Implementation.
897///
898/// Intended for Substrate FRAME-based runtimes only.
899///
900/// This implementation is backed by **fork-aware offchain storage**
901/// ([`StorageValueRef::local`]).
902///
903/// The timestamp type is the runtime's block number ([`BlockNumberFor`]),
904/// ensuring that all logs are tagged with the block context in which
905/// the operation occurred.
906impl<T, Value, Routine, Handler> KeyValueStore<Value, BlockNumberFor<T>> for ForkAware<T, Value, Routine, Handler>
907where
908    T: frame_system::Config,
909    Value: Portable,
910    Routine: OffchainStorageError<Self> + Routines<BlockNumberFor<T>>,
911    Handler: ForksHandler<T, ForkLocalDepot> + Logging<BlockNumberFor<T>, Level = LogLevel, Logger = DispatchError>,
912{
913    /// Keys are raw byte slices; allows flexible usage for any encoded identifier.
914    type Key = [u8];
915
916    /// Value type implementing [`Encode`] and [`Decode`]
917    type Value = Value;
918
919    /// Writes a value to **fork-aware offchain storage**.
920    ///
921    /// For **get-check-set** use [`Self::mutate`] instead for concurrency safety.
922    ///
923    /// Values written using this method are scoped to the current fork and
924    /// will be reverted automatically if the fork is abandoned.
925    fn insert(
926        key: &Self::Key,
927        value: &Value,
928        target: Option<&str>,
929        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
930    ) -> Result<(), Self::Logger> {
931        let key = key.to_vec();
932        let scope_key = Handler::add_to_scope(key, target, fmt)?;
933        let storage_ref = StorageValueRef::persistent(&scope_key);
934        storage_ref.set(value);
935        Ok(())
936    }
937
938    /// Reads a value from **fork-aware offchain storage**.
939    ///
940    /// The returned value reflects only the state of the current fork and
941    /// may differ across competing forks.
942    fn get(
943        key: &Self::Key,
944        target: Option<&str>,
945        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
946    ) -> Result<Option<Value>, Self::Logger> {
947        let scope_key = Handler::gen_scope_item_key(&key.to_vec());
948        if !Handler::scope_item_exists(&scope_key, target, fmt)? {
949            return Ok(None)
950        };
951
952        let storage_ref = StorageValueRef::persistent(&scope_key);
953        let block = frame_system::Pallet::<T>::block_number();
954
955        let Ok(value) = storage_ref.get() else {
956            return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
957                &<Routine as OffchainStorageError<Self>>::decode_failed().into(),
958                block,
959                target,
960                fmt,
961            ));
962        };
963
964        Ok(value)
965    }
966
967    /// Removes a value from **fork-aware offchain storage**.
968    ///
969    /// Removals are scoped to the current fork and are reverted automatically
970    /// if the fork is abandoned.
971    fn remove(
972        key: &Self::Key,
973        target: Option<&str>,
974        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
975    ) -> Result<Option<Value>, Self::Logger> {
976        let scope_key = Handler::gen_scope_item_key(&key.to_vec());
977        if !Handler::scope_item_exists(&scope_key, target, fmt)? {
978            return Ok(None)
979        }
980
981        let storage_ref = StorageValueRef::persistent(&scope_key);
982        let block = frame_system::Pallet::<T>::block_number();
983
984        let Ok(existing) = storage_ref.get::<Value>() else {
985            return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
986                &<Routine as OffchainStorageError<Self>>::decode_failed().into(),
987                block,
988                target,
989                fmt,
990            ));
991        };
992
993        let mut storage_ref = storage_ref;
994        storage_ref.clear();
995        Handler::remove_from_scope(&scope_key, target, fmt)?;
996
997        Ok(existing)
998    }
999
1000    /// Performs an atomic read-modify-write operation on **fork-aware offchain
1001    /// storage**.
1002    ///
1003    /// The closure is invoked with the current value, if any, and **must return**
1004    /// the new value to store. Removal is not supported by this method.
1005    ///
1006    /// Mutations performed by this method:
1007    /// - are visible only on the current fork,
1008    /// - are reverted automatically on re-orgs,
1009    /// - and are safe to use with speculative chain state.
1010    fn mutate<F>(
1011        key: &Self::Key,
1012        f: F,
1013        target: Option<&str>,
1014        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1015    ) -> Result<(), Self::Logger>
1016    where
1017        F: FnOnce(Result<Option<Value>, Self::Logger>) -> Result<Value, Self::Logger>,
1018    {
1019
1020        let scope_key = Handler::gen_scope_item_key(&key.to_vec());
1021        if !Handler::scope_item_exists(&scope_key, target, fmt)? {
1022            let value = f(Ok(None))?;
1023            Self::insert(key, &value, target, fmt)?;
1024            return Ok(())
1025        }
1026
1027        let storage_ref = StorageValueRef::persistent(&scope_key);
1028        let block = frame_system::Pallet::<T>::block_number();
1029
1030        let res = storage_ref.mutate::<Value, Self::Logger, _>(|current| {
1031            // Normalize storage read into Result<Option<Value>, Logged>
1032            let current = match current {
1033                Ok(opt) => Ok(opt),
1034                Err(_) => Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1035                    &<Routine as OffchainStorageError<Self>>::decode_failed().into(),
1036                    block,
1037                    target,
1038                    fmt,
1039                )),
1040            };
1041
1042            // Delegate mutation logic to caller
1043            f(current)
1044        });
1045
1046        match res {
1047            Ok(_) => Ok(()),
1048
1049            Err(MutateStorageError::ConcurrentModification(_)) => {
1050                return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1051                    &<Routine as OffchainStorageError<Self>>::concurrent_mutation().into(),
1052                    block,
1053                    target,
1054                    fmt,
1055                ));
1056            }
1057
1058            Err(MutateStorageError::ValueFunctionFailed(logged)) => {
1059                Err(<Self as Logging<BlockNumberFor<T>>>::error(
1060                    &logged, block, target, fmt,
1061                ))
1062            }
1063        }
1064    }
1065}
1066
1067// ===============================================================================
1068// ````````````````````````` FINALIZED STORAGE UTILITIES `````````````````````````
1069// ===============================================================================
1070
1071/// Defines a **finality evaluation policy** for values managed by
1072/// [`Finalized`] storage.
1073///
1074/// Intended for **Substrate FRAME-based runtimes only**.
1075///
1076/// This trait specifies the parameters used to derive a **confidence signal**
1077/// for speculative, fork-aware data based on:
1078/// - elapsed wall-clock time, and
1079/// - block-scoped repeated observations.
1080///
1081/// It only answers:
1082/// - *how long* a value must survive before it may be considered stable, and
1083/// - *how many distinct block observations* are required to strengthen confidence.
1084///
1085/// The policy provides *inputs* to confidence evaluation and does not
1086/// imply on-chain finality or absolute truth.
1087pub trait FinalizedPolicy<Context>
1088where
1089    Context: pallet_timestamp::Config,
1090{
1091    /// Wall-clock **elapsed time window** that must pass *after the first
1092    /// observation* before a value may begin to contribute to a stronger
1093    /// confidence signal.
1094    ///
1095    /// Conceptually, this represents the delay between:
1096    /// - an **initial observation window**, and
1097    /// - an **optimal finalized window** where confidence can be evaluated.
1098    ///
1099    /// The duration is expressed using the runtime's timestamp type
1100    /// (see [`pallet_timestamp::Config::Moment`]).
1101    fn finality_after() -> <Context as pallet_timestamp::Config>::Moment;
1102
1103    /// Number of **distinct blocks** in which the value must be observed
1104    /// *after* the finality window has elapsed.
1105    ///
1106    /// Observations are block-scoped:
1107    /// - At most one observation per block is counted.
1108    /// - Repeated OCW executions within the same block do not increase this value.
1109    ///
1110    /// This parameter acts as a confidence-strengthening threshold
1111    /// to guard against transient forks.
1112    fn finality_ticks() -> BlockNumberFor<Context>;
1113}
1114
1115/// Defines **caller-facing error signals** specific to
1116/// [`Finalized`] storage.
1117///
1118/// Intended for **Substrate FRAME-based runtimes only**.
1119///
1120/// This trait allows callers to control how **semantic invariant violations**
1121/// detected by the `Finalized` storage model are surfaced as
1122/// [`DispatchError`] values.
1123///
1124/// These errors:
1125/// - originate from finality-specific consistency checks,
1126/// - are logged by the storage layer,
1127/// - and are returned to the caller as *signals* of inconsistency,
1128///   not as definitive storage failures.
1129///
1130/// This trait does not affect storage behavior. It only defines
1131/// which error values are emitted when an invariant is violated.
1132pub trait FinalizedOffchainStorageError<Context, Value>
1133where
1134    Context: frame_system::Config,
1135{
1136    /// Concrete error type chosen by the caller.
1137    ///
1138    /// This error is converted into a [`DispatchError`] before being
1139    /// logged or returned.
1140    type Error: RuntimeError;
1141
1142    /// Emitted when a **fork-aware value hash exists without a corresponding
1143    /// entry in persistent storage**.
1144    ///
1145    /// This indicates a hanging speculative value. The fork-aware entry
1146    /// is cleaned up automatically before this error is returned.
1147    fn hanging_hash() -> Self::Error;
1148
1149    /// Emitted when **persistent storage contains no value at all**
1150    /// for the given key.
1151    ///
1152    /// This means there is **no speculative value being tracked**,
1153    /// and therefore the fork-aware entry has no semantic meaning.
1154    ///
1155    /// When this condition is detected, the fork-aware entry is
1156    /// cleaned up automatically before this error is returned.
1157    fn hanging_value() -> Self::Error;
1158}
1159
1160// ===============================================================================
1161// `````````````````````````````` FINALIZED STORAGE ``````````````````````````````
1162// ===============================================================================
1163
1164/// Marker type for finality-aware offchain storage, combining fork-aware and
1165/// persistent state to derive confidence-graded values via routine-defined
1166/// policies and observations.
1167///
1168/// Intended for **Substrate FRAME-based runtimes only**.
1169///
1170/// The `Finalized` storage model:
1171/// - records values speculatively using fork-aware storage,
1172/// - tracks historical observations in persistent storage,
1173/// - and exposes values only after evaluating time and observation-based
1174///   finality guarantees.
1175///
1176/// Finality is determined by:
1177/// - a wall-clock time window (see [`FinalizedPolicy`]),
1178/// - and repeated successful observations.
1179///
1180/// This marker is used to specialize [`KeyValueStore`] implementations that
1181/// combine [`ForkAware`] and [`Persistent`] storage to provide confidence-graded
1182/// values (see [`Confidence`]).
1183///
1184/// ## Behavioral contract
1185///
1186/// Any routine using `Finalized` storage **must provide error policies for the
1187/// exact internal storage forms used by this model** via
1188/// [`OffchainStorageError`]:
1189///
1190/// - [`ForkAware<Context, ValueHash, Routine>`], which stores speculative
1191///   fork-local identity using [`ValueHash`], and
1192/// - [`Persistent<Context, Ledger<Context, Moment<Context>, Value>, Routine>`],
1193///   which stores the persistent observation ledger using [`Ledger`] and
1194///   wall-clock [`Moment`].
1195///
1196/// In addition, the routine must define:
1197/// - a [`FinalizedPolicy`] describing when a value becomes stable, and
1198/// - [`FinalizedOffchainStorageError`] values for finality-specific
1199///   invariant violations.
1200///
1201/// Together, these requirements ensure that:
1202/// - fork-aware and persistent state remain consistent,
1203/// - semantic invariants are enforced at a single, centralized layer,
1204/// - and all failures are surfaced as **caller-defined error signals**
1205///   and logged exactly once.
1206///
1207/// ## Value-first semantics
1208///
1209/// This storage model is **value-first**: confidence is tied to the observed
1210/// *value*, not just the key. If the same value is inserted again for the same
1211/// key, its accumulated confidence is **reset**, as the insertion is treated as
1212/// a fresh observation sequence.
1213///
1214/// Callers are therefore responsible for deciding whether repeated insertions
1215/// of the same value are semantically meaningful. To avoid unintended confidence
1216/// resets, routines should refrain from inserting identical values multiple
1217/// times unless a reset is explicitly desired.
1218///
1219/// ## Timestamp semantics
1220///
1221/// All logging and routine behavior associated with this storage model is
1222/// **explicitly bound to block numbers** via [`BlockNumberFor<Context>`].
1223/// This type does **not** accept a generic timestamp parameter.
1224///
1225/// Wall-clock time, when required for finality evaluation, is obtained
1226/// explicitly from [`pallet_timestamp`].
1227///
1228/// ## Type parameters
1229///
1230/// - `Context`: The active runtime type (i.e. a type implementing
1231///   [`frame_system::Config`]). This binds the storage model to a specific
1232///   runtime configuration.
1233/// - `Value`: The value type whose finality is being tracked.
1234/// - `Routine`: A routine type implementing [`Routines`] parameterized
1235///   by [`BlockNumberFor<Context>`], allowing logging, error handling,
1236///   policy evaluation, and invariant enforcement to be specialized
1237///   at the type level.
1238/// - `Handler`: A type implementing [`ForksHandler`] using [`ForkLocalDepot`]
1239///   that manages the fork graph and scope tracking for this storage backend.
1240///
1241/// This type is a **marker only** and carries no runtime data.
1242#[derive(Clone, Copy, Debug)]
1243pub struct Finalized<Context, Value, Routine, Handler>(PhantomData<(Value, Context, Routine, Handler)>)
1244where
1245    Context: frame_system::Config,
1246    Value: Portable,
1247    Routine: Routines<BlockNumberFor<Context>>,
1248    Handler: ForksHandler<Context, ForkLocalDepot>;
1249
1250/// Stable, fork-independent identifier for values managed by [`Finalized`] storage.
1251///
1252/// `ValueHash` is computed using the `blake2_256` hash of the
1253/// SCALE-encoded representation of a value.
1254///
1255/// Within the [`Finalized`] storage model, this hash is used to:
1256/// - identify the *actual content* associated with a fork-aware key,
1257/// - correlate speculative fork-aware entries with their corresponding
1258///   persistent ledger records,
1259/// - and track value observations across forks.
1260///
1261/// Fork-aware storage records only the `ValueHash`, while the full value
1262/// and its observation metadata are stored persistently. This ensures that
1263/// semantic identity is preserved across re-orgs while allowing speculative
1264/// state to be reverted safely.
1265#[derive(Encode, Decode, Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord)]
1266pub struct ValueHash(pub [u8; 32]);
1267
1268impl ValueHash {
1269    pub fn new(hash: [u8; 32]) -> Self {
1270        ValueHash(hash)
1271    }
1272}
1273
1274/// Persistent observation record for a value managed by [`Finalized`] storage.
1275///
1276/// An `Observation` captures *when* a value was seen and *how many distinct
1277/// blocks* it has survived after entering the finality window.
1278///
1279/// This structure does not imply finality by itself; it only provides
1280/// the evidence required by [`FinalizedPolicy`] to derive a
1281/// [`Confidence`] level.
1282#[derive(Encode, Decode, Debug, Clone)]
1283pub struct Observation<Context, Value>
1284where
1285    Context: pallet_timestamp::Config,
1286{
1287    /// Wall-clock time when the value was first observed.
1288    pub first_seen: Moment<Context>,
1289
1290    /// Wall-clock time when the value was last observed.
1291    pub last_seen: Moment<Context>,
1292
1293    /// Number of distinct blocks in which the value was observed
1294    /// after the finality window elapsed.
1295    pub blocks_seen: BlockNumberFor<Context>,
1296
1297    /// The observed value.
1298    pub value: Value,
1299}
1300
1301/// Persistent observation ledger used by [`Finalized`] storage.
1302///
1303/// A `Ledger` maps a stable [`ValueHash`] to its corresponding
1304/// [`Observation`] record.
1305///
1306/// Within the [`Finalized`] storage model:
1307/// - The ledger is stored in **persistent offchain storage**.
1308/// - Entries are **fork-independent** and survive chain re-organizations.
1309/// - Each entry accumulates observation history across OCW executions.
1310///
1311/// The ledger acts as the authoritative source of truth for:
1312/// - value identity (via [`ValueHash`]),
1313/// - temporal stability,
1314/// - and block-scoped confirmation counts.
1315///
1316/// It is consulted to derive confidence levels (see [`Confidence`])
1317/// and to detect and clean up fork-aware inconsistencies.
1318#[derive(Encode, Decode, Debug, Clone)]
1319pub struct Ledger<Context, Value>(pub ConfidenceMap<Context, Value>)
1320where
1321    Context: pallet_timestamp::Config,
1322    Value: Encode + Decode + Clone;
1323
1324// Type Alias for Persistent Ledger
1325type ConfidenceMap<Context, Value> = BTreeMap<ValueHash, Observation<Context, Value>>;
1326
1327/// Confidence **signal** derived for a value evaluated by [`Finalized`] storage.
1328///
1329/// This enum represents the outcome of applying a [`FinalizedPolicy`] to an
1330/// observed value, based on elapsed time and block-scoped observations.
1331///
1332/// It expresses a **signal of stability**, not on-chain finality and not a
1333/// definitive statement of truth.
1334#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
1335pub enum Confidence<Value>
1336where
1337    Value: Portable,
1338{
1339    /// A **strong confidence signal**.
1340    ///
1341    /// The value has:
1342    /// - survived the configured finality time window, and
1343    /// - been observed across enough distinct blocks.
1344    ///
1345    /// This signal suggests that the value is *likely stable* and that
1346    /// irreversible or non-recoverable actions may be reasonable.
1347    Safe(Value),
1348
1349    /// A **weak confidence signal**.
1350    ///
1351    /// The value has survived the finality time window, but has **not yet**
1352    /// accumulated enough block-scoped observations.
1353    ///
1354    /// This signal suggests that only optimistic or recoverable actions
1355    /// should be considered.
1356    Risky(Value),
1357
1358    /// A **negative confidence signal**.
1359    ///
1360    /// The value exists, but the finality time window has **not** elapsed yet.
1361    ///
1362    /// This signal suggests that no action-reversible or irreversible-
1363    /// should be taken at this stage.
1364    Unsafe(Value),
1365}
1366
1367/// Wall-clock timestamp type used by [`Finalized`] storage.
1368///
1369/// An alias for the timestamp type provided by [`pallet_timestamp`]
1370/// for the given runtime.
1371///
1372/// It is used exclusively for **time-based finality evaluation**
1373/// (for example, measuring how long a value has survived),
1374/// and is **not** used for ordering, counting, or block-based logic.
1375///
1376/// Block-scoped semantics (such as observation counts) are expressed
1377/// separately via [`BlockNumberFor`].
1378pub type Moment<T> = <T as pallet_timestamp::Config>::Moment;
1379
1380/// [`KeyValueStore`] implementation for [`Finalized`] storage semantics.
1381///
1382/// This implementation materializes the behavioral contract defined by
1383/// [`Finalized`] by combining:
1384/// - fork-aware storage for speculative state,
1385/// - persistent storage for observation history,
1386/// - and routine-defined policies for finality evaluation and error signaling.
1387///
1388/// The required bounds ensure that the routine:
1389/// - defines **when** a value becomes stable ([`FinalizedPolicy`]),
1390/// - provides caller-defined error signals for finality invariants
1391///   ([`FinalizedOffchainStorageError`]),
1392/// - and supplies [`OffchainStorageError`] error policies for the
1393/// **exact storage forms** used internally by this model for:
1394///   - [`ForkAware<.., ValueHash, ..>`] using [`ValueHash`], and
1395///   - [`Persistent<.., Ledger<...>, ..>`] using [`Ledger`].
1396///
1397/// This guarantees that all storage failures and semantic violations are
1398/// surfaced consistently as caller-defined errors and are logged exactly
1399/// once at the correct abstraction layer.
1400impl<T, Value, Routine, Handler> KeyValueStore<Value, BlockNumberFor<T>> for Finalized<T, Value, Routine, Handler>
1401where
1402    T: pallet_timestamp::Config,
1403    Value: Portable,
1404    Routine: FinalizedOffchainStorageError<T, Value>
1405        + FinalizedPolicy<T>
1406        + OffchainStorageError<Persistent<T, Ledger<T, Value>, Routine>>
1407        + OffchainStorageError<ForkAware<T, ValueHash, Routine, Handler>>
1408        + Routines<BlockNumberFor<T>>,
1409    Handler: ForksHandler<T, ForkLocalDepot> + Logging<BlockNumberFor<T>, Level = LogLevel, Logger = DispatchError>,
1410{
1411    /// Keys are raw byte slices; allows flexible usage for any encoded identifier.
1412    type Key = [u8];
1413
1414    /// Return value type used when querying a key.
1415    ///
1416    /// The value is wrapped in [`Confidence`], representing a
1417    /// **confidence signal** derived from the [`Finalized`] storage
1418    /// model rather than a definitive truth or on-chain finality.
1419    type Value = Confidence<Value>;
1420
1421    /// Inserts a value **speculatively** under finality-aware semantics.
1422    ///
1423    /// This operation:
1424    /// - computes a stable [`ValueHash`] for fork-independent identity,
1425    /// - records the hash in **fork-aware storage** (speculative marker),
1426    /// - and inserts or updates an [`Observation`] in the **persistent ledger**.
1427    ///
1428    /// No confidence is implied by insertion alone; this operation only
1429    /// records *existence* and initializes observation tracking.
1430    fn insert(
1431        key: &Self::Key,
1432        value: &Value,
1433        target: Option<&str>,
1434        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1435    ) -> Result<(), Self::Logger> {
1436        // Compute stable value hash (identity across forks)
1437        let hash = ValueHash(blake2_256(&value.encode()));
1438
1439        // Read wall-clock time (confidence anchor)
1440        let now: Moment<T> = pallet_timestamp::Pallet::<T>::get();
1441
1442        // Write fork-aware speculative marker
1443        // (this is fork-local and will be reorged)
1444        ForkAware::<T, ValueHash, Routine, Handler>::insert(key, &hash, target, fmt)?;
1445
1446        // Persistent ledger mutation
1447        Persistent::<T, Ledger<T, Value>, Routine>::mutate(
1448            key,
1449            |current| {
1450                let mut ledger = match current {
1451                    Ok(Some(existing)) => existing,
1452                    Ok(None) => Ledger(ConfidenceMap::new()),
1453                    Err(logged) => return Err(logged),
1454                };
1455
1456                ledger.0.insert(
1457                    hash,
1458                    Observation {
1459                        first_seen: now,
1460                        last_seen: now,
1461                        blocks_seen: Zero::zero(),
1462                        value: value.clone(),
1463                    },
1464                );
1465
1466                Ok(ledger)
1467            },
1468            target,
1469            fmt,
1470        )?;
1471
1472        Ok(())
1473    }
1474
1475    /// Reads the value associated with the current fork and derives the
1476    /// value wrapped in a [`Confidence`] signal.
1477    ///
1478    /// Returned signals:
1479    /// - [`Confidence::Unsafe`] - finality window not elapsed.
1480    /// - [`Confidence::Risky`]  - time elapsed, insufficient block observations.
1481    /// - [`Confidence::Safe`]   - time and observation thresholds satisfied.
1482    ///
1483    /// Any detected invariant violation (for example, a fork-aware hash
1484    /// without a ledger entry) is logged and cleaned up automatically.
1485    fn get(
1486        key: &Self::Key,
1487        target: Option<&str>,
1488        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1489    ) -> Result<Option<Confidence<Value>>, Self::Logger> {
1490        let now: Moment<T> = pallet_timestamp::Pallet::<T>::get();
1491        let block = frame_system::Pallet::<T>::block_number();
1492
1493        // Read fork-aware speculative hash
1494        let hash = match ForkAware::<T, ValueHash, Routine, Handler>::get(key, target, fmt)? {
1495            Some(h) => h,
1496            None => return Ok(None),
1497        };
1498
1499        // Will be produced inside mutation
1500        let mut result: Option<Confidence<Value>> = None;
1501
1502        // Atomic persistent ledger mutation
1503        Persistent::<T, Ledger<T, Value>, Routine>::mutate(
1504            key,
1505            |current| {
1506                let mut ledger = match current {
1507                    Ok(Some(l)) => l,
1508                    Ok(None) => {
1509                        // Fork-aware exists but ledger missing -> clean fork-aware
1510                        ForkAware::<T, ValueHash, Routine, Handler>::remove(key, target, fmt)?;
1511                        return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1512                            &<Routine as FinalizedOffchainStorageError<T, Value>>::hanging_value()
1513                                .into(),
1514                            block,
1515                            target,
1516                            fmt,
1517                        ));
1518                    }
1519                    Err(logged) => return Err(logged),
1520                };
1521
1522                let obs = match ledger.0.get_mut(&hash) {
1523                    Some(o) => o,
1524                    None => {
1525                        // Fork-aware hash has no backing ledger entry -> cleanup
1526                        ForkAware::<T, ValueHash, Routine, Handler>::remove(key, target, fmt)?;
1527                        return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1528                            &<Routine as FinalizedOffchainStorageError<T, Value>>::hanging_hash()
1529                                .into(),
1530                            block,
1531                            target,
1532                            fmt,
1533                        ));
1534                    }
1535                };
1536
1537                // Snapshot for confidence computation
1538                let first_seen = obs.first_seen;
1539                let last_seen = obs.last_seen;
1540                let obs_count = obs.blocks_seen;
1541                let value = obs.value.clone();
1542
1543                // Confidence evaluation
1544                let after = <Routine as FinalizedPolicy<T>>::finality_after();
1545                let ticks = <Routine as FinalizedPolicy<T>>::finality_ticks();
1546
1547                // Update observation metadata
1548                obs.last_seen = now;
1549
1550                // Evaluate confidence based on temporal finality and repeated observations.
1551                //
1552                // Time-window finality check
1553                // - `first_seen`: moment of the first successful observation (insertion time)
1554                // - `after`:      required finality window duration
1555                // - `last_seen`:  moment of the most recent successful observation (from storage)
1556                //
1557                // If (first_seen + after) > last_seen, the value has NOT yet survived
1558                // the required finality window - meaning we have not observed it
1559                // long enough across time. The value remains `Unsafe`.
1560                //
1561                // Otherwise, the value has lived past the temporal finality window,
1562                // and we can evaluate observation-based stability.
1563                let confidence = match first_seen.saturating_add(after) > last_seen {
1564                    // Still within the finality time window -> not stable yet.
1565                    true => Confidence::Unsafe(value),
1566
1567                    // Time window satisfied; now evaluate repeated observations.
1568                    false => match obs_count < ticks {
1569                        true => {
1570                            // We only increment observation ticks if this observation
1571                            // occurred in a strictly new moment. Multiple observations
1572                            // within the same moment do not increase confidence.
1573                            if last_seen < now {
1574                                obs.blocks_seen += One::one();
1575                            }
1576
1577                            // Not enough distinct-moment observations yet -> still risky.
1578                            Confidence::Risky(value)
1579                        }
1580
1581                        // Required number of distinct-moment observations reached,
1582                        // and the time window has already elapsed -> value is finalized.
1583                        false => Confidence::Safe(value),
1584                    },
1585                };
1586
1587                result = Some(confidence);
1588
1589                Ok(ledger)
1590            },
1591            target,
1592            fmt,
1593        )?;
1594
1595        Ok(result)
1596    }
1597
1598    /// Removes the value associated with the **current fork**.
1599    ///
1600    /// Removal semantics:
1601    /// - The fork-aware marker is always removed first.
1602    /// - The corresponding persistent ledger entry is removed next.
1603    /// - The ledger itself is deleted if it becomes empty.
1604    ///
1605    /// This ensures no semantic or historical state is left behind once
1606    /// the value is no longer relevant.
1607    fn remove(
1608        key: &Self::Key,
1609        target: Option<&str>,
1610        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1611    ) -> Result<Option<Value>, Self::Logger> {
1612        let block = frame_system::Pallet::<T>::block_number();
1613
1614        // Read fork-aware hash (what we are removing)
1615        let hash = match ForkAware::<T, ValueHash, Routine, Handler>::get(key, target, fmt)? {
1616            Some(h) => h,
1617            None => return Ok(None), // nothing to remove
1618        };
1619
1620        // Always remove fork-aware entry first
1621        ForkAware::<T, ValueHash, Routine, Handler>::remove(key, target, fmt)?;
1622
1623        // Remove from persistent ledger atomically
1624        let mut removed: Option<Value> = None;
1625
1626        let mut is_empty = false;
1627
1628        Persistent::<T, Ledger<T, Value>, Routine>::mutate(
1629            key,
1630            |current| {
1631                let mut ledger = match current {
1632                    Ok(Some(l)) => l,
1633                    Ok(None) => {
1634                        return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1635                            &<Routine as FinalizedOffchainStorageError<T, Value>>::hanging_value()
1636                                .into(),
1637                            block,
1638                            target,
1639                            fmt,
1640                        ));
1641                    }
1642                    Err(logged) => return Err(logged),
1643                };
1644
1645                if let Some(obs) = ledger.0.remove(&hash) {
1646                    removed = Some(obs.value);
1647                }
1648
1649                if ledger.0.is_empty() {
1650                    is_empty = true;
1651                }
1652
1653                Ok(ledger)
1654            },
1655            target,
1656            fmt,
1657        )?;
1658
1659        // Drop empty ledger (no semantic meaning left)
1660        if is_empty {
1661            Persistent::<T, Ledger<T, Value>, Routine>::remove(key, target, fmt)?;
1662        }
1663
1664        Ok(removed)
1665    }
1666
1667    /// Mutates the value associated with a key under **finality-aware semantics**.
1668    ///
1669    /// The closure `f` receives the current value, if any, and must return
1670    /// a new value to replace it.
1671    ///
1672    /// Replacing a value **resets all finality observations**: the new value
1673    /// is treated as freshly observed and must re-accumulate confidence.
1674    ///
1675    /// The update is scoped to the current fork and preserves all storage
1676    /// invariants. Any detected invariant violation is logged once and
1677    /// cleaned up automatically before the error is returned.
1678    fn mutate<F>(
1679        key: &Self::Key,
1680        f: F,
1681        target: Option<&str>,
1682        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1683    ) -> Result<(), Self::Logger>
1684    where
1685        F: FnOnce(Result<Option<Value>, Self::Logger>) -> Result<Value, Self::Logger>,
1686    {
1687        let now: Moment<T> = pallet_timestamp::Pallet::<T>::get();
1688        let block = frame_system::Pallet::<T>::block_number();
1689
1690        // Fork-aware mutation is the outer authority
1691        let result = ForkAware::<T, ValueHash, Routine, Handler>::mutate(
1692            key,
1693            |current_hash| {
1694                // Resolve current value from persistent ledger
1695                let current_value = match current_hash {
1696                    Err(logged) => {
1697                        return Err(logged);
1698                    }
1699
1700                    Ok(None) => None,
1701
1702                    Ok(Some(hash)) => {
1703                        let ledger =
1704                            Persistent::<T, Ledger<T, Value>, Routine>::get(key, target, fmt)?;
1705
1706                        let ledger = match ledger {
1707                            Some(l) => l,
1708                            None => {
1709                                return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1710                                        &<Routine as FinalizedOffchainStorageError<
1711                                            T,
1712                                            Value,
1713                                        >>::hanging_value()
1714                                            .into(),
1715                                        block,
1716                                        target,
1717                                        fmt,
1718                                    ));
1719                            }
1720                        };
1721
1722                        match ledger.0.get(&hash) {
1723                            Some(obs) => Some(obs.value.clone()),
1724                            None => None,
1725                        }
1726                    }
1727                };
1728
1729                // Delegate domain mutation
1730                let new_value = f(Ok(current_value))?;
1731
1732                // Compute new identity
1733                let new_hash = ValueHash(blake2_256(&new_value.encode()));
1734
1735                // Update persistent ledger
1736                Persistent::<T, Ledger<T, Value>, Routine>::mutate(
1737                    key,
1738                    |ledger_result| {
1739                        let mut ledger = match ledger_result {
1740                            Ok(Some(l)) => l,
1741                            Ok(None) => Ledger(ConfidenceMap::new()),
1742                            Err(logged) => return Err(logged),
1743                        };
1744
1745                        // Remove old observation
1746                        if let Ok(Some(old_hash)) = current_hash {
1747                            ledger.0.remove(&old_hash);
1748                        }
1749
1750                        // Insert new observation
1751                        ledger.0.insert(
1752                            new_hash,
1753                            Observation {
1754                                first_seen: now,
1755                                last_seen: now,
1756                                blocks_seen: Zero::zero(),
1757                                value: new_value,
1758                            },
1759                        );
1760
1761                        Ok(ledger)
1762                    },
1763                    target,
1764                    fmt,
1765                )?;
1766                // Commit new fork-aware hash
1767                Ok(new_hash)
1768            },
1769            target,
1770            fmt,
1771        );
1772
1773        match result {
1774            Ok(_) => Ok(()),
1775
1776            Err(logged) => {
1777                if logged
1778                    == <Routine as FinalizedOffchainStorageError<T, Value>>::hanging_value().into()
1779                {
1780                    ForkAware::<T, ValueHash, Routine, Handler>::remove(key, target, fmt)?;
1781                }
1782                Err(logged)
1783            }
1784        }
1785    }
1786}
1787
1788// ===============================================================================
1789// `````````````````````````````````` ROUTINES ```````````````````````````````````
1790// ===============================================================================
1791
1792/// Fork-local storage scope for [`ForksHandler`] implementing [`ForkScopes`](crate::ForkScopes).
1793///
1794/// `ForkLocalDepot` is the branch-local scope container used by the
1795/// fork-aware offchain execution system to track visibility of
1796/// fork-scoped storage entries across branch lineage.
1797///
1798/// It does not store the actual values themselves.
1799///
1800/// Instead, it stores only deterministic 32-byte keys (`[u8; 32]`)
1801/// representing items written into fork-aware storage systems such as:
1802///
1803/// - [`ForkAware`]
1804/// - [`Finalized`]
1805///
1806/// These keys act as stable scope references that allow the fork graph
1807/// to answer:
1808///
1809/// ```ignore
1810/// "does this item exist on this branch or any reachable ancestor branch?"
1811/// ```
1812///
1813/// without requiring repeated traversal of historical parent branches.
1814///
1815/// ## Why this exists
1816///
1817/// In fork-aware OCW execution, each branch must maintain isolated local
1818/// state while still inheriting valid reachable state from its lineage.
1819///
1820/// Example:
1821///
1822/// ```text
1823/// A -> B -> C
1824///         |-- D
1825///         |-- D'
1826/// ```
1827///
1828/// Here:
1829///
1830/// - `D` and `D'` must not overwrite each other
1831/// - both branches must still see inherited state from `A -> B -> C`
1832///
1833/// `ForkLocalDepot` provides that visibility layer by separating:
1834///
1835/// - current-generation writes
1836/// - inherited historical writes
1837///
1838/// instead of repeatedly walking parent branches during every lookup.
1839///
1840/// ## Fork inheritance model
1841///
1842/// When a new sibling branch is created:
1843///
1844/// ```text
1845/// Parent branch:
1846/// A -> B -> C
1847///
1848/// New sibling:
1849///         |-- D'
1850/// ```
1851///
1852/// the child branch receives:
1853///
1854/// ```text
1855/// inherited_keys(child)
1856/// = inherited_keys(parent) + local_keys(parent)
1857/// ```
1858///
1859/// while starting with:
1860///
1861/// ```text
1862/// local_keys(child) = {}
1863/// ```
1864///
1865/// This ensures:
1866///
1867/// - parent state remains reachable
1868/// - new writes stay isolated to the new fork
1869/// - existence checks remain O(log n)
1870/// - no ancestry walking is required for normal reads
1871///
1872/// ## Example
1873///
1874/// ```text
1875/// Original branch:
1876///
1877/// local_keys      = {k1, k2}
1878/// inherited_keys  = {}
1879///
1880/// After fork:
1881///
1882/// local_keys      = {}
1883/// inherited_keys  = {k1, k2}
1884///
1885/// New write:
1886///
1887/// local_keys      = {k3}
1888/// inherited_keys  = {k1, k2}
1889/// ```
1890///
1891/// The child branch can see:
1892///
1893/// ```text
1894/// {k1, k2, k3}
1895/// ```
1896///
1897/// while sibling branches remain isolated from `k3`.
1898#[derive(Encode, Decode, Clone, Debug, Default)]
1899pub struct ForkLocalDepot {
1900    /// Keys inherited from previous generations through [`Accrete`].
1901    ///
1902    /// These represent all reachable historical entries inherited from
1903    /// ancestor branches.
1904    ///
1905    /// They are not created in the current branch generation, but remain
1906    /// visible because they were promoted forward during fork creation.
1907    ///
1908    /// This allows branch-local reads to access valid ancestor state
1909    /// without walking parent branches repeatedly.
1910    pub inherited_keys: BTreeSet<[u8; 32]>,
1911
1912    /// Keys created only in the current local generation.
1913    ///
1914    /// These represent the newest writes belonging exclusively to the
1915    /// current branch path.
1916    ///
1917    /// They are isolated to this branch until another fork occurs,
1918    /// at which point they are promoted into `inherited_keys` of the
1919    /// child branch through [`Accrete::accrete()`].
1920    ///
1921    /// This ensures writes remain fork-local while still preserving
1922    /// deterministic lineage inheritance for future branches.
1923    pub local_keys: BTreeSet<[u8; 32]>,
1924}
1925
1926impl Accrete for ForkLocalDepot {
1927    /// The original payload used to derive deterministic keys.
1928    ///
1929    /// Only the generated `[u8; 32]` key is stored internally.
1930    type Item = Vec<u8>;
1931
1932    /// Create the next generation.
1933    ///
1934    /// All current local keys are promoted into inherited history,
1935    /// and the returned generation starts with a fresh empty local layer.
1936    fn accrete(&self) -> Self {
1937        let mut inherited = self.inherited_keys.clone();
1938
1939        // Promote current local generation into inherited lineage
1940        inherited.extend(self.local_keys.iter().copied());
1941
1942        Self {
1943            inherited_keys: inherited,
1944            local_keys: BTreeSet::new(),
1945        }
1946    }
1947
1948    /// Returns inherited keys only.
1949    fn inherited(&self) -> Vec<[u8; 32]> {
1950        self.inherited_keys
1951            .iter()
1952            .copied()
1953            .collect()
1954    }
1955
1956    /// Returns current local generation keys only.
1957    fn local(&self) -> Vec<[u8; 32]> {
1958        self.local_keys
1959            .iter()
1960            .copied()
1961            .collect()
1962    }
1963
1964    /// Insert an item's deterministic key into the local generation.
1965    ///
1966    /// The payload itself is not stored here,
1967    /// only its stable key hash.
1968    ///
1969    /// Returns the deterministic key used for future lookups.
1970    fn add_to_local(
1971        &mut self,
1972        item: Self::Item,
1973    ) -> [u8; 32] {
1974        let key = Self::make_key(&item);
1975
1976        self.local_keys.insert(key);
1977
1978        key
1979    }
1980
1981    /// Checks existence only in local generation.
1982    fn exists_in_local(
1983        &self,
1984        key: &[u8; 32],
1985    ) -> bool {
1986        self.local_keys.contains(key)
1987    }
1988
1989    /// Checks existence only in inherited generations.
1990    fn exists_in_inherited(
1991        &self,
1992        key: &[u8; 32],
1993    ) -> bool {
1994        self.inherited_keys.contains(key)
1995    }
1996
1997    /// Remove a key only from the local generation.
1998    fn remove_from_local(
1999        &mut self,
2000        key: &[u8; 32],
2001    ) {
2002        self.local_keys.remove(key);
2003    }
2004
2005    /// Remove a key only from inherited generations.
2006    fn remove_from_inherited(
2007        &mut self,
2008        key: &[u8; 32],
2009    ) {
2010        self.inherited_keys.remove(key);
2011    }
2012}
2013
2014
2015/// **Authorization interface for a [`Routines`]**.
2016///
2017/// `RoutineOf` defines **who is allowed to execute** a routine at a given
2018/// point in time. It separates **authorization** from **execution**, which
2019/// is especially important in offchain contexts where signing keys,
2020/// rotation, and node-local state must be handled explicitly.
2021///
2022/// ## Why this exists
2023///
2024/// Offchain workers do not have the same execution guarantees as runtime
2025/// calls:
2026/// - there is no transactional rollback,
2027/// - failures do not revert state,
2028/// - and execution is best-effort.
2029///
2030/// Because of this, *authorization must be explicit* and *checked separately*
2031/// before a routine is allowed to run. `RoutineOf` provides a uniform way to:
2032///
2033/// - derive the concrete identifier (e.g. public key) authorized to run a routine,
2034/// - enforce key rotation and role-based access,
2035/// - fail early if the node is misconfigured or missing required keys.
2036///
2037/// ## Design principles
2038///
2039/// - `who()` must be **pure**: it must not mutate state.
2040/// - Failures are logged via [`Logging`] and treated as hard stops.
2041/// - The returned `Identifier` is typically used to sign payloads or
2042///   parameterize execution.
2043///
2044/// ## Example
2045///
2046/// ```text
2047/// Determine authorized signer
2048///        |
2049///        V
2050///   who() -> PublicKey
2051///        |
2052///        V
2053///  run_service(by = PublicKey)
2054/// ```
2055pub trait RoutineOf<Identifier, TimeStamp>: Logging<TimeStamp> + Routines<TimeStamp>
2056where
2057    TimeStamp: Time,
2058    Identifier: Portable,
2059{
2060    /// Returns the identifier authorized to execute the routine.
2061    ///
2062    /// If no valid identifier exists (e.g. missing key, inconsistent state),
2063    /// an error is logged and execution must not proceed.
2064    fn who(at: &TimeStamp) -> Result<Identifier, Self::Logger>;
2065}
2066
2067/// **Structured execution interface for offchain routines**.
2068///
2069/// `Routines` provides a **disciplined execution model** for offchain workers,
2070/// replacing ad-hoc logic with explicit phases and well-defined failure
2071/// semantics.
2072///
2073/// ## Why structured routines are needed
2074///
2075/// Offchain workers are fundamentally different from runtime calls:
2076///
2077/// | Runtime calls                    | Offchain workers                   |
2078/// |----------------------------------|------------------------------------|
2079/// | Transactional                    | Best-effort                        |
2080/// | Automatic rollback on error      | No rollback                        |
2081/// | State changes are atomic         | Partial execution is possible      |
2082/// | Errors bubble naturally          | Errors must be handled manually    |
2083///
2084/// As a result, offchain logic **must be structured explicitly** to ensure:
2085///
2086/// - invariants are checked before execution,
2087/// - routines run to *intentional completion*,
2088/// - partial state does not silently corrupt future runs,
2089/// - failures are observable and diagnosable.
2090///
2091/// The `Routines` trait enforces this structure.
2092///
2093/// ## Execution model
2094///
2095/// ```text
2096/// |-------------|
2097/// | can_run()   |  <- check invariants, prerequisites
2098/// |-----|-------|
2099///       |
2100///       V
2101/// |-------------|
2102/// | run_service |  <- perform the operation
2103/// |-----|-------|
2104///       |
2105///       V
2106/// |-------------|
2107/// | on_ran_*    |  <- bookkeeping, metrics, logging
2108/// |-------------|
2109/// ```
2110///
2111/// Each phase has a distinct responsibility, making offchain logic easier
2112/// to reason about, test, and evolve.
2113///
2114/// ## Failure semantics
2115///
2116/// - Any failure is **logged** via [`Logging`] and returned as `Logger`.
2117/// - Callers must treat failures as *hard stops* for the current routine.
2118/// - Subsequent routines may or may not execute, depending on orchestration.
2119///
2120/// This explicit handling avoids implicit control flow and makes routine
2121/// dependencies visible.
2122///
2123/// ## Arranging multiple routines
2124///
2125/// Structured routines compose naturally into pipelines:
2126///
2127/// ```text
2128/// Example
2129/// -------
2130/// Init -> Declare -> Rotate -> Elect
2131/// ```
2132///
2133/// Each routine:
2134/// - validates its own prerequisites,
2135/// - executes independently,
2136/// - leaves the system in a well-defined state.
2137///
2138/// This allows offchain workers to act as **deterministic coordinators**
2139/// rather than monolithic scripts.
2140///
2141/// ## Logging and observability
2142///
2143/// Because routines run outside the runtime's transactional model,
2144/// **logging is the primary observability mechanism**.
2145///
2146/// By integrating with [`Logging`]:
2147/// - all errors are logged exactly once,
2148/// - routine boundaries are visible in logs,
2149/// - execution can be traced across blocks.
2150///
2151/// This makes post-mortem debugging and operational monitoring feasible.
2152///
2153/// ## Example usage
2154///
2155/// ```text
2156/// let routine = MyRoutine { at: block };
2157///
2158/// if routine.can_run().is_ok() {
2159///     routine.run_service()?;
2160///     routine.on_ran_service();
2161/// }
2162/// ```
2163pub trait Routines<TimeStamp>: Logging<TimeStamp>
2164where
2165    TimeStamp: Time,
2166{
2167    /// Checks whether the routine is allowed to run.
2168    ///
2169    /// This method must:
2170    /// - validate prerequisites,
2171    /// - check invariants,
2172    /// - avoid mutating state.
2173    ///
2174    /// It exists to prevent partial execution in environments without
2175    /// rollback guarantees.
2176    fn can_run(&self) -> Result<(), Self::Logger>;
2177
2178    /// Executes the routine's core logic.
2179    ///
2180    /// Implementations should assume that `can_run` has already succeeded
2181    /// and focus solely on performing the intended operation.
2182    fn run_service(&self) -> Result<(), Self::Logger>;
2183
2184    /// Hook invoked after successful execution.
2185    ///
2186    /// This method is intended for:
2187    /// - logging,
2188    /// - metrics,
2189    /// - bookkeeping,
2190    /// - or emitting side effects that must only occur on success.
2191    ///
2192    /// The default implementation is a no-op.
2193    fn on_ran_service(&self) {}
2194}