Skip to main content

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::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;
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 convenience 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///
871/// This type is a **marker only** and carries no runtime data.
872#[derive(Clone, Copy, Debug, Default)]
873pub struct ForkAware<Context, Value, Routine>(PhantomData<(Value, Context, Routine)>)
874where
875    Context: frame_system::Config,
876    Value: Portable,
877    Routine: Routines<BlockNumberFor<Context>>;
878
879/// Default backend marker implementation for all valid [`ForkAware`] specializations.
880///
881/// This blanket implementation marks every well-formed [`ForkAware<Context, Value, Routine>`]
882/// type as a supported Substrate offchain storage backend.
883impl<Context, Value, Routine> SubstrateOffchainStorage for ForkAware<Context, Value, Routine>
884where
885    Context: frame_system::Config,
886    Value: Portable,
887    Routine: Routines<BlockNumberFor<Context>>,
888{
889}
890
891/// **Fork-Aware Offchain Storage Kind/Backend** Default [`KeyValueStore`]
892/// Implementation.
893///
894/// Intended for Substrate FRAME-based runtimes only.
895///
896/// This implementation is backed by **fork-aware offchain storage**
897/// ([`StorageValueRef::local`]).
898///
899/// The timestamp type is the runtime's block number ([`BlockNumberFor`]),
900/// ensuring that all logs are tagged with the block context in which
901/// the operation occurred.
902impl<T, Value, Routine> KeyValueStore<Value, BlockNumberFor<T>> for ForkAware<T, Value, Routine>
903where
904    T: frame_system::Config,
905    Value: Portable,
906    Routine: OffchainStorageError<Self> + Routines<BlockNumberFor<T>>,
907{
908    /// Keys are raw byte slices; allows flexible usage for any encoded identifier.
909    type Key = [u8];
910
911    /// Value type implementing [`Encode`] and [`Decode`]
912    type Value = Value;
913
914    /// Writes a value to **fork-aware offchain storage**.
915    ///
916    /// For **get-check-set** use [`Self::mutate`] instead for concurrency safety.
917    ///
918    /// Values written using this method are scoped to the current fork and
919    /// will be reverted automatically if the fork is abandoned.
920    fn insert(
921        key: &Self::Key,
922        value: &Value,
923        _target: Option<&str>,
924        _fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
925    ) -> Result<(), Self::Logger> {
926        let storage_ref = StorageValueRef::local(key);
927        storage_ref.set(value);
928        Ok(())
929    }
930
931    /// Reads a value from **fork-aware offchain storage**.
932    ///
933    /// The returned value reflects only the state of the current fork and
934    /// may differ across competing forks.
935    fn get(
936        key: &Self::Key,
937        target: Option<&str>,
938        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
939    ) -> Result<Option<Value>, Self::Logger> {
940        let storage_ref = StorageValueRef::local(key);
941        let block = frame_system::Pallet::<T>::block_number();
942
943        let Ok(value) = storage_ref.get() else {
944            return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
945                &<Routine as OffchainStorageError<Self>>::decode_failed().into(),
946                block,
947                target,
948                fmt,
949            ));
950        };
951
952        Ok(value)
953    }
954
955    /// Removes a value from **fork-aware offchain storage**.
956    ///
957    /// Removals are scoped to the current fork and are reverted automatically
958    /// if the fork is abandoned.
959    fn remove(
960        key: &Self::Key,
961        target: Option<&str>,
962        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
963    ) -> Result<Option<Value>, Self::Logger> {
964        let storage_ref = StorageValueRef::local(key);
965        let block = frame_system::Pallet::<T>::block_number();
966
967        let Ok(existing) = storage_ref.get::<Value>() else {
968            return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
969                &<Routine as OffchainStorageError<Self>>::decode_failed().into(),
970                block,
971                target,
972                fmt,
973            ));
974        };
975
976        let mut storage_ref = storage_ref;
977        storage_ref.clear();
978
979        Ok(existing)
980    }
981
982    /// Performs an atomic read–modify–write operation on **fork-aware offchain
983    /// storage**.
984    ///
985    /// The closure is invoked with the current value, if any, and **must return**
986    /// the new value to store. Removal is not supported by this method.
987    ///
988    /// Mutations performed by this method:
989    /// - are visible only on the current fork,
990    /// - are reverted automatically on re-orgs,
991    /// - and are safe to use with speculative chain state.
992    fn mutate<F>(
993        key: &Self::Key,
994        f: F,
995        target: Option<&str>,
996        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
997    ) -> Result<(), Self::Logger>
998    where
999        F: FnOnce(Result<Option<Value>, Self::Logger>) -> Result<Value, Self::Logger>,
1000    {
1001        let storage_ref = StorageValueRef::local(key);
1002        let block = frame_system::Pallet::<T>::block_number();
1003
1004        let res = storage_ref.mutate::<Value, Self::Logger, _>(|current| {
1005            // Normalize storage read into Result<Option<Value>, Logged>
1006            let current = match current {
1007                Ok(opt) => Ok(opt),
1008                Err(_) => Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1009                    &<Routine as OffchainStorageError<Self>>::decode_failed().into(),
1010                    block,
1011                    target,
1012                    fmt,
1013                )),
1014            };
1015
1016            // Delegate mutation logic to caller
1017            f(current)
1018        });
1019
1020        match res {
1021            Ok(_) => Ok(()),
1022
1023            Err(MutateStorageError::ConcurrentModification(_)) => {
1024                return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1025                    &<Routine as OffchainStorageError<Self>>::concurrent_mutation().into(),
1026                    block,
1027                    target,
1028                    fmt,
1029                ));
1030            }
1031
1032            Err(MutateStorageError::ValueFunctionFailed(logged)) => {
1033                Err(<Self as Logging<BlockNumberFor<T>>>::error(
1034                    &logged, block, target, fmt,
1035                ))
1036            }
1037        }
1038    }
1039}
1040
1041// ===============================================================================
1042// ````````````````````````` FINALIZED STORAGE UTILITIES `````````````````````````
1043// ===============================================================================
1044
1045/// Defines a **finality evaluation policy** for values managed by
1046/// [`Finalized`] storage.
1047///
1048/// Intended for **Substrate FRAME-based runtimes only**.
1049///
1050/// This trait specifies the parameters used to derive a **confidence signal**
1051/// for speculative, fork-aware data based on:
1052/// - elapsed wall-clock time, and
1053/// - block-scoped repeated observations.
1054///
1055/// It only answers:
1056/// - *how long* a value must survive before it may be considered stable, and
1057/// - *how many distinct block observations* are required to strengthen confidence.
1058///
1059/// The policy provides *inputs* to confidence evaluation and does not
1060/// imply on-chain finality or absolute truth.
1061pub trait FinalizedPolicy<Context>
1062where
1063    Context: pallet_timestamp::Config,
1064{
1065    /// Wall-clock **elapsed time window** that must pass *after the first
1066    /// observation* before a value may begin to contribute to a stronger
1067    /// confidence signal.
1068    ///
1069    /// Conceptually, this represents the delay between:
1070    /// - an **initial observation window**, and
1071    /// - an **optimal finalized window** where confidence can be evaluated.
1072    ///
1073    /// The duration is expressed using the runtime’s timestamp type
1074    /// (see [`pallet_timestamp::Config::Moment`]).
1075    fn finality_after() -> <Context as pallet_timestamp::Config>::Moment;
1076
1077    /// Number of **distinct blocks** in which the value must be observed
1078    /// *after* the finality window has elapsed.
1079    ///
1080    /// Observations are block-scoped:
1081    /// - At most one observation per block is counted.
1082    /// - Repeated OCW executions within the same block do not increase this value.
1083    ///
1084    /// This parameter acts as a confidence-strengthening threshold
1085    /// to guard against transient forks.
1086    fn finality_ticks() -> BlockNumberFor<Context>;
1087}
1088
1089/// Defines **caller-facing error signals** specific to
1090/// [`Finalized`] storage.
1091///
1092/// Intended for **Substrate FRAME-based runtimes only**.
1093///
1094/// This trait allows callers to control how **semantic invariant violations**
1095/// detected by the `Finalized` storage model are surfaced as
1096/// [`DispatchError`] values.
1097///
1098/// These errors:
1099/// - originate from finality-specific consistency checks,
1100/// - are logged by the storage layer,
1101/// - and are returned to the caller as *signals* of inconsistency,
1102///   not as definitive storage failures.
1103///
1104/// This trait does not affect storage behavior. It only defines
1105/// which error values are emitted when an invariant is violated.
1106pub trait FinalizedOffchainStorageError<Context, Value>
1107where
1108    Context: frame_system::Config,
1109{
1110    /// Concrete error type chosen by the caller.
1111    ///
1112    /// This error is converted into a [`DispatchError`] before being
1113    /// logged or returned.
1114    type Error: RuntimeError;
1115
1116    /// Emitted when a **fork-aware value hash exists without a corresponding
1117    /// entry in persistent storage**.
1118    ///
1119    /// This indicates a hanging speculative value. The fork-aware entry
1120    /// is cleaned up automatically before this error is returned.
1121    fn hanging_hash() -> Self::Error;
1122
1123    /// Emitted when **persistent storage contains no value at all**
1124    /// for the given key.
1125    ///
1126    /// This means there is **no speculative value being tracked**,
1127    /// and therefore the fork-aware entry has no semantic meaning.
1128    ///
1129    /// When this condition is detected, the fork-aware entry is
1130    /// cleaned up automatically before this error is returned.
1131    fn hanging_value() -> Self::Error;
1132}
1133
1134// ===============================================================================
1135// `````````````````````````````` FINALIZED STORAGE ``````````````````````````````
1136// ===============================================================================
1137
1138/// Marker type for finality-aware offchain storage, combining fork-aware and
1139/// persistent state to derive confidence-graded values via routine-defined
1140/// policies and observations.
1141///
1142/// Intended for **Substrate FRAME-based runtimes only**.
1143///
1144/// The `Finalized` storage model:
1145/// - records values speculatively using fork-aware storage,
1146/// - tracks historical observations in persistent storage,
1147/// - and exposes values only after evaluating time and observation-based
1148///   finality guarantees.
1149///
1150/// Finality is determined by:
1151/// - a wall-clock time window (see [`FinalizedPolicy`]),
1152/// - and repeated successful observations.
1153///
1154/// This marker is used to specialize [`KeyValueStore`] implementations that
1155/// combine [`ForkAware`] and [`Persistent`] storage to provide confidence-graded
1156/// values (see [`Confidence`]).
1157///
1158/// ## Behavioral contract
1159///
1160/// Any routine using `Finalized` storage **must provide error policies for the
1161/// exact internal storage forms used by this model** via
1162/// [`OffchainStorageError`]:
1163///
1164/// - [`ForkAware<Context, ValueHash, Routine>`], which stores speculative
1165///   fork-local identity using [`ValueHash`], and
1166/// - [`Persistent<Context, Ledger<Context, Moment<Context>, Value>, Routine>`],
1167///   which stores the persistent observation ledger using [`Ledger`] and
1168///   wall-clock [`Moment`].
1169///
1170/// In addition, the routine must define:
1171/// - a [`FinalizedPolicy`] describing when a value becomes stable, and
1172/// - [`FinalizedOffchainStorageError`] values for finality-specific
1173///   invariant violations.
1174///
1175/// Together, these requirements ensure that:
1176/// - fork-aware and persistent state remain consistent,
1177/// - semantic invariants are enforced at a single, centralized layer,
1178/// - and all failures are surfaced as **caller-defined error signals**
1179///   and logged exactly once.
1180///
1181/// ## Value-first semantics
1182///
1183/// This storage model is **value-first**: confidence is tied to the observed
1184/// *value*, not just the key. If the same value is inserted again for the same
1185/// key, its accumulated confidence is **reset**, as the insertion is treated as
1186/// a fresh observation sequence.
1187///
1188/// Callers are therefore responsible for deciding whether repeated insertions
1189/// of the same value are semantically meaningful. To avoid unintended confidence
1190/// resets, routines should refrain from inserting identical values multiple
1191/// times unless a reset is explicitly desired.
1192///
1193/// ## Timestamp semantics
1194///
1195/// All logging and routine behavior associated with this storage model is
1196/// **explicitly bound to block numbers** via [`BlockNumberFor<Context>`].
1197/// This type does **not** accept a generic timestamp parameter.
1198///
1199/// Wall-clock time, when required for finality evaluation, is obtained
1200/// explicitly from [`pallet_timestamp`].
1201///
1202/// ## Type parameters
1203///
1204/// - `Context`: The active runtime type (i.e. a type implementing
1205///   [`frame_system::Config`]). This binds the storage model to a specific
1206///   runtime configuration.
1207/// - `Value`: The value type whose finality is being tracked.
1208/// - `Routine`: A routine type implementing [`Routines`] parameterized
1209///   by [`BlockNumberFor<Context>`], allowing logging, error handling,
1210///   policy evaluation, and invariant enforcement to be specialized
1211///   at the type level.
1212///
1213/// This type is a **marker only** and carries no runtime data.
1214#[derive(Clone, Copy, Debug)]
1215pub struct Finalized<Context, Value, Routine>(PhantomData<(Value, Context, Routine)>)
1216where
1217    Context: frame_system::Config,
1218    Value: Portable,
1219    Routine: Routines<BlockNumberFor<Context>>;
1220
1221/// Stable, fork-independent identifier for values managed by [`Finalized`] storage.
1222///
1223/// `ValueHash` is computed using the `blake2_256` hash of the
1224/// SCALE-encoded representation of a value.
1225///
1226/// Within the [`Finalized`] storage model, this hash is used to:
1227/// - identify the *actual content* associated with a fork-aware key,
1228/// - correlate speculative fork-aware entries with their corresponding
1229///   persistent ledger records,
1230/// - and track value observations across forks.
1231///
1232/// Fork-aware storage records only the `ValueHash`, while the full value
1233/// and its observation metadata are stored persistently. This ensures that
1234/// semantic identity is preserved across re-orgs while allowing speculative
1235/// state to be reverted safely.
1236#[derive(Encode, Decode, Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord)]
1237pub struct ValueHash(pub [u8; 32]);
1238
1239impl ValueHash {
1240    pub fn new(hash: [u8; 32]) -> Self {
1241        ValueHash(hash)
1242    }
1243}
1244
1245/// Persistent observation record for a value managed by [`Finalized`] storage.
1246///
1247/// An `Observation` captures *when* a value was seen and *how many distinct
1248/// blocks* it has survived after entering the finality window.
1249///
1250/// This structure does not imply finality by itself; it only provides
1251/// the evidence required by [`FinalizedPolicy`] to derive a
1252/// [`Confidence`] level.
1253#[derive(Encode, Decode, Debug, Clone)]
1254pub struct Observation<Context, Value>
1255where
1256    Context: pallet_timestamp::Config,
1257{
1258    /// Wall-clock time when the value was first observed.
1259    pub first_seen: Moment<Context>,
1260
1261    /// Wall-clock time when the value was last observed.
1262    pub last_seen: Moment<Context>,
1263
1264    /// Number of distinct blocks in which the value was observed
1265    /// after the finality window elapsed.
1266    pub blocks_seen: BlockNumberFor<Context>,
1267
1268    /// The observed value.
1269    pub value: Value,
1270}
1271
1272/// Persistent observation ledger used by [`Finalized`] storage.
1273///
1274/// A `Ledger` maps a stable [`ValueHash`] to its corresponding
1275/// [`Observation`] record.
1276///
1277/// Within the [`Finalized`] storage model:
1278/// - The ledger is stored in **persistent offchain storage**.
1279/// - Entries are **fork-independent** and survive chain re-organizations.
1280/// - Each entry accumulates observation history across OCW executions.
1281///
1282/// The ledger acts as the authoritative source of truth for:
1283/// - value identity (via [`ValueHash`]),
1284/// - temporal stability,
1285/// - and block-scoped confirmation counts.
1286///
1287/// It is consulted to derive confidence levels (see [`Confidence`])
1288/// and to detect and clean up fork-aware inconsistencies.
1289#[derive(Encode, Decode, Debug, Clone)]
1290pub struct Ledger<Context, Value>(pub ConfidenceMap<Context, Value>)
1291where
1292    Context: pallet_timestamp::Config,
1293    Value: Encode + Decode + Clone;
1294
1295// Type Alias for Persistent Ledger
1296type ConfidenceMap<Context, Value> = BTreeMap<ValueHash, Observation<Context, Value>>;
1297
1298/// Confidence **signal** derived for a value evaluated by [`Finalized`] storage.
1299///
1300/// This enum represents the outcome of applying a [`FinalizedPolicy`] to an
1301/// observed value, based on elapsed time and block-scoped observations.
1302///
1303/// It expresses a **signal of stability**, not on-chain finality and not a
1304/// definitive statement of truth.
1305#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
1306pub enum Confidence<Value>
1307where
1308    Value: Portable,
1309{
1310    /// A **strong confidence signal**.
1311    ///
1312    /// The value has:
1313    /// - survived the configured finality time window, and
1314    /// - been observed across enough distinct blocks.
1315    ///
1316    /// This signal suggests that the value is *likely stable* and that
1317    /// irreversible or non-recoverable actions may be reasonable.
1318    Safe(Value),
1319
1320    /// A **weak confidence signal**.
1321    ///
1322    /// The value has survived the finality time window, but has **not yet**
1323    /// accumulated enough block-scoped observations.
1324    ///
1325    /// This signal suggests that only optimistic or recoverable actions
1326    /// should be considered.
1327    Risky(Value),
1328
1329    /// A **negative confidence signal**.
1330    ///
1331    /// The value exists, but the finality time window has **not** elapsed yet.
1332    ///
1333    /// This signal suggests that no action-reversible or irreversible-
1334    /// should be taken at this stage.
1335    Unsafe(Value),
1336}
1337
1338/// Wall-clock timestamp type used by [`Finalized`] storage.
1339///
1340/// An alias for the timestamp type provided by [`pallet_timestamp`]
1341/// for the given runtime.
1342///
1343/// It is used exclusively for **time-based finality evaluation**
1344/// (for example, measuring how long a value has survived),
1345/// and is **not** used for ordering, counting, or block-based logic.
1346///
1347/// Block-scoped semantics (such as observation counts) are expressed
1348/// separately via [`BlockNumberFor`].
1349pub type Moment<T> = <T as pallet_timestamp::Config>::Moment;
1350
1351/// [`KeyValueStore`] implementation for [`Finalized`] storage semantics.
1352///
1353/// This implementation materializes the behavioral contract defined by
1354/// [`Finalized`] by combining:
1355/// - fork-aware storage for speculative state,
1356/// - persistent storage for observation history,
1357/// - and routine-defined policies for finality evaluation and error signaling.
1358///
1359/// The required bounds ensure that the routine:
1360/// - defines **when** a value becomes stable ([`FinalizedPolicy`]),
1361/// - provides caller-defined error signals for finality invariants
1362///   ([`FinalizedOffchainStorageError`]),
1363/// - and supplies [`OffchainStorageError`] error policies for the
1364/// **exact storage forms** used internally by this model for:
1365///   - [`ForkAware<.., ValueHash, ..>`] using [`ValueHash`], and
1366///   - [`Persistent<.., Ledger<...>, ..>`] using [`Ledger`].
1367///
1368/// This guarantees that all storage failures and semantic violations are
1369/// surfaced consistently as caller-defined errors and are logged exactly
1370/// once at the correct abstraction layer.
1371impl<T, Value, Routine> KeyValueStore<Value, BlockNumberFor<T>> for Finalized<T, Value, Routine>
1372where
1373    T: pallet_timestamp::Config,
1374    Value: Portable,
1375    Routine: FinalizedOffchainStorageError<T, Value>
1376        + FinalizedPolicy<T>
1377        + OffchainStorageError<Persistent<T, Ledger<T, Value>, Routine>>
1378        + OffchainStorageError<ForkAware<T, ValueHash, Routine>>
1379        + Routines<BlockNumberFor<T>>,
1380{
1381    /// Keys are raw byte slices; allows flexible usage for any encoded identifier.
1382    type Key = [u8];
1383
1384    /// Return value type used when querying a key.
1385    ///
1386    /// The value is wrapped in [`Confidence`], representing a
1387    /// **confidence signal** derived from the [`Finalized`] storage
1388    /// model rather than a definitive truth or on-chain finality.
1389    type Value = Confidence<Value>;
1390
1391    /// Inserts a value **speculatively** under finality-aware semantics.
1392    ///
1393    /// This operation:
1394    /// - computes a stable [`ValueHash`] for fork-independent identity,
1395    /// - records the hash in **fork-aware storage** (speculative marker),
1396    /// - and inserts or updates an [`Observation`] in the **persistent ledger**.
1397    ///
1398    /// No confidence is implied by insertion alone; this operation only
1399    /// records *existence* and initializes observation tracking.
1400    fn insert(
1401        key: &Self::Key,
1402        value: &Value,
1403        target: Option<&str>,
1404        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1405    ) -> Result<(), Self::Logger> {
1406        // Compute stable value hash (identity across forks)
1407        let hash = ValueHash(blake2_256(&value.encode()));
1408
1409        // Read wall-clock time (confidence anchor)
1410        let now: Moment<T> = pallet_timestamp::Pallet::<T>::get();
1411
1412        // Write fork-aware speculative marker
1413        // (this is fork-local and will be reorged)
1414        ForkAware::<T, ValueHash, Routine>::insert(key, &hash, target, fmt)?;
1415
1416        // Persistent ledger mutation
1417        Persistent::<T, Ledger<T, Value>, Routine>::mutate(
1418            key,
1419            |current| {
1420                let mut ledger = match current {
1421                    Ok(Some(existing)) => existing,
1422                    Ok(None) => Ledger(ConfidenceMap::new()),
1423                    Err(logged) => return Err(logged),
1424                };
1425
1426                ledger.0.insert(
1427                    hash,
1428                    Observation {
1429                        first_seen: now,
1430                        last_seen: now,
1431                        blocks_seen: Zero::zero(),
1432                        value: value.clone(),
1433                    },
1434                );
1435
1436                Ok(ledger)
1437            },
1438            target,
1439            fmt,
1440        )?;
1441
1442        Ok(())
1443    }
1444
1445    /// Reads the value associated with the current fork and derives the
1446    /// value wrapped in a [`Confidence`] signal.
1447    ///
1448    /// Returned signals:
1449    /// - [`Confidence::Unsafe`] - finality window not elapsed.
1450    /// - [`Confidence::Risky`]  - time elapsed, insufficient block observations.
1451    /// - [`Confidence::Safe`]   - time and observation thresholds satisfied.
1452    ///
1453    /// Any detected invariant violation (for example, a fork-aware hash
1454    /// without a ledger entry) is logged and cleaned up automatically.
1455    fn get(
1456        key: &Self::Key,
1457        target: Option<&str>,
1458        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1459    ) -> Result<Option<Confidence<Value>>, Self::Logger> {
1460        let now: Moment<T> = pallet_timestamp::Pallet::<T>::get();
1461        let block = frame_system::Pallet::<T>::block_number();
1462
1463        // Read fork-aware speculative hash
1464        let hash = match ForkAware::<T, ValueHash, Routine>::get(key, target, fmt)? {
1465            Some(h) => h,
1466            None => return Ok(None),
1467        };
1468
1469        // Will be produced inside mutation
1470        let mut result: Option<Confidence<Value>> = None;
1471
1472        // Atomic persistent ledger mutation
1473        Persistent::<T, Ledger<T, Value>, Routine>::mutate(
1474            key,
1475            |current| {
1476                let mut ledger = match current {
1477                    Ok(Some(l)) => l,
1478                    Ok(None) => {
1479                        // Fork-aware exists but ledger missing -> clean fork-aware
1480                        ForkAware::<T, ValueHash, Routine>::remove(key, target, fmt)?;
1481                        return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1482                            &<Routine as FinalizedOffchainStorageError<T, Value>>::hanging_value()
1483                                .into(),
1484                            block,
1485                            target,
1486                            fmt,
1487                        ));
1488                    }
1489                    Err(logged) => return Err(logged),
1490                };
1491
1492                let obs = match ledger.0.get_mut(&hash) {
1493                    Some(o) => o,
1494                    None => {
1495                        // Fork-aware hash has no backing ledger entry -> cleanup
1496                        ForkAware::<T, ValueHash, Routine>::remove(key, target, fmt)?;
1497                        return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1498                            &<Routine as FinalizedOffchainStorageError<T, Value>>::hanging_hash()
1499                                .into(),
1500                            block,
1501                            target,
1502                            fmt,
1503                        ));
1504                    }
1505                };
1506
1507                // Snapshot for confidence computation
1508                let first_seen = obs.first_seen;
1509                let last_seen = obs.last_seen;
1510                let obs_count = obs.blocks_seen;
1511                let value = obs.value.clone();
1512
1513                // Confidence evaluation
1514                let after = <Routine as FinalizedPolicy<T>>::finality_after();
1515                let ticks = <Routine as FinalizedPolicy<T>>::finality_ticks();
1516
1517                // Update observation metadata
1518                obs.last_seen = now;
1519
1520                // Evaluate confidence based on temporal finality and repeated observations.
1521                //
1522                // Time-window finality check
1523                // - `first_seen`: moment of the first successful observation (insertion time)
1524                // - `after`:      required finality window duration
1525                // - `last_seen`:  moment of the most recent successful observation (from storage)
1526                //
1527                // If (first_seen + after) > last_seen, the value has NOT yet survived
1528                // the required finality window - meaning we have not observed it
1529                // long enough across time. The value remains `Unsafe`.
1530                //
1531                // Otherwise, the value has lived past the temporal finality window,
1532                // and we can evaluate observation-based stability.
1533                let confidence = match first_seen.saturating_add(after) > last_seen {
1534                    // Still within the finality time window -> not stable yet.
1535                    true => Confidence::Unsafe(value),
1536
1537                    // Time window satisfied; now evaluate repeated observations.
1538                    false => match obs_count < ticks {
1539                        true => {
1540                            // We only increment observation ticks if this observation
1541                            // occurred in a strictly new moment. Multiple observations
1542                            // within the same moment do not increase confidence.
1543                            if last_seen < now {
1544                                obs.blocks_seen += One::one();
1545                            }
1546
1547                            // Not enough distinct-moment observations yet -> still risky.
1548                            Confidence::Risky(value)
1549                        }
1550
1551                        // Required number of distinct-moment observations reached,
1552                        // and the time window has already elapsed -> value is finalized.
1553                        false => Confidence::Safe(value),
1554                    },
1555                };
1556
1557                result = Some(confidence);
1558
1559                Ok(ledger)
1560            },
1561            target,
1562            fmt,
1563        )?;
1564
1565        Ok(result)
1566    }
1567
1568    /// Removes the value associated with the **current fork**.
1569    ///
1570    /// Removal semantics:
1571    /// - The fork-aware marker is always removed first.
1572    /// - The corresponding persistent ledger entry is removed next.
1573    /// - The ledger itself is deleted if it becomes empty.
1574    ///
1575    /// This ensures no semantic or historical state is left behind once
1576    /// the value is no longer relevant.
1577    fn remove(
1578        key: &Self::Key,
1579        target: Option<&str>,
1580        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1581    ) -> Result<Option<Value>, Self::Logger> {
1582        let block = frame_system::Pallet::<T>::block_number();
1583
1584        // Read fork-aware hash (what we are removing)
1585        let hash = match ForkAware::<T, ValueHash, Routine>::get(key, target, fmt)? {
1586            Some(h) => h,
1587            None => return Ok(None), // nothing to remove
1588        };
1589
1590        // Always remove fork-aware entry first
1591        ForkAware::<T, ValueHash, Routine>::remove(key, target, fmt)?;
1592
1593        // Remove from persistent ledger atomically
1594        let mut removed: Option<Value> = None;
1595
1596        let mut is_empty = false;
1597
1598        Persistent::<T, Ledger<T, Value>, Routine>::mutate(
1599            key,
1600            |current| {
1601                let mut ledger = match current {
1602                    Ok(Some(l)) => l,
1603                    Ok(None) => {
1604                        return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1605                            &<Routine as FinalizedOffchainStorageError<T, Value>>::hanging_value()
1606                                .into(),
1607                            block,
1608                            target,
1609                            fmt,
1610                        ));
1611                    }
1612                    Err(logged) => return Err(logged),
1613                };
1614
1615                if let Some(obs) = ledger.0.remove(&hash) {
1616                    removed = Some(obs.value);
1617                }
1618
1619                if ledger.0.is_empty() {
1620                    is_empty = true;
1621                }
1622
1623                Ok(ledger)
1624            },
1625            target,
1626            fmt,
1627        )?;
1628
1629        // Drop empty ledger (no semantic meaning left)
1630        if is_empty {
1631            Persistent::<T, Ledger<T, Value>, Routine>::remove(key, target, fmt)?;
1632        }
1633
1634        Ok(removed)
1635    }
1636
1637    /// Mutates the value associated with a key under **finality-aware semantics**.
1638    ///
1639    /// The closure `f` receives the current value, if any, and must return
1640    /// a new value to replace it.
1641    ///
1642    /// Replacing a value **resets all finality observations**: the new value
1643    /// is treated as freshly observed and must re-accumulate confidence.
1644    ///
1645    /// The update is scoped to the current fork and preserves all storage
1646    /// invariants. Any detected invariant violation is logged once and
1647    /// cleaned up automatically before the error is returned.
1648    fn mutate<F>(
1649        key: &Self::Key,
1650        f: F,
1651        target: Option<&str>,
1652        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1653    ) -> Result<(), Self::Logger>
1654    where
1655        F: FnOnce(Result<Option<Value>, Self::Logger>) -> Result<Value, Self::Logger>,
1656    {
1657        let now: Moment<T> = pallet_timestamp::Pallet::<T>::get();
1658        let block = frame_system::Pallet::<T>::block_number();
1659
1660        // Fork-aware mutation is the outer authority
1661        let result = ForkAware::<T, ValueHash, Routine>::mutate(
1662            key,
1663            |current_hash| {
1664                // Resolve current value from persistent ledger
1665                let current_value = match current_hash {
1666                    Err(logged) => {
1667                        return Err(logged);
1668                    }
1669
1670                    Ok(None) => None,
1671
1672                    Ok(Some(hash)) => {
1673                        let ledger =
1674                            Persistent::<T, Ledger<T, Value>, Routine>::get(key, target, fmt)?;
1675
1676                        let ledger = match ledger {
1677                            Some(l) => l,
1678                            None => {
1679                                return Err(<Self as Logging<BlockNumberFor<T>>>::warn(
1680                                        &<Routine as FinalizedOffchainStorageError<
1681                                            T,
1682                                            Value,
1683                                        >>::hanging_value()
1684                                            .into(),
1685                                        block,
1686                                        target,
1687                                        fmt,
1688                                    ));
1689                            }
1690                        };
1691
1692                        match ledger.0.get(&hash) {
1693                            Some(obs) => Some(obs.value.clone()),
1694                            None => None,
1695                        }
1696                    }
1697                };
1698
1699                // Delegate domain mutation
1700                let new_value = f(Ok(current_value))?;
1701
1702                // Compute new identity
1703                let new_hash = ValueHash(blake2_256(&new_value.encode()));
1704
1705                // Update persistent ledger
1706                Persistent::<T, Ledger<T, Value>, Routine>::mutate(
1707                    key,
1708                    |ledger_result| {
1709                        let mut ledger = match ledger_result {
1710                            Ok(Some(l)) => l,
1711                            Ok(None) => Ledger(ConfidenceMap::new()),
1712                            Err(logged) => return Err(logged),
1713                        };
1714
1715                        // Remove old observation
1716                        if let Ok(Some(old_hash)) = current_hash {
1717                            ledger.0.remove(&old_hash);
1718                        }
1719
1720                        // Insert new observation
1721                        ledger.0.insert(
1722                            new_hash,
1723                            Observation {
1724                                first_seen: now,
1725                                last_seen: now,
1726                                blocks_seen: Zero::zero(),
1727                                value: new_value,
1728                            },
1729                        );
1730
1731                        Ok(ledger)
1732                    },
1733                    target,
1734                    fmt,
1735                )?;
1736                // Commit new fork-aware hash
1737                Ok(new_hash)
1738            },
1739            target,
1740            fmt,
1741        );
1742
1743        match result {
1744            Ok(_) => Ok(()),
1745
1746            Err(logged) => {
1747                if logged
1748                    == <Routine as FinalizedOffchainStorageError<T, Value>>::hanging_value().into()
1749                {
1750                    ForkAware::<T, ValueHash, Routine>::remove(key, target, fmt)?;
1751                }
1752                Err(logged)
1753            }
1754        }
1755    }
1756}
1757
1758// ===============================================================================
1759// `````````````````````````````````` ROUTINES ```````````````````````````````````
1760// ===============================================================================
1761
1762/// **Authorization interface for a [`Routines`]**.
1763///
1764/// `RoutineOf` defines **who is allowed to execute** a routine at a given
1765/// point in time. It separates **authorization** from **execution**, which
1766/// is especially important in offchain contexts where signing keys,
1767/// rotation, and node-local state must be handled explicitly.
1768///
1769/// ## Why this exists
1770///
1771/// Offchain workers do not have the same execution guarantees as runtime
1772/// calls:
1773/// - there is no transactional rollback,
1774/// - failures do not revert state,
1775/// - and execution is best-effort.
1776///
1777/// Because of this, *authorization must be explicit* and *checked separately*
1778/// before a routine is allowed to run. `RoutineOf` provides a uniform way to:
1779///
1780/// - derive the concrete identifier (e.g. public key) authorized to run a routine,
1781/// - enforce key rotation and role-based access,
1782/// - fail early if the node is misconfigured or missing required keys.
1783///
1784/// ## Design principles
1785///
1786/// - `who()` must be **pure**: it must not mutate state.
1787/// - Failures are logged via [`Logging`] and treated as hard stops.
1788/// - The returned `Identifier` is typically used to sign payloads or
1789///   parameterize execution.
1790///
1791/// ## Example
1792///
1793/// ```text
1794/// Determine authorized signer
1795///        |
1796///        V
1797///   who() -> PublicKey
1798///        |
1799///        V
1800///  run_service(by = PublicKey)
1801/// ```
1802pub trait RoutineOf<Identifier, TimeStamp>: Logging<TimeStamp> + Routines<TimeStamp>
1803where
1804    TimeStamp: Time,
1805    Identifier: Portable,
1806{
1807    /// Returns the identifier authorized to execute the routine.
1808    ///
1809    /// If no valid identifier exists (e.g. missing key, inconsistent state),
1810    /// an error is logged and execution must not proceed.
1811    fn who(at: &TimeStamp) -> Result<Identifier, Self::Logger>;
1812}
1813
1814/// **Structured execution interface for offchain routines**.
1815///
1816/// `Routines` provides a **disciplined execution model** for offchain workers,
1817/// replacing ad-hoc logic with explicit phases and well-defined failure
1818/// semantics.
1819///
1820/// ## Why structured routines are needed
1821///
1822/// Offchain workers are fundamentally different from runtime calls:
1823///
1824/// | Runtime calls                    | Offchain workers                   |
1825/// |----------------------------------|------------------------------------|
1826/// | Transactional                    | Best-effort                        |
1827/// | Automatic rollback on error      | No rollback                        |
1828/// | State changes are atomic         | Partial execution is possible      |
1829/// | Errors bubble naturally          | Errors must be handled manually    |
1830///
1831/// As a result, offchain logic **must be structured explicitly** to ensure:
1832///
1833/// - invariants are checked before execution,
1834/// - routines run to *intentional completion*,
1835/// - partial state does not silently corrupt future runs,
1836/// - failures are observable and diagnosable.
1837///
1838/// The `Routines` trait enforces this structure.
1839///
1840/// ## Execution model
1841///
1842/// ```text
1843/// |-------------|
1844/// | can_run()   |  <- check invariants, prerequisites
1845/// |-----|-------|
1846///       |
1847///       V
1848/// |-------------|
1849/// | run_service |  <- perform the operation
1850/// |-----|-------|
1851///       |
1852///       V
1853/// |-------------|
1854/// | on_ran_*    |  <- bookkeeping, metrics, logging
1855/// |-------------|
1856/// ```
1857///
1858/// Each phase has a distinct responsibility, making offchain logic easier
1859/// to reason about, test, and evolve.
1860///
1861/// ## Failure semantics
1862///
1863/// - Any failure is **logged** via [`Logging`] and returned as `Logger`.
1864/// - Callers must treat failures as *hard stops* for the current routine.
1865/// - Subsequent routines may or may not execute, depending on orchestration.
1866///
1867/// This explicit handling avoids implicit control flow and makes routine
1868/// dependencies visible.
1869///
1870/// ## Arranging multiple routines
1871///
1872/// Structured routines compose naturally into pipelines:
1873///
1874/// ```text
1875/// Example
1876/// -------
1877/// Init -> Declare -> Rotate -> Elect
1878/// ```
1879///
1880/// Each routine:
1881/// - validates its own prerequisites,
1882/// - executes independently,
1883/// - leaves the system in a well-defined state.
1884///
1885/// This allows offchain workers to act as **deterministic coordinators**
1886/// rather than monolithic scripts.
1887///
1888/// ## Logging and observability
1889///
1890/// Because routines run outside the runtime’s transactional model,
1891/// **logging is the primary observability mechanism**.
1892///
1893/// By integrating with [`Logging`]:
1894/// - all errors are logged exactly once,
1895/// - routine boundaries are visible in logs,
1896/// - execution can be traced across blocks.
1897///
1898/// This makes post-mortem debugging and operational monitoring feasible.
1899///
1900/// ## Example usage
1901///
1902/// ```text
1903/// let routine = MyRoutine { at: block };
1904///
1905/// if routine.can_run().is_ok() {
1906///     routine.run_service()?;
1907///     routine.on_ran_service();
1908/// }
1909/// ```
1910pub trait Routines<TimeStamp>: Logging<TimeStamp>
1911where
1912    TimeStamp: Time,
1913{
1914    /// Checks whether the routine is allowed to run.
1915    ///
1916    /// This method must:
1917    /// - validate prerequisites,
1918    /// - check invariants,
1919    /// - avoid mutating state.
1920    ///
1921    /// It exists to prevent partial execution in environments without
1922    /// rollback guarantees.
1923    fn can_run(&self) -> Result<(), Self::Logger>;
1924
1925    /// Executes the routine’s core logic.
1926    ///
1927    /// Implementations should assume that `can_run` has already succeeded
1928    /// and focus solely on performing the intended operation.
1929    fn run_service(&self) -> Result<(), Self::Logger>;
1930
1931    /// Hook invoked after successful execution.
1932    ///
1933    /// This method is intended for:
1934    /// - logging,
1935    /// - metrics,
1936    /// - bookkeeping,
1937    /// - or emitting side effects that must only occur on success.
1938    ///
1939    /// The default implementation is a no-op.
1940    fn on_ran_service(_: &Self) {}
1941}