frame_suite/
forks.rs

1// SPDX-License-Identifier: MPL-1.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// ```````````````````````````` FORK-LOCAL UTILITIES `````````````````````````````
14// ===============================================================================
15
16//! Fork-local utilities for pallet offchain workers (OCWs).
17//!
18//! This module does not provide canonical chain selection or consensus.
19//!
20//! Instead, it runs on top of a pallet's OCW execution and maintains a
21//! deterministic local fork graph so the pallet can answer:
22//!
23//! ```ignore
24//! "what was my local state on this branch?"
25//! ```
26//!
27//! A [`Branch`] represents a continuous stream of blocks extending on top
28//! of each other along the same path.
29//!
30//! ```text
31//! A -> B -> C -> D
32//! same branch
33//! ```
34//!
35//! As long as blocks continue as direct children, the same branch is reused
36//! and only the branch head moves forward.
37//!
38//! When a division occurs (a sibling block appears at the same ancestry),
39//! a new fork branch is created.
40//!
41//! ```text
42//! A -> B -> C
43//!         |-- D
44//!         |-- D'
45//! ```
46//!
47//! Here:
48//!
49//! - `D` is the original branch continuation
50//! - `D'` is the new sibling branch
51//! - `A -> B -> C` is the parent branch of both paths
52//!
53//! Each branch carries its own fork-local scope through [`ForkScopes`].
54//!
55//! When a new sibling branch is created, it inherits from the parent branch
56//! using [`Accrete`]:
57//!
58//! ```text
59//! scope(D') = scope(C).accrete()
60//! ```
61//!
62//! This allows each fork path to maintain isolated local state while still
63//! preserving inherited lineage state.
64//!
65//! ## Usage
66//!
67//! Every pallet using this system should begin its OCW execution with
68//! [`ForksHandler::start`]:
69//!
70//! ```ignore
71//! fn offchain_worker(block_number: BlockNumberFor<T>) {
72//!     <Self as ForksHandler<T, MyForkScope>>::start(
73//!         Some("my-pallet"),
74//!         Some(LogFormatter::default()),
75//!         || {
76//!             // pallet-specific OCW logic here
77//!         }
78//!     );
79//! }
80//! ```
81//!
82//! [`ForksHandler::start`] handles:
83//!
84//! - longest-chain extension vs sibling fork creation
85//! - missing branch recovery (during client inactivity)
86//! - safe branch resolution before OCW logic executes
87//!
88//! The OCW closure (main logic) runs only after branch state is
89//! valid and ready to map the fork graph.
90//!
91//! ## Navigation
92//!
93//! Since fork resolution is delayed by one block:
94//!
95//! ```ignore
96//! block N executes
97//! -> block N - 1 is resolved and persisted
98//! ```
99//!
100//! the current executing block is not yet inserted into the local fork graph.
101//!
102//! For normal OCW access, use [`ForksHandler::get_prev_block_branch`]
103//! to retrieve the previous block's (`N - 1`) resolved branch.
104//!
105//! From that branch, navigation can continue using [`ForkAction`] and
106//! [`ForksHandler::transition`], or helpers like:
107//!
108//! - [`ForksHandler::get_block_branch`]
109//! - [`ForksHandler::get_prev_branch`]
110//! - [`ForksHandler::get_branch`]
111//!
112//! This allows movement across:
113//!
114//! - parent branches
115//! - child branches
116//! - sibling branches
117//! - root ancestry
118//!
119//! This provides deterministic branch-local traversal without relying on
120//! canonical consensus routing.
121//!
122//! The system is intentionally fork-aware, scope-first, and best-effort:
123//! it tracks local execution branches, not global consensus finality.
124
125// ===============================================================================
126// ``````````````````````````````````` IMPORTS ```````````````````````````````````
127// ===============================================================================
128
129// --- Local-Crate ---
130use crate::{Accrete, LogFormatter, Logging, Portable};
131
132// --- Scale-codec ---
133use codec::{Decode, Encode};
134
135// --- Rust-core (no-std) ---
136use core::fmt::Debug;
137
138// --- FRAME System ---
139use frame_system::{pallet_prelude::BlockNumberFor, Config, Pallet};
140
141// --- Substrate Primitives ---
142use sp_core::blake2_256;
143use sp_std::vec;
144use sp_runtime::{
145    offchain::storage::{MutateStorageError, StorageValueRef},
146    traits::{One, Saturating, Zero},
147    DispatchError, Vec
148};
149
150// ===============================================================================
151// `````````````````````````````````` CONSTANTS ``````````````````````````````````
152// ===============================================================================
153
154/// Highest known longest-chain head used for fork detection.
155///
156/// If a new block extends past `HEAD_BLOCK`,
157/// it is treated as longest-chain extension.
158///
159/// If another block appears at the same height or lower,
160/// it is treated as a sibling fork.
161///
162/// Sibling fork detection is best-effort:
163///
164/// a lower block may still be the head of its own valid fork,
165/// but it is treated as a sibling branch of the nearest known path.
166///
167/// This intentionally favors fewer branch creations
168/// and reduced storage growth over perfect historical fork reconstruction.
169pub const HEAD_BLOCK: &'static [u8] = b"LOCAL_HEAD_BLOCK";
170
171// ===============================================================================
172// `````````````````````````````````` STRUCTURES `````````````````````````````````
173// ===============================================================================
174
175/// Fork branch details pertaining to a block and the
176/// specialized scope state defined by the pallet/module
177/// for which the local fork graph exists.
178///
179/// Each branch represents the traversed path generation
180/// from its local root.
181///
182/// This root is not necessarily true genesis, but in the
183/// best-case scenario it is the original genesis ancestry.
184///
185/// If the next block is a direct child on top of the same path,
186/// the same branch structure is shared and only the branch head
187/// moves forward.
188///
189/// ```text
190/// Direct child progression:
191///
192/// A -> B -> C -> D
193/// same branch
194///
195/// only:
196/// head = D
197/// ```
198///
199/// If the next block becomes a sibling block, it constitutes
200/// a fork and a new branch is created.
201///
202/// That new branch takes an [`Accrete`] over the previous
203/// scope state so all further state becomes localized
204/// to that fork path.
205///
206/// ```text
207/// Sibling fork:
208///
209/// A -> B -> C
210///         |-- D
211///         |-- D'
212///
213/// D  = original branch
214/// D' = new sibling branch
215///
216/// scope(D') = scope(D).accrete()
217/// ```
218///
219/// This structure also stores enough ancestry details to
220/// manually traverse:
221///
222/// - parent branches
223/// - sibling branches
224/// - nested forks
225///
226/// allowing full local fork graph inspection.
227#[derive(Clone, Debug, Encode, Decode)]
228pub struct Branch<T: Config, S: ForkScopes> {
229    /// Structural parent branch.
230    ///
231    /// `None` for synthetic recovery root branches
232    /// or initial local roots.
233    pub parent: Option<[u8; 32]>,
234
235    /// Latest block height currently owned
236    /// by this branch.
237    pub head: BlockNumberFor<T>,
238
239    /// Pallet-local fork scope carried by
240    /// this branch lineage.
241    pub scope: S,
242
243    /// Stable ancestry root for deterministic
244    /// branch identity.
245    ///
246    /// Usually this is the parent block hash of the
247    /// block where this fork graph started.
248    ///
249    /// Example:
250    ///
251    /// - genesis block start: parent hash = [0; 32]
252    /// - mid-chain fork start: parent hash of that fork root
253    ///
254    /// Shared across all sibling forks created
255    /// from that same branch origin.
256    pub genesis: [u8; 32],
257
258    /// Fork lineage path from genesis.
259    ///
260    /// ```text
261    /// Root:
262    /// A -> B -> C
263    /// counter = []
264    ///
265    /// First sibling fork:
266    /// A -> B -> C
267    ///         |-- C' [0]
268    ///
269    /// Second sibling fork:
270    /// A -> B -> C
271    ///         |-- C'  [0]
272    ///         |-- C'' [1]
273    ///
274    /// Nested fork:
275    /// A -> B -> C
276    ///         |-- C'  [0]
277    ///              |-- D' [0, 0]
278    ///         |-- C'' [1]
279    ///              |-- D' [1, 0]
280    ///              |-- D'' [1, 1]
281    /// ```
282    pub counter: Vec<u32>,
283}
284
285// ===============================================================================
286// ```````````````````````````````````` ENUMS ````````````````````````````````````
287// ===============================================================================
288
289/// Deterministic branch traversal and navigation actions
290/// for moving across the local fork graph.
291#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
292pub enum ForkAction {
293
294    /// Move upward N parent branches.
295    ///
296    /// Before:
297    /// A -> B -> C
298    ///         |-- C'
299    ///             |-- D'
300    ///                 ^
301    ///
302    /// Example:
303    /// MoveToParentBranchBack(2)
304    ///
305    /// After:
306    /// A -> B -> C
307    ///           ^
308    MoveToParentBranchBack(u32),
309
310    /// Move to the direct parent branch.
311    ///
312    /// Before:
313    /// A -> B -> C
314    ///         |-- C'
315    ///             ^
316    ///
317    /// After:
318    /// A -> B -> C
319    ///           ^
320    MoveToParentBranch,
321
322    /// Move forward into the N-th child branch if it exists.
323    ///
324    /// Before:
325    /// A -> B -> C
326    ///         ^
327    ///         |-- C'
328    ///         |-- C''
329    ///
330    /// Example:
331    /// MoveToChildBranch(1)
332    ///
333    /// After:
334    /// A -> B -> C
335    ///         |-- C''
336    ///             ^
337    MoveToChildBranch(u32),
338
339    /// Move forward into the first child branch if it exists.
340    ///
341    /// Before:
342    /// A -> B -> C
343    ///           ^
344    ///         |-- C'
345    ///
346    /// After:
347    /// A -> B -> C
348    ///         |-- C'
349    ///             ^
350    ///
351    /// Deterministic traversal:
352    /// always child index 0.
353    MoveToNextChildBranch,
354
355    /// Move to a specific sibling branch index.
356    ///
357    /// If unavailable, remain on current branch.
358    ///
359    /// Before:
360    /// A -> B -> C
361    ///         |-- D
362    ///         |   ^
363    ///         |-- D'
364    ///
365    /// After:
366    /// A -> B -> C
367    ///         |-- D
368    ///         |-- D'
369    ///             ^
370    MoveToSiblingBranch(u32),
371
372    /// Move to the next sibling branch if it exists.
373    ///
374    /// Before:
375    /// A -> B -> C
376    ///         |-- D
377    ///         |   ^
378    ///         |-- D'
379    ///
380    /// After:
381    /// A -> B -> C
382    ///         |-- D
383    ///         |-- D'
384    ///             ^
385    MoveToNextSiblingBranch,
386
387    /// Move to the previous sibling branch if it exists.
388    ///
389    /// Before:
390    /// A -> B -> C
391    ///         |-- D
392    ///         |-- D'
393    ///             ^
394    ///
395    /// After:
396    /// A -> B -> C
397    ///         |-- D
398    ///         |   ^
399    ///         |-- D'
400    MoveToPreviousSiblingBranch,
401
402    /// Jump to the oldest reachable ancestry root.
403    ///
404    /// This may be true genesis ancestry or a synthetic
405    /// recovery root depending on recovery history.
406    ///
407    /// Before:
408    /// A -> B -> C
409    ///         |-- C' -> D'
410    ///                  ^
411    ///
412    /// After:
413    /// A
414    /// ^
415    MoveToRootBranch,
416
417}
418
419// ===============================================================================
420// ```````````````````````````````````` TRAITS ```````````````````````````````````
421// ===============================================================================
422
423/// A scope is an abstract area for storing branch-local state and anything
424/// logically related to that fork, such as:
425///
426/// - values
427/// - references
428/// - pointers
429/// - indexes
430/// - cached storage views
431/// - execution context
432/// - fork-local metadata
433/// - lineage-dependent runtime state
434///
435/// `ForkScopes` is generational:
436///
437/// - [`Default`] provides the empty first generation
438/// - [`Portable`] provides codec-safe storage and cloning
439/// - [`Accrete`] allows each new branch to inherit and extend scope
440///
441/// When a new fork branch is created, it accretes from its parent branch,
442/// carrying forward previous generations while starting a fresh local layer.
443///
444/// This makes the newest generation the full reachable state, avoiding
445/// repeated traversal of older branch ancestry during inspection.
446pub trait ForkScopes: Portable + Default + Debug + Accrete {}
447
448/// Blanked Implementation for all types that satisfy the trait impls.
449impl<T> ForkScopes for T where T: Portable + Default + Debug + Accrete {}
450
451/// Fork-aware local branch collection framework for pallet/module state.
452///
453/// This trait allows a pallet (or module using OCWs) to maintain its own
454/// deterministic local fork graph independent of chain consensus.
455///
456/// It is tightly coupled to FRAME System and uses:
457///
458/// - current block number
459/// - parent hash
460/// - historical block hashes
461///
462/// to resolve and recover local branch state.
463///
464/// Each implementation defines:
465///
466/// - its own `TAG` (storage namespace)
467/// - its own `ForkScope` (local state tracked per branch)
468///
469/// This lets every pallet answer:
470///
471/// ```ignore
472/// "what was my local state on this branch?"
473/// ```
474///
475/// Useful for:
476///
477/// - OCW-derived state
478/// - local indexing and aggregation
479/// - branch-aware replay
480/// - deterministic recovery after storage loss
481///
482/// ## OCW execution model
483///
484/// Offchain workers should always begin with:
485///
486/// ```ignore
487/// fn offchain_worker(block_number: BlockNumberFor<T>) {
488///     <Self as ForksHandler<T, MyForkScope>>::start(
489///         Some("my-pallet"),
490///         Some(LogFormatter::default()),
491///         || {
492///             // pallet-specific OCW logic here
493///         }
494///     );
495/// }
496/// ```
497///
498/// [`Self::start`] is the only valid entry point.
499///
500/// It handles:
501///
502/// - longest-chain extension vs sibling fork creation
503/// - recovery of missing or corrupted branch state
504/// - conditions where OCW execution should be skipped
505///
506/// The OCW closure executes only after branch resolution
507/// and recovery have completed.
508///
509/// ## Scope safety
510///
511/// Fork scope state is recoverable, but not permanently trusted.
512///
513/// Recovery may recreate synthetic forks and restore only the
514/// minimum valid state required for continued execution,
515/// not exact historical lineage.
516///
517/// Fork recovery guarantees execution continuity,
518/// not perfect reconstruction.
519///
520/// ## Query model
521///
522/// Branch resolution is intentionally delayed by one block.
523///
524/// The current executing block is not inserted into the fork graph
525/// during its own OCW execution.
526///
527/// Instead:
528///
529/// ```ignore
530/// block N OCW executes
531/// -> block N - 1 is resolved and persisted
532/// ```
533///
534/// because the current block hash is not yet safely available
535/// for deterministic fork routing.
536///
537/// This means queries during OCW execution resolve the
538/// previous block's branch by default.
539///
540/// Additional traversal across parent, sibling,
541/// and canonical ancestry is available through
542/// branch access helpers.
543pub trait ForksHandler<T: Config, S: ForkScopes>:
544    Logging<BlockNumberFor<T>, Logger = DispatchError> + Sized
545{
546    /// Storage namespace prefix for all fork-local keys.
547    ///
548    /// Used to isolate multiple fork-graphs with special scopes.
549    const TAG: &[u8];
550
551    /// Maximum sibling forks allowed from a single branch point.
552    ///
553    /// Once exceeded, no additional sibling branch is created
554    /// and [`Self::max_forks`] is triggered.
555    const MAX_FORKS: u32;
556
557    /// Maximum reverse traversal attempts during recovery.
558    ///
559    /// Used when branch resolution fails and the system
560    /// walks backward to find the nearest recoverable branch state.
561    ///
562    /// Prevents unbounded historical scanning.
563    const MAX_RECOVER_TRAVERSAL: u32;
564
565    /// Start fork resolution for the previous block and execute OCW logic
566    /// inside the resolved branch environment.
567    ///
568    /// This is the only valid OCW entry point.
569    ///
570    /// It determines:
571    ///
572    /// - longest-chain extension vs sibling fork creation
573    /// - divider / branch recovery when storage is missing
574    /// - corruption handling for decode failures
575    /// - mutation conflict promotion into sibling forks
576    /// - conditions where OCW execution should be skipped
577    ///
578    /// Resolution is intentionally delayed by one block:
579    ///
580    /// ```ignore
581    /// block N OCW executes
582    /// -> block N - 1 is resolved and persisted
583    /// ```
584    ///
585    /// because the current block hash is not yet safely available
586    /// for deterministic fork routing.
587    ///
588    /// The provided `ocw` closure runs only after:
589    ///
590    /// - branch resolution is complete
591    /// - recovery (if needed) has finished
592    /// - block -> divider -> branch invariants are restored
593    ///
594    /// This guarantees OCW logic executes only inside a valid
595    /// fork-aware branch context.
596    fn start<F: FnOnce()>(
597        target: Option<&str>,
598        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
599        ocw: F,
600    ) { 
601        // Current executing OCW block (block N).
602        //
603        // Fork registration is intentionally delayed by one block,
604        // so this execution resolves and persists: block N - 1
605        //
606        // instead of the currently executing block itself.
607        let block = Pallet::<T>::block_number();
608
609        // Early bootstrap boundary detection.
610        //
611        // At the earliest chain boundary: parent == grand_parent
612        //
613        // because historical hashes are not yet available and
614        // saturating subtraction collapses both values.
615        //
616        // In this state there is not enough ancestry to safely
617        // resolve fork lineage, so execution is skipped.
618        let actual_parent_block = block.saturating_sub(One::one());
619        let actual_grandparent_block = block.saturating_sub(2u8.into());
620
621        if actual_parent_block == actual_grandparent_block {
622            return;
623        }
624
625        // Shift execution target: block N -> resolve block N - 1
626        //
627        // This gives access to:
628        //
629        // - exact current hash of N - 1
630        // - exact parent hash of N - 2
631        //
632        // which removes sibling ambiguity and allows deterministic
633        // branch routing using fully materialized hashes.
634        let block = block.saturating_sub(One::one());
635
636        // Recovery loop.
637        //
638        // Recovery handlers return: Ok(()) => continue
639        // so execution restarts cleanly after repairing storage.
640        //
641        // In practice this usually runs:
642        // - once for normal execution
643        // - twice when recovery is required
644        let _ = loop {
645            // Exact block being inserted into the fork graph.
646            //
647            // Named `current` for branch semantics,
648            // but structurally this is: block N - 1
649            let current = Pallet::<T>::block_hash(block);
650
651            // Parent of the resolved block.
652            //
653            // parent(current) == block N - 2
654            let parent = Pallet::<T>::block_hash(block.saturating_sub(One::one()));
655
656            // Highest known longest-chain boundary.
657            //
658            // Used only for fork detection:
659            //
660            //     block <= head -> sibling fork path
661            //     block >  head -> longest-chain extension
662            //
663            // This is best-effort and intentionally favors:
664            //
665            // - fewer new branches
666            // - lower storage growth
667            //
668            // over perfect historical fork reconstruction.
669            //
670            // (branch a)  (branch a)  (branch a)
671            // A ----------B-----------C
672            //
673            // is same as
674            //                      A (branch a)
675            //                       \
676            //                        B (branch a.a)
677            //                         \
678            //                          C (branch a.b)
679            let head = match Self::get_head() {
680                Some(v) => v,
681                None => {
682                    let initial_head = block.saturating_sub(One::one());
683                    store_encoded([Self::TAG, HEAD_BLOCK].concat(), &initial_head);
684                    initial_head
685                }
686            };
687
688            // Divider lookup: parent -> divider
689            //
690            // Divider is the routing layer between blocks and branches.
691            //
692            // Multiple sequential blocks of the same ancestry:
693            //
694            //     A -> B -> C -> D
695            //
696            // share the same branch structure and local scope lineage,
697            // so they resolve into the same branch and only extend its head.
698            //
699            // OCW scope mutation happens only after branch resolution
700            // and graph persistence complete.
701            //
702            // Under normal execution this behaves like sequential runtime:
703            //
704            // blocks of the same ancestry only build forward on top of
705            // the existing branch, so mutation conflicts are not expected.
706            //
707            // A conflict may still happen if a previous OCW is still running
708            // while the next block begins execution asynchronously.
709            //
710            // In that case mutation is resolved by promoting the later writer
711            // into a sibling branch (clone on mutation conflict),
712            // because execution cannot safely wait or abort without first
713            // preserving deterministic fork graph progression.
714            let divider_hash = Self::get_divider(parent);
715
716            // Missing divider means ancestry routing is broken.
717            //
718            // Recovery restores only the minimum valid scope
719            // required for execution continuity, not exact
720            // historical fork reconstruction.
721            if divider_hash.is_none() {
722                match Self::parent_divider_unavailable(block, target, fmt) {
723                    Ok(_) => continue,
724                    Err(e) => break e,
725                }
726            }   
727            
728            // Full branch resolution: parent -> dividerkey -> branchkey
729            //
730            // Parent's (N-2) Branch Key
731            let branch_hash = Self::get_branch_hash(parent);
732
733            // SIBLING FORK PATH
734            //
735            // Another block already occupied this height: block <= head
736            // so this is treated as a sibling fork.
737            if block <= head {
738                let prev_branch = match branch_hash {
739                    Some(h) => match Self::get_branch(&h) {
740                        Some(b) => b,
741                        
742                        // Divider exists but branch payload is missing.
743                        None => match Self::parent_branch_unavailable(block, target, fmt) {
744                            Ok(_) => continue,
745                            Err(e) => break e,
746                        },
747                    },
748                    
749                    // Divider exists but deeper branch resolution failed.
750                    None => match Self::parent_branch_hash_unavailable(block, target, fmt) {
751                        Ok(_) => continue,
752                        Err(e) => break e,
753                    },
754                };
755
756                // New sibling receives:
757                //
758                // - logically accreted scope
759                // - same ancestry root (genesis) continued
760                // - same lineage path until sibling index append
761                let scope = prev_branch.scope.accrete();
762                let genesis = prev_branch.genesis;
763                let mut counter = prev_branch.counter.clone();
764
765                // Find next available sibling slot:
766                //
767                // [x.0], [x.1], [x.2], ...
768                let mut i = 0u32;
769                let k = loop {
770                    let mut try_counter = counter.clone();
771                    try_counter.push(i);
772
773                    let try_branch_hash = branch_key(Self::TAG, genesis, &try_counter);
774
775                    // First unused deterministic sibling slot found.
776                    if load_value::<Branch<T, S>>(&try_branch_hash).is_none() {
777                        break Some(i);
778                    }
779
780                    i += 1;
781
782                    if i > Self::MAX_FORKS {
783                        break None;
784                    }
785                };
786
787                let Some(new_counter) = k else {
788                    match Self::max_forks(block, target, fmt) {
789                        Ok(_) => continue,
790                        Err(e) => break e,
791                    }
792                };
793                
794                // Append the sibling fork as a new counter.
795                counter.push(new_counter);
796
797                // Permanent deterministic branch identity: genesis + updated lineage counter
798                let new_branch_hash = branch_key(Self::TAG, genesis, &counter);
799
800                let new_branch = Branch::<T, S> {
801                    parent: branch_hash,
802                    head: block,
803                    scope,
804                    genesis,
805                    counter,
806                };
807                store_encoded(&new_branch_hash, &new_branch);
808
809                // Divider identity: parent + branchkey
810                //
811                // allows multiple sibling branches from the same parent without overwrite.
812                let new_divider_hash = divider_key(Self::TAG, parent, new_branch_hash);
813                store_encoded(&new_divider_hash, &new_branch_hash);
814
815                // Final block key-derivation: block -> divider -> branch for N-1 block
816                let block_hash = block_key(Self::TAG, current);
817                store_encoded(&block_hash, &new_divider_hash);
818
819                // Run OCW logic and return
820                ocw();
821                return;
822            }
823
824            // LONGEST-CHAIN EXTENSION PATH
825            //
826            // Normal forward progression of the active branch.
827            let Some(located_branch_hash) = branch_hash else {
828                match Self::parent_branch_hash_unavailable(block, target, fmt) {
829                    Ok(_) => continue,
830                    Err(e) => break e,
831                }
832            };
833
834            // Optimistic mutation:
835            //
836            // mutate existing branch only
837            //
838            // no new branch is created here as its carried forward.
839            let storage_ref = StorageValueRef::persistent(&located_branch_hash);
840            let result = storage_ref.mutate(|result: Result<Option<Branch<T, S>>, _>| {
841                let Ok(maybe) = result else {
842                    // Decode corruption is treated the same as
843                    // missing branch state and enters recovery.
844                    match Self::inherited_branch_decode_error(block, target, fmt) {
845                        Ok(_) => return Err(None),
846                        Err(e) => return Err(Some(e)),
847                    }
848                };
849
850                let mut branch = match maybe {
851                    Some(v) => v,
852
853                    None => match Self::parent_branch_unavailable(block, target, fmt) {
854                        Ok(_) => return Err(None),
855                        Err(e) => return Err(Some(e)),
856                    },
857                };
858
859                // Extend active branch head only.
860                branch.head = block;
861
862                Ok(branch)
863            });
864
865            match result {
866                Ok(_) => {}
867
868                Err(e) => match e {
869                    // Another OCW won the mutation race.
870                    //
871                    // Do not retry mutation.
872                    //
873                    // Promote into a sibling conflict branch
874                    // to preserve deterministic execution.
875                    // Clone on Mutate Conflict
876                    MutateStorageError::ConcurrentModification(_) => {
877                        match Self::inherited_branch_mutation_conflict(block, target, fmt) {
878                            Ok(_) => {
879                                ocw();
880                                return;
881                            }
882                            Err(e) => break e,
883                        }
884                    }
885
886                    MutateStorageError::ValueFunctionFailed(e) => match e {
887                        Some(e) => break e,
888
889                        // Recovery repaired state,
890                        // restart cleanly.
891                        None => continue,
892                    },
893                },
894            }
895
896            // Persist final routing invariant: block -> divider -> branch
897            let block_hash = block_key(Self::TAG, current);
898
899            let Some(divider) = divider_hash else {
900                unreachable!()
901            };
902
903            store_encoded(&block_hash, &divider);
904
905            // Update longest known boundary only for
906            // forward longest-chain progression.
907            store_encoded([Self::TAG, HEAD_BLOCK].concat(), &block);
908
909            // Run OCW logic and return
910            ocw();
911            return;
912        };
913
914        return;
915    }
916
917    /// Returns the highest known longest-chain boundary used for fork detection.
918    ///
919    /// This is local fork-tracking state, not consensus finality.
920    ///
921    /// Used by [`Self::start`] to decide:
922    ///
923    /// ```ignore
924    /// block <= HEAD_BLOCK -> sibling fork path
925    /// block >  HEAD_BLOCK -> longest-chain extension
926    /// ```
927    fn get_head() -> Option<BlockNumberFor<T>> {
928        load_value::<BlockNumberFor<T>>(&[Self::TAG, HEAD_BLOCK].concat())
929    }
930
931    /// Returns the fork-branch key-hash for a persisted block hash.
932    ///
933    /// This should be queried using already finalized block hashes,
934    /// typically the previous block during OCW execution.
935    fn get_branch_hash(hash: T::Hash) -> Option<[u8; 32]> {
936        let divider_hash = Self::get_divider(hash)?;
937        load_value::<[u8; 32]>(&divider_hash)
938    }
939
940    /// Returns the resolved fork-branch data for a persisted block hash.
941    ///
942    /// This should be queried using already finalized block hashes,
943    /// typically the previous block during OCW execution.
944    fn get_block_branch(hash: T::Hash) -> Option<Branch<T, S>> {
945        let branch_hash = Self::get_branch_hash(hash)?;
946        Self::get_branch(&branch_hash)
947    }
948
949    /// Loads a branch directly from its branch hash (key).
950    fn get_branch(branch_hash: &[u8]) -> Option<Branch<T, S>> {
951        load_value::<Branch<T, S>>(branch_hash)
952    }
953
954    /// Returns the structural parent branch of a resolved block.
955    ///
956    /// Useful for manual traversal across fork ancestry.
957    ///
958    /// This should be queried using already finalized block hashes,
959    /// typically the previous block during OCW execution.
960    fn get_prev_branch(hash: T::Hash) -> Option<Branch<T, S>> {
961        let branch = Self::get_block_branch(hash)?;
962        let parent = branch.parent?;
963        Self::get_branch(&parent)
964    }
965
966    fn get_prev_block_branch() -> Option<Branch<T, S>> {
967        let block = Pallet::<T>::block_number();
968        let hash = Pallet::<T>::block_hash(block.saturating_sub(One::one()));
969        Self::get_block_branch(hash)
970    }
971
972    /// Returns the divider for a persisted block hash.
973    ///
974    /// Divider is the routing layer that allows multiple sibling
975    /// branches to coexist from the same parent ancestry.
976    ///
977    /// This should be queried using already finalized block hashes,
978    /// typically the previous block during OCW execution.
979    fn get_divider(hash: T::Hash) -> Option<[u8; 32]> {
980        let hash = block_key(Self::TAG, hash);
981        load_value::<[u8; 32]>(&hash)
982    }
983
984    /// Deterministic traversal across persisted local fork branches.
985    ///
986    /// This moves between already resolved [`Branch`] states created by
987    /// [`ForksHandler::start`] during pallet OCW execution.
988    ///
989    /// Since fork resolution is delayed by one block:
990    ///
991    /// ```ignore
992    /// block N executes
993    /// -> block N - 1 is resolved and persisted
994    /// ```
995    ///
996    /// the current executing block is not yet inserted into the local fork
997    /// graph during its own OCW execution.
998    ///
999    /// For normal OCW access, use [`ForksHandler::get_prev_block_branch`]
1000    /// to retrieve the previous block's (`N - 1`) resolved branch.
1001    ///
1002    /// From that branch, navigation can continue using [`ForkAction`] and
1003    /// [`ForksHandler::transition`], or other helpers such as:
1004    ///
1005    /// - [`ForksHandler::get_block_branch`]
1006    /// - [`ForksHandler::get_prev_branch`]
1007    /// - [`ForksHandler::get_branch`]
1008    ///
1009    /// A branch represents a continuous stream of blocks on the same path:
1010    ///
1011    /// ```text
1012    /// A -> B -> C -> D
1013    /// same branch
1014    /// ```
1015    ///
1016    /// When a division occurs, a new sibling branch is created:
1017    ///
1018    /// ```text
1019    /// A -> B -> C
1020    ///         |-- D
1021    ///         |-- D'
1022    /// ```
1023    ///
1024    /// Here:
1025    ///
1026    /// - `D` is the original branch continuation
1027    /// - `D'` is the new sibling branch
1028    ///
1029    /// The branch that existed before the split (`A -> B -> C`)
1030    /// becomes the parent branch for both paths.
1031    ///
1032    /// A child branch is any branch created from that fork point.
1033    ///
1034    /// Example:
1035    ///
1036    /// ```text
1037    /// parent branch
1038    /// A -> B -> C
1039    ///
1040    /// child branches
1041    ///         |-- D   [0]
1042    ///         |-- D'  [1]
1043    /// ```
1044    ///
1045    /// Nested forks create deeper child branches:
1046    ///
1047    /// ```text
1048    /// A -> B -> C
1049    ///         |-- D'      [0]
1050    ///              |-- E' [0,0]
1051    /// ```
1052    ///
1053    /// This function performs branch navigation, not direct block traversal,
1054    /// so block numbers are not passed here.
1055    ///
1056    /// If block position is needed, it can be inferred from:
1057    ///
1058    /// - the branch [`Branch::head`]
1059    /// - the previously resolved branch head
1060    ///
1061    /// Traversal uses [`ForkAction`] to move between:
1062    ///
1063    /// - parent branches
1064    /// - child branches
1065    /// - sibling branches
1066    /// - root ancestry
1067    ///
1068    /// Returns `Some(branch)` if the target exists,
1069    /// otherwise `None`.
1070    fn transition(
1071        branch: &Branch<T, S>,
1072        action: ForkAction,
1073    ) -> Option<Branch<T, S>> {
1074        match action {
1075 
1076            ForkAction::MoveToParentBranch => {
1077                let parent_key = branch.parent?;
1078                let parent_branch = load_value::<Branch<T, S>>(&parent_key)?;
1079                Some(parent_branch)
1080            },
1081 
1082            ForkAction::MoveToParentBranchBack(n) => {
1083                if n.is_zero() {
1084                    return Some(branch.clone());
1085                }
1086                let mut current_branch = branch.clone();
1087                for _ in 0..n {
1088                    let next =
1089                        Self::transition(&current_branch, ForkAction::MoveToParentBranch)?;
1090                    current_branch = next;
1091                }
1092                Some(current_branch)
1093            },
1094  
1095
1096            ForkAction::MoveToChildBranch(index) => {
1097                let mut child_counter = branch.counter.clone();
1098                child_counter.push(index);
1099 
1100                // branch_key is now called with Self::TAG so the key matches
1101                // exactly what start() stored - the bug in the old Branch impl
1102                // was that it omitted the tag entirely.
1103                let child_key = branch_key(Self::TAG, branch.genesis, &child_counter);
1104                let child_branch = load_value::<Branch<T, S>>(&child_key)?;
1105                Some(child_branch)
1106            },
1107
1108            ForkAction::MoveToNextChildBranch => {
1109                Self::transition(branch, ForkAction::MoveToChildBranch(0))
1110            },
1111 
1112  
1113            ForkAction::MoveToSiblingBranch(index) => {
1114                let sibling_counter = if branch.counter.is_empty() {
1115                    // Root branch - children/siblings live at counter [index].
1116                    vec![index]
1117                } else {
1118                    // Replace last element with the target index.
1119                    let mut c = branch.counter.clone();
1120                    *c.last_mut()? = index;
1121                    c
1122                };
1123 
1124                // Bail if the computed counter is identical to the current one
1125                // (caller asked to move to the branch they are already on).
1126                if sibling_counter == branch.counter {
1127                    return None;
1128                }
1129 
1130                let sibling_key = branch_key(Self::TAG, branch.genesis, &sibling_counter);
1131                let sibling_branch = load_value::<Branch<T, S>>(&sibling_key)?;
1132                Some(sibling_branch)
1133            },
1134 
1135            ForkAction::MoveToNextSiblingBranch => {
1136                let next_index = branch.counter.last().map(|k| k.saturating_add(One::one())).unwrap_or(0);
1137                Self::transition(branch, ForkAction::MoveToSiblingBranch(next_index))
1138            },
1139 
1140            ForkAction::MoveToPreviousSiblingBranch => {
1141                let last = *branch.counter.last()?;
1142                if last.is_zero() {
1143                    return None;
1144                }
1145                Self::transition(branch, ForkAction::MoveToSiblingBranch(last.saturating_sub(One::one())))
1146            },
1147
1148            ForkAction::MoveToRootBranch => {
1149                let mut current_branch = branch.clone();
1150                loop {
1151                    if current_branch.parent.is_none() {
1152                        return Some(current_branch);
1153                    }
1154                    match Self::transition(&current_branch, ForkAction::MoveToParentBranch) {
1155                        Some(parent) => {
1156                            current_branch = parent;
1157                        },
1158                        // Parent key was set but branch payload is missing from
1159                        // storage - return the last successfully loaded branch.
1160                        None => return Some(current_branch),
1161                    }
1162                }
1163            },
1164        }
1165    }
1166
1167    /// Derives a 32-byte scope key for a given scope item.
1168    ///
1169    /// Delegates to [`Accrete::make_key`] which produces a stable, content-addressed
1170    /// key from the item. 
1171    /// 
1172    /// The same item always produces the same key regardless
1173    /// of the block or fork it is called from, making scope keys fork-independent.
1174    fn gen_scope_item_key(
1175        item: &S::Item,
1176    ) -> [u8; 32] {
1177        S::make_key(item)
1178    }
1179
1180    /// Returns `true` if the given scope key exists in the current fork's branch.
1181    /// 
1182    /// Resolves the branch for `block - 1` via [`Self::get_prev_block_branch`]
1183    /// and checks both the **local** scope (items written on this exact branch)
1184    /// and the **inherited** scope (items promoted from ancestor branches via
1185    /// `accrete()`).
1186    /// 
1187    /// Returns `Err(OCWForksNotEnabled)` if no branch exists for the previous block, 
1188    /// which indicates the fork graph has not been initialized via `ForksHandler::start`.
1189    fn scope_item_exists(   
1190        key: &[u8; 32],
1191        target: Option<&str>,
1192        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1193    ) -> Result<bool, Self::Logger> {
1194        let Some(branch) = Self::get_prev_block_branch() else {
1195            return Err(<Self as Logging<BlockNumberFor<T>>>::error(
1196                &Self::forks_not_enabled(),
1197                Pallet::<T>::block_number(),
1198                target,
1199                fmt,
1200            ));
1201        };
1202
1203        if branch.scope.exists_in_local(&key) {
1204            return Ok(true);
1205        }
1206
1207        if branch.scope.exists_in_inherited(&key) {
1208            return Ok(true);
1209        }
1210
1211        Ok(false)
1212    }
1213
1214    /// Registers a scope item in the **local** scope of the current branch.
1215    ///
1216    /// Resolves the branch for `block - 1` using `block_hash(block - 1)` as
1217    /// the lookup key. 
1218    /// 
1219    /// The item is added to `branch.scope.local_keys` so it is visible to 
1220    /// [`Self::scope_item_exists`] on the same branch and propagates into 
1221    /// `inherited_keys` of any child branch created via `accrete()` during
1222    /// the next `ForksHandler::start` call.
1223    ///
1224    /// Returns the 32-byte scope key assigned to the item.
1225    ///
1226    /// Returns:
1227    /// - `Err(OCWForksNotEnabled)` if `block_hash(block - 1)` has no
1228    /// corresponding branch entry, meaning `ForksHandler::start` has not yet
1229    /// run at the current block.
1230    /// - `Err(OCWForksInconsistent)` if the branch hash resolves
1231    /// but the branch itself cannot be loaded.
1232    fn add_to_scope(
1233        item: S::Item,
1234        target: Option<&str>,
1235        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1236    ) -> Result<[u8; 32], Self::Logger> {
1237        let block = Pallet::<T>::block_number()
1238            .saturating_sub(One::one());
1239
1240        let hash = Pallet::<T>::block_hash(block);
1241
1242        let Some(branch_hash) = Self::get_branch_hash(hash) else {
1243            return Err(<Self as Logging<BlockNumberFor<T>>>::error(
1244                &Self::forks_not_enabled(),
1245                Pallet::<T>::block_number(),
1246                target,
1247                fmt,
1248            ));
1249        };
1250
1251        let Some(mut branch) = Self::get_branch(&branch_hash) else {
1252            return Err(<Self as Logging<BlockNumberFor<T>>>::error(
1253                &Self::inconsistent_forks(),
1254                Pallet::<T>::block_number(),
1255                target,
1256                fmt,
1257            ));
1258        };
1259
1260        let key = branch.scope.add_to_local(item);
1261
1262        store_encoded(&branch_hash, &branch);
1263
1264        Ok(key)
1265    }
1266
1267    /// Removes a scope item from the current branch's local or inherited scope.
1268    ///
1269    /// Resolves the branch for `block - 1` and removes the key from whichever
1270    /// scope layer it occupies:
1271    ///
1272    /// - If the key is in `local_keys`, it is removed directly and the branch
1273    ///   is persisted.
1274    /// - If the key is in `inherited_keys`, it is removed from the inherited
1275    ///   layer and the branch is persisted.
1276    /// - If the key is in neither layer, the call is a no-op and returns `Ok(())`.
1277    ///
1278    /// Returns:
1279    /// - `Err(OCWForksNotEnabled)` if the branch cannot be resolved.
1280    /// - `Err(OCWForksInconsistent)` if the branch hash exists but the
1281    /// branch itself cannot be loaded.
1282    fn remove_from_scope(
1283        key: &[u8; 32],
1284        target: Option<&str>,
1285        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1286    ) -> Result<(), Self::Logger> {
1287        let block = Pallet::<T>::block_number()
1288            .saturating_sub(One::one());
1289
1290        let hash = Pallet::<T>::block_hash(block);
1291
1292        let Some(branch_hash) = Self::get_branch_hash(hash) else {
1293            return Err(<Self as Logging<BlockNumberFor<T>>>::error(
1294                &Self::forks_not_enabled(),
1295                Pallet::<T>::block_number(),
1296                target,
1297                fmt,
1298            ));
1299        };
1300
1301        let Some(mut branch) = Self::get_prev_block_branch() else {
1302            return Err(<Self as Logging<BlockNumberFor<T>>>::error(
1303                &Self::inconsistent_forks(),
1304                Pallet::<T>::block_number(),
1305                target,
1306                fmt,
1307            ));
1308        };
1309
1310        if branch.scope.exists_in_local(&key) {
1311            branch.scope.remove_from_local(&key);
1312
1313            store_encoded(&branch_hash, &branch);
1314
1315            return Ok(());
1316        }
1317
1318        if !branch.scope.exists_in_inherited(&key) {
1319            return Ok(());
1320        }
1321
1322        branch.scope.remove_from_inherited(&key);
1323
1324        store_encoded(&branch_hash, &branch);
1325
1326        Ok(())
1327    }
1328
1329    /// Returns the error used when fork-aware storage is accessed before
1330    /// `ForksHandler::start` has initialized the fork graph.
1331    fn forks_not_enabled() -> DispatchError;
1332
1333    /// Returns the error used when the fork graph is in an inconsistent state.
1334    fn inconsistent_forks() -> DispatchError;
1335
1336    /// Recovery path when a target block's parent block
1337    /// does not have a resolvable branch available.
1338    ///
1339    /// The target block is usually (N-1) and parent (N-2)
1340    ///
1341    /// Storage corruption may permanently lose the parent's
1342    /// local fork scope for that generation, which cannot be
1343    /// reconstructed from chain history alone.
1344    ///
1345    /// Recovery walks backward to the nearest recoverable branch
1346    /// and restores only the minimum valid scope required for
1347    /// execution continuity.
1348    ///
1349    /// This is intentionally scope-first, not lineage-first:
1350    /// synthetic recovery branches may be created instead of
1351    /// exact historical fork reconstruction.
1352    fn parent_branch_hash_unavailable(
1353        block: BlockNumberFor<T>,
1354        _target: Option<&str>,
1355        _fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1356    ) -> Result<(), Self::Logger> {
1357        // Start recovery from: block - 2
1358        //
1359        // because the missing branch belongs to: parent(block)
1360        //
1361        // and we must search older ancestry for the nearest
1362        // recoverable branch state.
1363        let mut recoverer = block.saturating_sub(2u8.into());
1364
1365        let mut recovered = None;
1366
1367        // Prevent unbounded historical scanning.
1368        let mut attempts = 0u32;
1369
1370        loop {
1371            // Hard recovery bound reached.
1372            if attempts >= Self::MAX_RECOVER_TRAVERSAL {
1373                break;
1374            }
1375
1376            // Genesis underflow boundary.
1377            //
1378            // Normally unreachable because genesis-adjacent blocks
1379            // are skipped during regular execution of start().
1380            //
1381            // Recovery still handles this path explicitly so synthetic
1382            // branches can be created for those skipped genesis ranges also.
1383            if recoverer.is_zero() {
1384                break;
1385            }
1386
1387            // Try resolving: recover_via -> divider -> branch
1388            //
1389            // for an older known block.
1390            let recover_via = Pallet::<T>::block_hash(recoverer.saturating_sub(One::one()));
1391
1392            // First valid recoverable branch found.
1393            if let Some(branch) = Self::get_block_branch(recover_via) {
1394                recovered = Some(branch);
1395                break;
1396            }
1397
1398            // Continue walking backward.
1399            recoverer = recoverer.saturating_sub(One::one());
1400            attempts += 1;
1401        }
1402
1403        let scope = match recovered {
1404            // Valid older branch found.
1405            //
1406            // Recovery continues from its accreted scope.
1407            //
1408            // Any local scope that originally belonged to the
1409            // missing branch being recovered is permanently lost
1410            // and cannot be reconstructed from chain history.
1411            //
1412            // We therefore continue from the nearest valid
1413            // recoverable ancestor scope instead.
1414            Some(branch) => branch.scope.accrete(),
1415
1416            // No recoverable branch exists.
1417            //
1418            // Create a synthetic local branches so execution
1419            // can continue safely.
1420            //
1421            // Example:
1422            //
1423            // Real history (lost):
1424            //
1425            // A -> B -> C -> D
1426            //
1427            // After corruption:
1428            //
1429            // A -> ? -> ? -> D
1430            //
1431            // Recovery:
1432            //
1433            // A -> B
1434            //
1435            // C*   D*
1436            //
1437            // where:
1438            //
1439            // * = synthetic recovery branches
1440            //
1441            // Exact lineage is unknown, so recovery restores
1442            // independent best-case scope accreted roots instead of inventing
1443            // unverifiable ancestry.
1444            None => {
1445                // This path does not recover the full lineage because:
1446                //
1447                // - no earlier recoverable branch exists, or
1448                // - MAX_RECOVER_TRAVERSAL bound was reached, or
1449                // - block traveral underflowed, indicating genesis blocks for recovery
1450                //
1451                // In that case only the immediate parent of the
1452                // target block is recovered as a synthetic root branch
1453                // with an empty local scope.
1454
1455                let parent_block = block.saturating_sub(One::one());
1456                // Missing parent block being reconstructed.
1457                let parent = Pallet::<T>::block_hash(parent_block);
1458
1459                // Used only as deterministic synthetic root anchor.
1460                let grand_parent = Pallet::<T>::block_hash(block.saturating_sub(2u8.into()));
1461
1462                // Recovery starts from empty local scope.
1463                //
1464                // Exact historical lineage cannot be proven,
1465                // so we do not attempt full lineage reconstruction.
1466                //
1467                // The synthetic root is anchored at the recovery
1468                // block's parent ancestry:
1469                //
1470                //     target block = block
1471                //     parent       = block - 1 (recover)
1472                //     grand_parent = block - 2
1473                //
1474                // Since we are recovering the missing parent branch,
1475                // genesis is derived from the parent's parent
1476                // (`grand_parent`) as the deterministic recovery root.
1477                let (scope, genesis) = (
1478                    S::default(),
1479                    grand_parent.encode().using_encoded(blake2_256),
1480                );
1481
1482                let branch = Branch::<T, S> {
1483                    parent: None,
1484                    head: parent_block,
1485                    scope,
1486                    genesis,
1487                    counter: Vec::new(),
1488                };
1489
1490                // Synthetic independent recovery root.
1491                let branch_hash = branch_key(Self::TAG, genesis, &[]);
1492
1493                store_encoded(&branch_hash, &branch);
1494
1495                // Restore: parent -> divider -> branch
1496                let divider_hash = divider_key(Self::TAG, parent, branch_hash);
1497
1498                store_encoded(&divider_hash, &branch_hash);
1499
1500                let block_hash = block_key(Self::TAG, parent);
1501
1502                store_encoded(&block_hash, &divider_hash);
1503
1504                return Ok(());
1505            }
1506        };
1507
1508        // Forward rebuild begins immediately after
1509        // the last recoverable point.
1510        let mut target = recoverer.saturating_add(One::one());
1511        let mut branchkey = None;
1512
1513        while target < block {
1514            // Block being synthetically restored.
1515            let current = Pallet::<T>::block_hash(target);
1516
1517            let parent = Pallet::<T>::block_hash(target.saturating_sub(One::one()));
1518
1519            let branch_hash = match branchkey {
1520                Some(h) => h,
1521                None => {
1522                    // Each recovered step is treated as an
1523                    // independent synthetic scope branch.
1524                    //
1525                    // This is intentionally scope-first recovery.
1526                    //
1527                    // Any original local scope that belonged to these
1528                    // historical blocks, if it once existed locally,
1529                    // is permanently lost and cannot be reconstructed.
1530                    //
1531                    // Recovery restores only execution continuity,
1532                    // not the exact historical fork-local state.
1533
1534                    let genesis = parent.encode().using_encoded(blake2_256);
1535
1536                    let branch = Branch::<T, S> {
1537                        parent: Self::get_branch_hash(Pallet::<T>::block_hash(recoverer.saturating_sub(One::one()))),
1538                        head: target,
1539                        scope: scope.clone(),
1540                        genesis,
1541                        counter: Vec::new(),
1542                    };
1543
1544                    let key = branch_key(Self::TAG, genesis, &[]);
1545
1546                    store_encoded(&key, &branch);
1547
1548                    branchkey = Some(key);
1549
1550                    key
1551                }
1552            };
1553
1554            // Restore routing invariant: block -> divider -> branch
1555            let divider_hash = divider_key(Self::TAG, parent, branch_hash);
1556
1557            store_encoded(&divider_hash, &branch_hash);
1558
1559            let block_hash = block_key(Self::TAG, current);
1560
1561            store_encoded(&block_hash, &divider_hash);
1562
1563            target = target.saturating_add(One::one());
1564        }
1565        
1566        Ok(())
1567    }
1568
1569    /// Recovery path when a divider exists for a target block's (N-1)
1570    /// parent (N-2) but the resolved branch data is missing.
1571    ///
1572    /// The stale divider is cleared first, then recovery
1573    /// falls back to [`Self::parent_branch_hash_unavailable`]
1574    /// to rebuild the minimum valid branch state.
1575    fn parent_branch_unavailable(
1576        block: BlockNumberFor<T>,
1577        target: Option<&str>,
1578        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1579    ) -> Result<(), Self::Logger> {
1580        // To Resolve: parent -> divider -> branch
1581        let parent = Pallet::<T>::block_hash(block.saturating_sub(1u8.into()));
1582
1583        // Divider still exists, so ancestry routing is present.
1584        //
1585        // Only the actual branch payload is missing.
1586        let divider_hash = match Self::get_divider(parent) {
1587            Some(v) => v,
1588
1589            // Divider is also missing.
1590            //
1591            // This is no longer a branch-only failure and must
1592            // fall back to full ancestry recovery.
1593            None => {
1594                return Self::parent_branch_hash_unavailable(block, target, fmt);
1595            }
1596        };
1597
1598        // Divider points to invalid / missing branch state.
1599        //
1600        // Clear stale routing first so recovery can rebuild:
1601        //
1602        //      block -> divider -> branch
1603        //
1604        // cleanly without reusing corrupted ancestry.
1605        let mut divider_ref = StorageValueRef::persistent(&divider_hash);
1606
1607        divider_ref.clear();
1608
1609        // Delegate to normal branch recovery.
1610        Self::parent_branch_hash_unavailable(block, target, fmt)
1611    }
1612
1613    /// Recovery path when optimistic branch mutation fails due to
1614    /// concurrent OCW modification.
1615    ///
1616    /// Unlike other recovery paths, this handles the target block (N-1)
1617    /// itself, not its missing parent (N-2) ancestry. It does not return
1618    /// control to [`Self::start`] for retry, because no parent recovery
1619    /// is needed.
1620    ///
1621    /// Instead, it directly performs branch update for the target
1622    /// block by cloning the conflicting structure - the inherited
1623    /// branch from parent into a new sibling branch.
1624    ///
1625    /// The conflicting writer keeps the original branch,
1626    /// while the later writer continues on a cloned sibling fork.
1627    ///
1628    /// This preserves deterministic execution without retrying
1629    /// mutation on already committed branch state.
1630    fn inherited_branch_mutation_conflict(
1631        block: BlockNumberFor<T>,
1632        target: Option<&str>,
1633        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1634    ) -> Result<(), Self::Logger> {
1635        // Current block being persisted.
1636        let current = Pallet::<T>::block_hash(block);
1637
1638        // Parent of the target block.
1639        // Used to resolve: parent -> divider -> branch(parent)
1640        //
1641        // because the conflict belongs to the parent branch lineage.
1642        let parent = Pallet::<T>::block_hash(block.saturating_sub(One::one()));
1643
1644        // Locate the existing branch that won the mutation race.
1645        let branch_hash = match Self::get_branch_hash(parent) {
1646            Some(v) => v,
1647
1648            // Parent ancestry is already broken.
1649            None => {
1650                return Self::parent_branch_hash_unavailable(block, target, fmt);
1651            }
1652        };
1653
1654        let prev_branch = match Self::get_branch(&branch_hash) {
1655            Some(v) => v,
1656
1657            // Divider exists but branch payload is missing.
1658            None => {
1659                return Self::parent_branch_unavailable(block, target, fmt);
1660            }
1661        };
1662
1663        // Clone logical scope from the already-existing branch.
1664        //
1665        // Conflict resolution becomes:
1666        //
1667        // existing branch => sibling branch
1668        let scope = prev_branch.scope.accrete();
1669        let genesis = prev_branch.genesis;
1670        let mut counter = prev_branch.counter.clone();
1671
1672        // Find the next deterministic sibling slot.
1673        //
1674        // Since mutation already happened on the original branch,
1675        // we must force this execution into a sibling branch.
1676        //
1677        // Reusing the same branch would overwrite already
1678        // committed branch state.
1679        //
1680        // Example:
1681        //
1682        // Original:
1683        //
1684        // A -> B -> C -> D
1685        //
1686        // where:
1687        //
1688        // A starts the branch lineage
1689        //
1690        // If C and D mutate concurrently:
1691        //
1692        // writer 1 -> keeps original branch
1693        // writer 2 -> mutation conflict
1694        //
1695        // Recovery becomes:
1696        //
1697        // A -> B -> C
1698        //         |-- C' -> D
1699        //
1700        // We effectively abandon continuation on the original
1701        // branch and create a cloned sibling fork from the
1702        // last safe branch point.
1703        //
1704        // The cloned branch keeps:
1705        //
1706        // - same scope lineage
1707        // - same genesis
1708        //
1709        // and only receives a new sibling counter:
1710        //
1711        // [0], [1], [2], ...
1712        let mut i = 0u32;
1713
1714        let next_counter = loop {
1715            let mut try_counter = counter.clone();
1716            try_counter.push(i);
1717
1718            let try_branch_hash = branch_key(Self::TAG, genesis, &try_counter);
1719
1720            // First empty sibling slot found.
1721            if load_value::<Branch<T, S>>(&try_branch_hash).is_none() {
1722                break Some(i);
1723            }
1724
1725            i += 1;
1726
1727            if i > Self::MAX_FORKS {
1728                break None;
1729            }
1730        };
1731
1732        let Some(new_counter) = next_counter else {
1733            return Self::max_forks(block, target, fmt);
1734        };
1735
1736        counter.push(new_counter);
1737
1738        // New deterministic sibling branch identity.
1739        let new_branch_hash = branch_key(Self::TAG, genesis, &counter);
1740
1741        let new_branch = Branch::<T, S> {
1742            parent: Some(branch_hash),
1743            head: block,
1744            scope,
1745            genesis,
1746            counter,
1747        };
1748
1749        store_encoded(&new_branch_hash, &new_branch);
1750
1751        // New sibling divider: parent + branch
1752        let divider_hash = divider_key(Self::TAG, parent, new_branch_hash);
1753
1754        store_encoded(&divider_hash, &new_branch_hash);
1755
1756        // Final resolution: block -> divider -> branch
1757        let block_hash = block_key(Self::TAG, current);
1758
1759        store_encoded(&block_hash, &divider_hash);
1760
1761        // Conflict branch becomes the new reachable head.
1762        store_encoded([Self::TAG, HEAD_BLOCK].concat(), &block);
1763
1764        Ok(())
1765    }
1766
1767    /// Recovery path when divider routing is missing for the
1768    /// target block's (N-1) parent (N-2).
1769    ///
1770    /// Since divider loss breaks ancestry routing entirely,
1771    /// recovery falls back directly to
1772    /// [`Self::parent_branch_hash_unavailable`].
1773    fn parent_divider_unavailable(
1774        block: BlockNumberFor<T>,
1775        target: Option<&str>,
1776        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1777    ) -> Result<(), Self::Logger> {
1778        Self::parent_branch_hash_unavailable(block, target, fmt)
1779    }
1780
1781    /// Recovery path when branch decoding fails for the
1782    /// target block's (N-1) inherited branch from parent (N-2)
1783    /// for extension.
1784    ///
1785    /// This means the branch exists in storage,
1786    /// but its payload is corrupted or unreadable.
1787    ///
1788    /// It is treated the same as a missing branch and
1789    /// delegated to [`Self::parent_branch_unavailable`].
1790    fn inherited_branch_decode_error(
1791        block: BlockNumberFor<T>,
1792        target: Option<&str>,
1793        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1794    ) -> Result<(), Self::Logger> {
1795        Self::parent_branch_unavailable(block, target, fmt)
1796    }
1797
1798    /// Triggered when no additional sibling branch slot
1799    /// can be allocated under the configured limit as the sibling
1800    /// of the target block's (N-1) parent (N-2).
1801    ///
1802    /// This occurs when:
1803    ///
1804    /// ```ignore
1805    /// sibling_count > MAX_FORKS
1806    /// ```
1807    ///
1808    /// and branch creation must stop.
1809    fn max_forks(
1810        block: BlockNumberFor<T>,
1811        target: Option<&str>,
1812        fmt: Option<LogFormatter<BlockNumberFor<T>, Self::Level>>,
1813    ) -> Result<(), Self::Logger> {
1814        Err(<Self as Logging<BlockNumberFor<T>>>::error(
1815            &Self::max_forks_error(),
1816            block,
1817            target,
1818            fmt,
1819        ))
1820    }
1821
1822    /// Error returned when fork creation exceeds
1823    /// [`Self::MAX_FORKS`].
1824    fn max_forks_error() -> DispatchError;
1825
1826}
1827
1828// ===============================================================================
1829// `````````````````````````````` PRIVATE UTILITIES ``````````````````````````````
1830// ===============================================================================
1831
1832/// Deterministic storage hash builder.
1833///
1834/// Used for all Persistent Node-Local storage keys.
1835fn make_hash(tag: &[u8], input: impl Encode, suffix: &[u8]) -> [u8; 32] {
1836    let mut source = tag.encode();
1837    source.extend_from_slice(&input.encode());
1838    source.extend_from_slice(suffix);
1839    blake2_256(&source)
1840}
1841
1842/// Persist an encoded value into Persistent Node-Local storage.
1843fn store_encoded<K: AsRef<[u8]>, V: Encode>(key: K, value: &V) {
1844    let storage_ref = StorageValueRef::persistent(key.as_ref());
1845    storage_ref.set(&value);
1846}
1847
1848/// Load and decode a value from Persistent Node-Local storage.
1849fn load_value<V: codec::Decode>(key: &[u8]) -> Option<V> {
1850    let storage_ref = StorageValueRef::persistent(key);
1851    let Ok(result) = storage_ref.get::<V>() else {
1852        return None;
1853    };
1854    result
1855}
1856
1857/// Deterministic branch identity key
1858///
1859/// ```ignore
1860/// genesis + counter lineage -> branchkey
1861/// ```
1862fn branch_key(tag: &[u8], genesis: [u8; 32], counter: &[u32]) -> [u8; 32] {
1863    let mut identity = genesis.encode();
1864
1865    for c in counter {
1866        identity.extend_from_slice(&c.encode());
1867    }
1868
1869    make_hash(tag, &identity, b"branch")
1870}
1871
1872/// Divider identity key
1873///
1874/// ```ignore
1875/// parent + branch -> divider
1876/// ```
1877///
1878/// Allows sibling branches from the same parent.
1879fn divider_key(tag: &[u8], hash: impl Encode, branch_key: [u8; 32]) -> [u8; 32] {
1880    let mut identity = hash.encode();
1881    identity.extend_from_slice(&branch_key.encode());
1882
1883    make_hash(tag, &identity, b"divider")
1884}
1885
1886/// Block routing identity key
1887///
1888/// ```ignore
1889/// block -> divider
1890/// ```
1891fn block_key(tag: &[u8], hash: impl Encode) -> [u8; 32] {
1892    let identity = hash.encode();
1893    make_hash(tag, &identity, b"block")
1894}
1895
1896
1897// ===============================================================================
1898// `````````````````````````````````` UNIT TESTS `````````````````````````````````
1899// ===============================================================================
1900
1901#[cfg(test)]
1902mod tests {
1903        
1904    // -------------------------------------------------------------------------
1905    // ```````````````````````````````` IMPORTS ````````````````````````````````
1906    // -------------------------------------------------------------------------
1907    use super::*;
1908
1909    // --- FRAME Support ---
1910    use frame_support::derive_impl;
1911
1912    // --- FRAME System --- 
1913    use frame_system::pallet_prelude::BlockNumberFor;
1914
1915    // --- Substrate crates ---
1916    use sp_core::offchain::{
1917        testing::{TestOffchainExt, TestTransactionPoolExt},
1918        OffchainDbExt, OffchainWorkerExt, TransactionPoolExt,
1919    };
1920    use sp_io::TestExternalities;
1921    use sp_runtime::{
1922        offchain::storage::StorageValueRef,
1923        traits::{BlakeTwo256, Hash},
1924        AccountId32, BuildStorage, DispatchError,
1925    };
1926
1927    // -------------------------------------------------------------------------
1928    // `````````````````````````````` MOCK RUNTIME `````````````````````````````
1929    // -------------------------------------------------------------------------
1930
1931    pub type Block = frame_system::mocking::MockBlock<Test>;
1932
1933    #[frame_support::runtime]
1934    pub mod runtime {
1935        #[runtime::runtime]
1936        #[runtime::derive(
1937            RuntimeCall,
1938            RuntimeEvent,
1939            RuntimeError,
1940            RuntimeOrigin,
1941            RuntimeFreezeReason,
1942            RuntimeHoldReason,
1943            RuntimeSlashReason,
1944            RuntimeLockId,
1945            RuntimeTask,
1946            RuntimeViewFunction
1947        )]
1948        pub struct Test;
1949
1950        #[runtime::pallet_index(0)]
1951        pub type System = frame_system::Pallet<Test>;
1952    }
1953
1954    #[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
1955    impl frame_system::Config for Test {
1956        type Block = Block;
1957        type AccountId = AccountId32;
1958        type Lookup = sp_runtime::traits::IdentityLookup<Self::AccountId>;
1959    }
1960
1961    // -------------------------------------------------------------------------
1962    // `````````````````````````` OCW TEST ENVIRONMENT `````````````````````````
1963    // -------------------------------------------------------------------------
1964
1965    fn new_ocw_ext() -> TestExternalities {
1966        let storage = frame_system::GenesisConfig::<Test>::default()
1967            .build_storage()
1968            .unwrap();
1969
1970        let mut ext = TestExternalities::new(storage);
1971        ext.execute_with(|| System::set_block_number(1u64));
1972
1973        let (offchain, _state) = TestOffchainExt::new();
1974        ext.register_extension(OffchainWorkerExt::new(offchain.clone()));
1975        ext.register_extension(OffchainDbExt::new(offchain));
1976
1977        let (pool, _) = TestTransactionPoolExt::new();
1978        ext.register_extension(TransactionPoolExt::new(pool));
1979
1980        ext
1981    }
1982
1983    // -------------------------------------------------------------------------
1984    // `````````````````````````` MOCK IMPL FORKSCOPES `````````````````````````
1985    // -------------------------------------------------------------------------
1986
1987    // A minimal scope implementation that actually tracks local and inherited
1988    // keys
1989    #[derive(Clone, Debug, Default, Encode, Decode)]
1990    struct TestScope {
1991        local: std::collections::BTreeSet<[u8; 32]>,
1992        inherited: std::collections::BTreeSet<[u8; 32]>,
1993    }
1994
1995    impl Accrete for TestScope {
1996        type Item = Vec<u8>;
1997
1998        fn accrete(&self) -> Self {
1999            let mut inh = self.inherited.clone();
2000            inh.extend(self.local.iter().copied());
2001            Self { local: std::collections::BTreeSet::new(), inherited: inh }
2002        }
2003
2004        fn inherited(&self) -> Vec<[u8; 32]> { self.inherited.iter().copied().collect() }
2005        fn local(&self) -> Vec<[u8; 32]>     { self.local.iter().copied().collect() }
2006
2007        fn add_to_local(&mut self, item: Self::Item) -> [u8; 32] {
2008            let key = Self::make_key(&item);
2009            self.local.insert(key);
2010            key
2011        }
2012
2013        fn exists_in_local(&self, key: &[u8; 32]) -> bool { self.local.contains(key) }
2014        fn exists_in_inherited(&self, key: &[u8; 32]) -> bool { self.inherited.contains(key) }
2015        fn remove_from_local(&mut self, key: &[u8; 32]) { self.local.remove(key); }
2016        fn remove_from_inherited(&mut self, key: &[u8; 32]) { self.inherited.remove(key); }
2017    }
2018
2019    // -------------------------------------------------------------------------
2020    // ```````````````````````````````` CONSTANTS ``````````````````````````````
2021    // -------------------------------------------------------------------------
2022
2023    const TAG: &[u8] = b"test_forks";
2024
2025    // -------------------------------------------------------------------------
2026    // ```````````````````````` MOCK IMPL FORKS-HANDLER ````````````````````````
2027    // -------------------------------------------------------------------------
2028
2029    struct TestForks;
2030
2031    impl ForksHandler<Test, TestScope> for TestForks {
2032        const TAG: &[u8] = b"test_forks";
2033        const MAX_FORKS: u32 = 3;
2034        const MAX_RECOVER_TRAVERSAL: u32 = 10;
2035
2036        fn max_forks_error() -> DispatchError {
2037            DispatchError::Other("max_forks_exceeded")
2038        }
2039
2040        fn forks_not_enabled() -> DispatchError {
2041            DispatchError::Other("forks-not-enabled")
2042        }
2043        
2044        fn inconsistent_forks() -> DispatchError {
2045            DispatchError::Other("inconsistent-forks")
2046        }
2047    }
2048 
2049    // -------------------------------------------------------------------------
2050    // ```````````````````````````````` HELPERS ````````````````````````````````
2051    // -------------------------------------------------------------------------
2052
2053    /// Returns a deterministic non-zero mock hash for block `n`.
2054    fn mock_hash(n: u64) -> <Test as frame_system::Config>::Hash {
2055        BlakeTwo256::hash(&n.to_le_bytes())
2056    }
2057
2058    /// Populates frame_system::BlockHash for blocks `start..=end`.
2059    fn register_block_hashes(start: u64, end: u64) {
2060        for n in start..=end {
2061            frame_system::BlockHash::<Test>::insert(n, mock_hash(n));
2062        }
2063    }
2064
2065    /// Sets system block number.
2066    fn set_block(n: u64) { System::set_block_number(n) }
2067
2068    /// Reads HEAD from offchain storage.
2069    fn read_head() -> Option<BlockNumberFor<Test>> {
2070        load_value::<BlockNumberFor<Test>>(&[TAG, HEAD_BLOCK].concat())
2071    }
2072
2073    /// Resolves a branch via the full routing chain for block `n`:
2074    /// block_hash(n) -> block_key -> divider -> branch_key -> Branch
2075    fn resolve_branch(n: u64) -> Option<Branch<Test, TestScope>> {
2076        TestForks::get_block_branch(mock_hash(n))
2077    }
2078 
2079    /// Reads a branch directly by genesis + counter.
2080    fn branch_by_lineage(
2081        genesis: [u8; 32],
2082        counter: &[u32],
2083    ) -> Option<Branch<Test, TestScope>> {
2084        load_value::<Branch<Test, TestScope>>(&branch_key(TAG, genesis, counter))
2085    }
2086
2087    /// Returns the genesis that the None recovery path derives when
2088    /// grand_parent = block_hash(gp_block).
2089    fn recovery_genesis(gp_block: u64) -> [u8; 32] {
2090        mock_hash(gp_block).encode().using_encoded(blake2_256)
2091    }
2092
2093    // -------------------------------------------------------------------------
2094    // ````````````````````` TS 1 - KEY BUILDER DETERMINISM ````````````````````
2095    // -------------------------------------------------------------------------
2096
2097    /// Behavior: block_key is deterministic, TAG-namespaced, and distinct
2098    /// across different block hashes.
2099    ///
2100    /// Scenario: two block hashes, two TAGs.
2101    #[test]
2102    fn key_builders_block_key_is_deterministic_and_tag_namespaced() {
2103        let h1 = mock_hash(1);
2104        let h2 = mock_hash(2);
2105        let tag_a = b"pallet_a".as_ref();
2106        let tag_b = b"pallet_b".as_ref();
2107 
2108        // Deterministic.
2109        assert_eq!(block_key(tag_a, h1), block_key(tag_a, h1));
2110 
2111        // Different TAG -> different key.
2112        assert_ne!(block_key(tag_a, h1), block_key(tag_b, h1));
2113 
2114        // Different hash -> different key.
2115        assert_ne!(block_key(tag_a, h1), block_key(tag_a, h2));
2116    }
2117 
2118    /// Behavior: divider_key differentiates sibling branches from the same
2119    /// parent, which is what prevents them from overwriting each other.
2120    ///
2121    /// Scenario: one parent hash, two different branch keys (siblings).
2122    #[test]
2123    fn key_builders_divider_key_differentiates_siblings_from_same_parent() {
2124        let tag = TAG;
2125        let parent = mock_hash(5);
2126        let branch_a = [0xAAu8; 32];
2127        let branch_b = [0xBBu8; 32];
2128 
2129        let d_a = divider_key(tag, parent, branch_a);
2130        let d_b = divider_key(tag, parent, branch_b);
2131 
2132        // Two siblings with the same parent must produce distinct divider keys.
2133        assert_ne!(d_a, d_b);
2134 
2135        // Deterministic
2136        assert_eq!(d_a, divider_key(tag, parent, branch_a));
2137    }
2138
2139    /// Behavior: branch_key encodes the full counter lineage, so branches at
2140    /// different paths are always stored at distinct keys.
2141    ///
2142    /// Scenario: root [], first fork [0], second fork [1], nested fork [0,0],
2143    /// and same counter under a different genesis.
2144    #[test]
2145    fn key_builders_branch_key_encodes_full_counter_lineage() {
2146        let tag = TAG;
2147        let genesis = recovery_genesis(0);
2148 
2149        let k_root = branch_key(tag, genesis, &[]);
2150        let k_fork0 = branch_key(tag, genesis, &[0]);
2151        let k_fork1 = branch_key(tag, genesis, &[1]);
2152        let k_nested = branch_key(tag, genesis, &[0, 0]);
2153 
2154        assert_ne!(k_root, k_fork0);
2155        assert_ne!(k_fork0, k_fork1);
2156        assert_ne!(k_fork0, k_nested);
2157 
2158        // Deterministic
2159        assert_eq!(k_fork0, branch_key(tag, genesis, &[0]));
2160 
2161        // Different genesis -> different key even with same counter.
2162        let genesis2 = recovery_genesis(1);
2163        assert_ne!(branch_key(tag, genesis, &[0]), branch_key(tag, genesis2, &[0]));
2164    }
2165
2166    // -------------------------------------------------------------------------
2167    // ````````````````````````` TS 2 - BOOTSTRAP GUARD ````````````````````````
2168    // -------------------------------------------------------------------------
2169
2170    /// Behavior: start() returns immediately at block 0 - saturating sub
2171    /// collapses parent and grandparent to the same value.
2172    ///
2173    /// Scenario: N=0, actual_parent(0) == actual_grandparent(0).
2174    #[test]
2175    fn bootstrap_guard_skips_block_zero() {
2176        new_ocw_ext().execute_with(|| {
2177            set_block(0);
2178            let mut ran = false;
2179            TestForks::start(None, None, || { ran = true; });
2180            assert!(!ran, "ocw must not run at block 0");
2181            assert!(read_head().is_none());
2182        });
2183    }
2184
2185    /// Behavior: start() returns immediately at block 1.
2186    ///
2187    /// Scenario: N=1, actual_parent(0) == actual_grandparent(0).
2188    #[test]
2189    fn bootstrap_guard_skips_block_one() {
2190        new_ocw_ext().execute_with(|| {
2191            set_block(1);
2192            let mut ran = false;
2193            TestForks::start(None, None, || { ran = true; });
2194            assert!(!ran, "ocw must not run at block 1");
2195            assert!(read_head().is_none());
2196        });
2197    }
2198
2199    /// Behavior: block 2 is the exact lower boundary where start() proceeds.
2200    ///
2201    /// Scenario: guard fires at N=1, passes at N=2.
2202    /// since, actual_parent(1) != actual_grandparent(0)
2203    #[test]
2204    fn bootstrap_guard_exact_boundary_block_two_passes() {
2205        new_ocw_ext().execute_with(|| {
2206            register_block_hashes(0, 2);
2207
2208            set_block(1);
2209            let mut ran = false;
2210            TestForks::start(None, None, || { ran = true; });
2211            assert!(!ran, "block 1 must be skipped by the bootstrap guard");
2212
2213            set_block(2);
2214            let mut ran = false;
2215            TestForks::start(None, None, || { ran = true; });
2216            assert!(ran, "block 2 must pass the bootstrap guard and call ocw");
2217        });
2218    }
2219
2220    // -------------------------------------------------------------------------
2221    // ``````````````````` TS 3 - FRESH GRAPH INITIALISATION ```````````````````
2222    // -------------------------------------------------------------------------
2223
2224    /// Behavior: the first start() call creates a root branch and establishes
2225    /// the full routing invariant for the resolved block.
2226    ///
2227    /// Scenario:
2228    /// (no prior graph)
2229    ///
2230    /// After start(N=2) - resolves block 1:
2231    /// root branch  counter=[]  head=1  parent=None
2232    /// HEAD = 1
2233    ///
2234    /// Routing: block_hash(1) -> block_key -> divider -> branch
2235    ///
2236    /// Note: block_hash(0) also has routing because recovery stores it as
2237    /// the synthetic root anchor for block 1's parent. Both point to the
2238    /// same branch payload, which has head=1 after the longest-chain mutate.
2239    #[test]
2240    fn fresh_graph_initialisation_at_block_two() {
2241        new_ocw_ext().execute_with(|| {
2242            register_block_hashes(0, 2);
2243
2244            set_block(2);
2245            let mut ran = false;
2246            TestForks::start(None, None, || { ran = true; });
2247            assert!(ran, "ocw must run after fresh graph initialisation");
2248
2249            // HEAD = N-1 = 1.
2250            assert_eq!(read_head(), Some(1));
2251
2252            let root = resolve_branch(1)
2253                .expect("block 1 routing must resolve");
2254 
2255            assert!(root.parent.is_none());
2256            assert!(root.counter.is_empty());
2257            assert_eq!(root.head, 1);
2258
2259            // block 0 routes to the same branch as block 1 (synthetic root anchor).
2260            let b0 = resolve_branch(0)
2261                .expect("block 0 routing exists as the synthetic root anchor");
2262            assert_eq!(b0.genesis, root.genesis);
2263            assert_eq!(b0.head, 1);
2264 
2265            // No sibling must exist
2266            assert!(
2267                branch_by_lineage(root.genesis, &[0]).is_none(),
2268                "no sibling branch may exist after fresh init"
2269            );
2270        });
2271    }
2272
2273    // -------------------------------------------------------------------------
2274    // `````````````````````` TS 4 - SEQUENTIAL EXTENSION ``````````````````````
2275    // -------------------------------------------------------------------------
2276
2277    /// Behavior: successive start() calls on the same lineage extend the root
2278    /// branch head in-place without creating new branches.
2279    ///
2280    /// Scenario:
2281    /// A(0) -> B(1) -> C(2) -> D(3)  => single root branch throughout
2282    ///
2283    /// After start(N=3): root.head=2, HEAD=2
2284    /// After start(N=4): root.head=3, HEAD=3
2285    #[test]
2286    fn sequential_extension_advances_root_branch_head() {
2287        new_ocw_ext().execute_with(|| {
2288            register_block_hashes(0, 5);
2289
2290            set_block(2);
2291            TestForks::start(None, None, || {});
2292
2293            set_block(3);
2294            let mut ran = false;
2295            TestForks::start(None, None, || { ran = true; });
2296
2297            assert!(ran, "ocw must run at block 3");
2298            assert_eq!(read_head(), Some(2));
2299
2300            let b2 = resolve_branch(2).expect("block 2 routing must resolve");
2301            assert_eq!(b2.head, 2);
2302            assert!(b2.counter.is_empty());
2303 
2304            // Earlier routing for block 1 must survive and share genesis.
2305            let b1 = resolve_branch(1).expect("block 1 routing must still resolve");
2306            assert_eq!(b1.genesis, b2.genesis);
2307 
2308            // No sibling must exist.
2309            assert!(
2310                branch_by_lineage(b2.genesis, &[0]).is_none(),
2311                "no sibling may exist after sequential extension"
2312            );
2313
2314            set_block(4);
2315            let mut ran = false;
2316            TestForks::start(None, None, || { ran = true; });
2317
2318            assert!(ran, "ocw must run at block 4");
2319            assert_eq!(read_head(), Some(3));
2320
2321            let b3 = resolve_branch(3).expect("block 3 routing must resolve");
2322            assert_eq!(b3.head, 3);
2323            assert_eq!(b3.genesis, b2.genesis, "genesis must be stable across extensions");
2324        });
2325    }
2326
2327    // -------------------------------------------------------------------------
2328    // `````````````````````` TS 5 - SIBLING FORK CREATION `````````````````````
2329    // -------------------------------------------------------------------------
2330
2331    /// Behavior: a competing block at height <= HEAD triggers the sibling path.
2332    /// A new branch is created with its own routing chain. HEAD is not updated.
2333    ///
2334    /// Scenario:
2335    /// - Canonical: A(0) -> B(1) -> C(2)->D(3) => HEAD=3
2336    /// - Fork: A(0) -> B(1) -> C'(2) -> D'(3) => competing hashes
2337    ///
2338    /// After fork start(N=4):
2339    /// sibling  counter=[0]  head=3  parent=Some(fork_root_key)
2340    /// HEAD stays at 3
2341    #[test]
2342    fn sibling_fork_created_when_block_at_or_below_head() {
2343        new_ocw_ext().execute_with(|| {
2344            register_block_hashes(0, 5);
2345
2346            set_block(2);
2347            TestForks::start(None, None, || {});
2348            set_block(3);
2349            TestForks::start(None, None, || {});
2350            set_block(4);
2351            TestForks::start(None, None, || {});
2352            assert_eq!(read_head(), Some(3));
2353
2354            // Capture canonical routing before injecting the fork.
2355            let canonical = resolve_branch(3).expect("canonical block 3 must resolve");
2356
2357            // Inject a competing fork at blocks 2 and 3.
2358            let fork_hash_3 = BlakeTwo256::hash(b"fork_block_3");
2359            let fork_hash_2 = BlakeTwo256::hash(b"fork_block_2");
2360            frame_system::BlockHash::<Test>::insert(3, fork_hash_3);
2361            frame_system::BlockHash::<Test>::insert(2, fork_hash_2);
2362
2363            set_block(4);
2364            let mut ran = false;
2365            TestForks::start(None, None, || { ran = true; });
2366
2367            assert!(ran, "ocw must run on the sibling fork path");
2368
2369            // HEAD must not advance - sibling path does not update it.
2370            assert_eq!(read_head(), Some(3), "HEAD must stay at 3");
2371
2372            // Resolve sibling via the fork's routing chain.
2373            let sibling = TestForks::get_block_branch(fork_hash_3)
2374                .expect("fork_hash_3 must resolve to sibling branch");
2375            assert_eq!(sibling.head, 3);
2376            assert_eq!(sibling.counter, vec![0u32]);
2377            assert!(sibling.parent.is_some());
2378 
2379            // Load fork_root via sibling.parent - no genesis derivation needed.
2380            let fork_root_key = sibling.parent.unwrap();
2381            let fork_root = TestForks::get_branch(&fork_root_key)
2382                .expect("fork recovery root must be loadable via sibling.parent");
2383            assert_eq!(fork_root.head, 2);
2384            assert!(fork_root.counter.is_empty());
2385 
2386            // Canonical routing must not have been overwritten by the fork.
2387            frame_system::BlockHash::<Test>::insert(3, mock_hash(3));
2388            let canonical_after = resolve_branch(3)
2389                .expect("canonical routing must survive fork creation");
2390            assert_eq!(canonical_after.genesis, canonical.genesis);
2391        });
2392    }
2393
2394    // -------------------------------------------------------------------------
2395    // `````````````````` TS 6 - OCW CLOSURE INVOCATION COUNT ``````````````````
2396    // -------------------------------------------------------------------------
2397
2398    /// Behavior: OCW closure runs exactly once per successful start() call
2399    /// and never during bootstrap-guarded blocks.
2400    ///
2401    /// Scenario: two bootstrap blocks (0,1) and three sequential blocks (2,3,4).
2402    #[test]
2403    fn ocw_closure_runs_exactly_once_per_successful_call() {
2404        new_ocw_ext().execute_with(|| {
2405            register_block_hashes(0, 5);
2406            let mut count = 0u32;
2407
2408            set_block(0); 
2409            TestForks::start(None, None, || { count += 1; });
2410            set_block(1); 
2411            TestForks::start(None, None, || { count += 1; });
2412            assert_eq!(count, 0, "ocw must never run at blocks 0 or 1");
2413
2414            set_block(2);
2415            TestForks::start(None, None, || { count += 1; });
2416            assert_eq!(count, 1);
2417
2418            set_block(3);
2419            TestForks::start(None, None, || { count += 1; });
2420            assert_eq!(count, 2);
2421
2422            set_block(4);
2423            TestForks::start(None, None, || { count += 1; });
2424            assert_eq!(count, 3);
2425        });
2426    }
2427
2428    // -------------------------------------------------------------------------
2429    // ```````````````````` TS 7 - RECOVERY: MISSING DIVIDER ```````````````````
2430    // -------------------------------------------------------------------------
2431
2432    /// Behavior: a wiped block_key routing entry triggers parent_divider_unavailable,
2433    /// which delegates to parent_branch_hash_unavailable. Recovery rebuilds routing
2434    /// for the gap and HEAD advances correctly.
2435    ///
2436    /// Scenario:
2437    /// - Canonical: A(0) -> B(1) -> C(2) -> D(3) =>  HEAD=3
2438    /// - Corrupt: block_key for block 3 wiped
2439    ///
2440    /// Recovery rebuilds block 3 routing with parent linkage to block 2.
2441    /// Result: E(4) resolved, HEAD=4
2442    #[test]
2443    fn recovery_missing_divider_rebuilds_routing_and_advances_head() {
2444        new_ocw_ext().execute_with(|| {
2445            register_block_hashes(0, 6);
2446
2447            set_block(2);
2448            TestForks::start(None, None, || {});
2449            set_block(3);
2450            TestForks::start(None, None, || {});
2451            set_block(4);
2452            TestForks::start(None, None, || {});
2453            assert_eq!(read_head(), Some(3));
2454
2455            // Wipe the routing entry for block 3.
2456            StorageValueRef::persistent(&block_key(TAG, mock_hash(3))).clear();
2457            assert!(resolve_branch(3).is_none(), "block 3 routing must be broken after wipe");
2458
2459            set_block(5);
2460            let mut ran = false;
2461            TestForks::start(None, None, || { ran = true; });
2462
2463            assert!(ran, "ocw must run after missing-divider recovery");
2464            assert_eq!(read_head(), Some(4), "HEAD must advance to 4 after recovery");
2465
2466            let b4 = resolve_branch(4).expect("block 4 routing must resolve after recovery");
2467            assert_eq!(b4.head, 4);
2468 
2469            // Forward rebuild restores block 3's routing pointing to the same synthetic
2470            // branch. The longest-chain mutate at iteration 2 then advances that
2471            // branch's head from 3 -> 4 in-place, so both block 3 and block 4 route
2472            // to the same payload with head=4.
2473            let b3 = resolve_branch(3).expect("block 3 routing must be rebuilt by forward recovery");
2474            assert_eq!(b3.head, 4, "rebuilt block 3 branch shares payload with block 4 (head advanced to 4 by mutate)");
2475            assert_eq!(
2476                b3.genesis, b4.genesis,
2477                "block 3 and block 4 must share the same synthetic branch lineage"
2478            );
2479        });
2480    }
2481
2482    // -------------------------------------------------------------------------
2483    // ``` TS 8 - RECOVERY: CORRUPTED BRANCH PAYLOAD + STALE DIVIDER CLEANUP ```
2484    // -------------------------------------------------------------------------
2485
2486    /// Behavior: `parent_branch_unavailable` clears the stale divider before
2487    /// delegating to recovery. This test confirms the divider is absent after
2488    /// `start()` completes.
2489    ///
2490    /// The sibling path (block=3 <= head=3) is used so that
2491    /// `parent_branch_unavailable(block=3)` computes:
2492    ///
2493    ///   parent = block_hash(2) = mock_hash(2)
2494    ///
2495    /// making divider(mock_hash(2)) the exact key captured and asserted cleared.
2496    ///
2497    /// Scenario:
2498    /// - Canonical: A(0) -> B(1) -> C(2) -> D(3)  =>  HEAD=3
2499    /// - Corrupt: branch payload wiped, routing intact
2500    ///
2501    /// start(N=4) again: block=3 <= head=3 -> sibling path
2502    /// get_branch(branch_key) -> None
2503    /// parent_branch_unavailable clears divider(mock_hash(2))
2504    /// recovery runs, sibling created, HEAD unchanged
2505    #[test]
2506    fn recovery_stale_divider_is_cleared_before_fallback_recovery() {
2507        new_ocw_ext().execute_with(|| {
2508            register_block_hashes(0, 5);
2509
2510            set_block(2); TestForks::start(None, None, || {});
2511            set_block(3); TestForks::start(None, None, || {});
2512            set_block(4); TestForks::start(None, None, || {});
2513            assert_eq!(read_head(), Some(3));
2514
2515            // Capture the exact divider that parent_branch_unavailable will clear.
2516            let divider_hash = TestForks::get_divider(mock_hash(2))
2517                .expect("divider for mock_hash(2) must exist before corruption");
2518
2519            // routing resolves before corruption.
2520            assert!(resolve_branch(3).is_some(),
2521                "block 3 routing must be intact before corruption");
2522
2523            // Wipe the branch payload only.
2524            // block_key -> divider -> branch_key all remain intact.
2525            let b3 = resolve_branch(3).expect("block 3 must resolve");
2526            let root_key = branch_key(TAG, b3.genesis, &[]);
2527            StorageValueRef::persistent(&root_key).clear();
2528
2529            // routing now fails at the branch payload level.
2530            assert!(resolve_branch(3).is_none(),
2531                "routing must return None when branch payload is missing");
2532
2533            // start() again at N=4: block=3 <= head=3 -> sibling path
2534            // -> get_branch returns None -> parent_branch_unavailable fires
2535            // -> clears divider_hash -> recovery runs.
2536            set_block(4);
2537            let mut ran = false;
2538            TestForks::start(None, None, || { ran = true; });
2539
2540            // divider_hash must be absent: parent_branch_unavailable cleared it
2541            // before delegating to recovery.
2542            assert!(
2543                load_value::<[u8; 32]>(&divider_hash).is_none(),
2544                "stale divider must be cleared before recovery"
2545            );
2546
2547            assert!(ran, "ocw must run after stale-divider recovery");
2548
2549            // HEAD must not advance - sibling path does not update HEAD.
2550            assert_eq!(read_head(), Some(3));
2551        });
2552    }
2553
2554    // -------------------------------------------------------------------------
2555    // ````` TS 9 - RECOVERY: MULTI-BLOCK GAP WITH SHARED SYNTHETIC BRANCH `````
2556    // -------------------------------------------------------------------------
2557
2558    /// Behavior: the forward rebuild restores routing from recoverer+1 up to
2559    /// block (exclusive). Block 3 is the recoverer itself and is not restored,
2560    /// only block 4 is rebuilt, pointing to block 2 as its parent.
2561    ///
2562    /// Scenario:
2563    /// - Before:  A(0) -> B(1) -> C(2) -> D(3) -> E(4)  =>  HEAD=4
2564    /// - Corrupt: block_key for blocks 3 and 4 wiped
2565    ///
2566    /// Recovery walks back from recoverer=3, finds ancestor at block_hash(2).
2567    /// Forward rebuild: target=4 only (target starts at recoverer+1=4).
2568    /// block_key for block 3 is not restored.
2569    /// block_key for block 4 is restored (synthetic branch with parent=block2_branch).
2570    ///
2571    /// Result: F(5) resolved, HEAD=5
2572    #[test]
2573    fn recovery_rebuilds_multi_block_gap_with_shared_synthetic_branch() {
2574        new_ocw_ext().execute_with(|| {
2575            register_block_hashes(0, 7);
2576 
2577            set_block(2); 
2578            TestForks::start(None, None, || {});
2579            set_block(3); 
2580            TestForks::start(None, None, || {});
2581            set_block(4); 
2582            TestForks::start(None, None, || {});
2583            set_block(5); 
2584            TestForks::start(None, None, || {});
2585            assert_eq!(read_head(), Some(4));
2586 
2587            StorageValueRef::persistent(&block_key(TAG, mock_hash(3))).clear();
2588            StorageValueRef::persistent(&block_key(TAG, mock_hash(4))).clear();
2589 
2590            assert!(resolve_branch(3).is_none(), "block 3 routing must be broken");
2591            assert!(resolve_branch(4).is_none(), "block 4 routing must be broken");
2592 
2593            set_block(6);
2594            let mut ran = false;
2595            TestForks::start(None, None, || { ran = true; });
2596 
2597            assert!(ran, "ocw must run after multi-block gap recovery");
2598            assert_eq!(read_head(), Some(5));
2599 
2600            // Block 5 must resolve - it is the block resolved by this start() call.
2601            let b5 = resolve_branch(5).expect("block 5 routing must resolve");
2602            assert_eq!(b5.head, 5);
2603 
2604            // Block 4 rebuilt by forward loop - parent links to block 2 (last intact ancestor).
2605            let b4 = resolve_branch(4).expect("block 4 routing must be rebuilt by forward recovery");
2606            let parent_key = b4.parent.expect("synthetic branch must carry parent linkage");
2607            let parent_branch = TestForks::get_branch(&parent_key)
2608                .expect("synthetic branch parent must be loadable");
2609            let b2 = resolve_branch(2).expect("block 2 must be intact");
2610            assert_eq!(parent_branch.genesis, b2.genesis,
2611                "synthetic branch parent must link to the last intact ancestor (block 2)");
2612
2613            // Block 3 is the recoverer itself - the forward loop starts at recoverer+1=4
2614            // and does not restore block 3's routing. It remains unresolvable.
2615            assert!(resolve_branch(3).is_none(),
2616                "block 3 routing is not restored by forward rebuild");
2617        });
2618    }
2619
2620    // -------------------------------------------------------------------------
2621    // ```````````````` TS 10 - RECOVERY: DECODE ERROR IN MUTATE ```````````````
2622    // -------------------------------------------------------------------------
2623
2624    /// Behavior: a garbage branch payload causes Branch::decode to fail inside
2625    /// the mutate closure. inherited_branch_decode_error -> parent_branch_unavailable
2626    /// -> stale divider cleared -> parent_branch_hash_unavailable rebuilds routing.
2627    ///
2628    /// Scenario:
2629    /// - Canonical: A(0) -> B(1) -> C(2)  => HEAD=2
2630    /// - Corrupt: branch payload replaced with 0xDEADBEEF
2631    ///
2632    /// mutate -> Err(decode) -> inherited_branch_decode_error -> recovery
2633    /// Result: D(3) resolved, HEAD=3
2634    #[test]
2635    fn decode_error_in_mutate_triggers_recovery_and_ocw_still_runs() {
2636        new_ocw_ext().execute_with(|| {
2637            register_block_hashes(0, 5);
2638 
2639            set_block(2); 
2640            TestForks::start(None, None, || {});
2641            set_block(3); 
2642            TestForks::start(None, None, || {});
2643            assert_eq!(read_head(), Some(2));
2644 
2645            // Derive genesis from the routing chain, not by independent computation.
2646            let b2 = resolve_branch(2).expect("block 2 must resolve before corruption");
2647            let root_key = branch_key(TAG, b2.genesis, &[]);
2648            StorageValueRef::persistent(&root_key).set(&[0xDE, 0xAD, 0xBE, 0xEF]);
2649 
2650            assert!(resolve_branch(2).is_none(),
2651                "routing must return None when payload is corrupt");
2652 
2653            set_block(4);
2654            let mut ran = false;
2655            TestForks::start(None, None, || { ran = true; });
2656 
2657            assert!(ran, "ocw must run after decode-error recovery");
2658            assert_eq!(read_head(), Some(3), "HEAD must advance to 3");
2659 
2660            let b3 = resolve_branch(3).expect("block 3 routing must resolve after recovery");
2661            assert_eq!(b3.head, 3);
2662        });
2663    }
2664
2665    // -------------------------------------------------------------------------
2666    // `````````` TS 11 - CONCURRENT MODIFICATION / SIBLING PROMOTION ``````````
2667    //
2668    // StorageValueRef::mutate internally uses compare-and-set (CAS), so
2669    // ConcurrentModification only happens if some other write updates
2670    // storage between the read and write phase.
2671    //
2672    // In this test environment everything runs single-threaded, so we can't
2673    // realistically reproduce that race condition through start() itself.
2674    //
2675    // Instead, this test calls inherited_branch_mutation_conflict()
2676    // directly and verifies the same recovery path:
2677    //
2678    // - a sibling branch is created in the next available slot
2679    // - the sibling keeps a parent pointer to the original branch
2680    // - routing is rebuilt for the conflicted block
2681    // - HEAD remains consistent after recovery
2682    // -------------------------------------------------------------------------
2683
2684    /// Behavior: inherited_branch_mutation_conflict promotes the second writer
2685    /// into a new sibling branch. The sibling shares genesis with the original
2686    /// branch, carries parent=original_branch_key, and gets its own routing.
2687    ///
2688    /// Scenario:
2689    /// Canonical chain built to HEAD=2.
2690    /// Writer 1 already committed block 2 on the root branch (counter=[]).
2691    /// Writer 2 arrives late - simulated by calling the conflict handler
2692    /// directly with block=2 (the block both writers competed on).
2693    ///
2694    /// Before conflict handler:
2695    ///   root  counter=[]  head=2  (writer 1 committed)
2696    ///
2697    /// After conflict handler:
2698    ///   root  counter=[]  head=2   (unchanged)
2699    ///     |
2700    ///     +-- sibling  counter=[0]  head=2  parent=root_key  (writer 2)
2701    #[test]
2702    fn concurrent_modification_promotes_conflict_writer_to_sibling_branch() {
2703        new_ocw_ext().execute_with(|| {
2704            register_block_hashes(0, 4);
2705 
2706            set_block(2); TestForks::start(None, None, || {});
2707            set_block(3); TestForks::start(None, None, || {});
2708            assert_eq!(read_head(), Some(2));
2709 
2710            // The conflict handler resolves parent = block_hash(block-1=1) = mock_hash(1).
2711            // Capture the root branch at that key before the conflict fires.
2712            let root_branch_hash = TestForks::get_branch_hash(mock_hash(1))
2713                .expect("root branch hash must exist");
2714 
2715            // Verify the root branch is reachable and at the expected state.
2716            let root = TestForks::get_branch(&root_branch_hash)
2717                .expect("root branch must be loadable");
2718            assert!(root.counter.is_empty());
2719            assert_eq!(root.head, 2);
2720 
2721            // Fire the conflict handler directly for block=2.
2722            let result = TestForks::inherited_branch_mutation_conflict(2, None, None);
2723            assert!(result.is_ok(), "conflict handler must succeed");
2724 
2725            assert_eq!(read_head(), Some(2), "HEAD must be 2 after conflict resolution");
2726 
2727            // Routing for block 2 must now point to the sibling branch.
2728            let sibling = TestForks::get_block_branch(mock_hash(2))
2729                .expect("block 2 routing must resolve to the sibling branch");
2730 
2731            assert_eq!(sibling.counter, vec![0u32]);
2732            assert_eq!(sibling.head, 2);
2733 
2734            // Sibling must point to the root branch as its structural parent.
2735            let sibling_parent_key = sibling.parent
2736                .expect("sibling must carry a parent key");
2737            assert_eq!(sibling_parent_key, root_branch_hash,
2738                "sibling parent must be the root branch (writer 1's branch)");
2739 
2740            // Root branch must be unchanged - writer 1's commit is preserved.
2741            let root_after = TestForks::get_branch(&root_branch_hash)
2742                .expect("root branch must still exist");
2743            assert_eq!(root_after.counter, root.counter);
2744            assert_eq!(root_after.head, root.head);
2745            assert_eq!(root_after.genesis, sibling.genesis);
2746        });
2747    }
2748
2749    // -------------------------------------------------------------------------
2750    // `````````````````````` TS 12 - MAX FORKS EXHAUSTION `````````````````````
2751    // -------------------------------------------------------------------------
2752
2753    /// Behavior: when all counter slots [0..=MAX_FORKS] under the fork's
2754    /// genesis are occupied, the slot search fails, max_forks() returns Err,
2755    /// the loop breaks, and the OCW closure is not called.
2756    ///
2757    /// Scenario:
2758    /// - Canonical: A(0) -> B(1) -> C(2) -> D(3)  => HEAD=3
2759    /// - Fork: competing hashes for blocks 2 and 3
2760    /// all sibling slots pre-filled under fork genesis
2761    ///
2762    /// Result: OCW not called, HEAD stays at 3
2763    #[test]
2764    fn max_forks_exhaustion_prevents_sibling_creation_and_ocw() {
2765        new_ocw_ext().execute_with(|| {
2766            register_block_hashes(0, 5);
2767 
2768            set_block(2); 
2769            TestForks::start(None, None, || {});
2770            set_block(3); 
2771            TestForks::start(None, None, || {});
2772            set_block(4); 
2773            TestForks::start(None, None, || {});
2774            assert_eq!(read_head(), Some(3));
2775 
2776            // Fork genesis derived from grand_parent = block_hash(3-2=1)
2777            let genesis_fork = recovery_genesis(1);
2778            let root_key = branch_key(TAG, genesis_fork, &[]);
2779 
2780            store_encoded(&root_key, &Branch::<Test, TestScope> {
2781                parent: None,
2782                head: 2,
2783                scope: TestScope::default(),
2784                genesis: genesis_fork,
2785                counter: vec![],
2786            });
2787            
2788            // Fill every sibling slot so no free slot exists.
2789            for i in 0u32..=TestForks::MAX_FORKS {
2790                let sibling_key = branch_key(TAG, genesis_fork, &[i]);
2791                store_encoded(&sibling_key, &Branch::<Test, TestScope> {
2792                    parent: Some(root_key),
2793                    head: 2,
2794                    scope: TestScope::default(),
2795                    genesis: genesis_fork,
2796                    counter: vec![i],
2797                });
2798            }
2799 
2800            let fork_hash_2 = BlakeTwo256::hash(b"max_fork_block_2");
2801            let fork_hash_3 = BlakeTwo256::hash(b"max_fork_block_3");
2802            frame_system::BlockHash::<Test>::insert(2, fork_hash_2);
2803            frame_system::BlockHash::<Test>::insert(3, fork_hash_3);
2804            
2805            // Wire routing so the fork is reachable via block_key(TAG, fork_hash_2).
2806            let dh = divider_key(TAG, fork_hash_2, root_key);
2807            store_encoded(&dh, &root_key);
2808            store_encoded(&block_key(TAG, fork_hash_2), &dh);
2809 
2810            set_block(4);
2811            let mut ran = false;
2812            TestForks::start(None, None, || { ran = true; });
2813 
2814            assert!(!ran, "ocw must NOT run when MAX_FORKS is exhausted");
2815            assert_eq!(read_head(), Some(3), "HEAD must stay at 3");
2816            assert!(
2817                branch_by_lineage(genesis_fork, &[TestForks::MAX_FORKS + 1]).is_none(),
2818                "no branch beyond MAX_FORKS must be created"
2819            );
2820        });
2821    }
2822
2823    // -------------------------------------------------------------------------
2824    // ``````````` TS 13 - RECOVERY: SYNTHETIC BRANCH PARENT LINKAGE ```````````
2825    // -------------------------------------------------------------------------
2826
2827    /// Behavior: every synthetic branch created during forward rebuild must
2828    /// carry a parent pointer to the last intact ancestor branch, not None.
2829    ///
2830    /// Scenario:
2831    /// - Canonical:  A(0) -> B(1) -> C(2) -> D(3)  => HEAD=3
2832    /// - Corrupt: block_key for block 3 wiped
2833    ///
2834    /// Rebuilt block 3 branch: parent = block_2_branch_key
2835    #[test]
2836    fn recovery_synthetic_branch_preserves_parent_linkage() {
2837        new_ocw_ext().execute_with(|| {
2838            register_block_hashes(0, 5);
2839 
2840            set_block(2); 
2841            TestForks::start(None, None, || {});
2842            set_block(3); 
2843            TestForks::start(None, None, || {});
2844            set_block(4); 
2845            TestForks::start(None, None, || {});
2846 
2847            // Capture block 2 branch hash before wiping block 3.
2848            let b2_branch_hash = TestForks::get_branch_hash(mock_hash(2))
2849                .expect("block 2 branch hash must exist");
2850 
2851            StorageValueRef::persistent(&block_key(TAG, mock_hash(3))).clear();
2852 
2853            set_block(5);
2854            TestForks::start(None, None, || {});
2855 
2856            let b3 = resolve_branch(3).expect("block 3 routing must be rebuilt");
2857 
2858            let parent_key = b3.parent
2859                .expect("rebuilt synthetic branch must carry a parent key");
2860            assert_eq!(parent_key, b2_branch_hash,
2861                "synthetic branch parent must point to block 2's branch");
2862 
2863            // Navigating to the parent must load block 2's branch.
2864            let parent_branch = TestForks::get_branch(&parent_key)
2865                .expect("parent branch must be loadable");
2866            let b2 = resolve_branch(2).expect("block 2 must still be intact");
2867            assert_eq!(parent_branch.genesis, b2.genesis);
2868        });
2869    }
2870 
2871    // -------------------------------------------------------------------------
2872    // ``````````````````` TS 14 - REPEATED START IDEMPOTENCY ``````````````````
2873    // -------------------------------------------------------------------------
2874
2875    /// Behavior: calling start() twice at the same block does not corrupt HEAD,
2876    /// duplicate branches, or alter existing routing.
2877    ///
2878    /// Scenario: start(N=3) called twice in succession.
2879    #[test]
2880    fn repeated_start_at_same_block_is_idempotent() {
2881        new_ocw_ext().execute_with(|| {
2882            register_block_hashes(0, 4);
2883 
2884            set_block(2); 
2885            TestForks::start(None, None, || {});
2886            set_block(3); 
2887            TestForks::start(None, None, || {});
2888 
2889            let head_first = read_head();
2890            let b2_first = resolve_branch(2).expect("block 2 must resolve");
2891 
2892            set_block(3);
2893            TestForks::start(None, None, || {});
2894 
2895            assert_eq!(read_head(), head_first, "HEAD must not change after repeated start");
2896 
2897            let b2_second = resolve_branch(2).expect("block 2 must still resolve");
2898            assert_eq!(b2_first.genesis, b2_second.genesis,
2899                "repeated start must not alter branch genesis");
2900            assert_eq!(b2_first.head, b2_second.head,
2901                "repeated start must not alter branch head");
2902        });
2903    }
2904
2905    // -------------------------------------------------------------------------
2906    // ````````````````````` TS 15 - FORK GRAPH NAVIGATION `````````````````````
2907    // -------------------------------------------------------------------------
2908    // Verifies all ForkAction variants against a graph with a canonical root
2909    // and a fork branch created by injecting competing hashes at block 3.
2910    //
2911    // Graph after setup:
2912    //
2913    //   [canonical]
2914    //   root  counter=[]  head=3  parent=None
2915    //     ^
2916    //     | fork_root.parent points here (set by forward rebuild recovery)
2917    //     |
2918    //   [fork]
2919    //   fork_root  counter=[]  head=2  parent=Some(canonical_root_key)
2920    //       |
2921    //       +-- sibling  counter=[0]  head=3  parent=Some(fork_root_key)
2922    #[test]
2923    fn fork_action_handler_navigation_after_graph_built() {
2924        new_ocw_ext().execute_with(|| {
2925            register_block_hashes(0, 6);
2926 
2927            set_block(2);
2928            TestForks::start(None, None, || {});
2929            set_block(3);
2930            TestForks::start(None, None, || {});
2931            set_block(4);
2932            TestForks::start(None, None, || {});
2933 
2934            // Create sibling fork at block 3 by injecting competing hashes.
2935            let fork_hash_3 = BlakeTwo256::hash(b"nav_fork_3");
2936            let fork_hash_2 = BlakeTwo256::hash(b"nav_fork_2");
2937            frame_system::BlockHash::<Test>::insert(3, fork_hash_3);
2938            frame_system::BlockHash::<Test>::insert(2, fork_hash_2);
2939            set_block(4);
2940            TestForks::start(None, None, || {});
2941 
2942            // Load branches via routing chains
2943            frame_system::BlockHash::<Test>::insert(3, mock_hash(3));
2944            frame_system::BlockHash::<Test>::insert(2, mock_hash(2));
2945 
2946            let root = resolve_branch(3)
2947                .expect("canonical root must resolve via block 3 routing");
2948            let sibling = TestForks::get_block_branch(fork_hash_3)
2949                .expect("sibling must resolve via fork_hash_3 routing chain");
2950            let fork_root_key = sibling.parent
2951                .expect("sibling must carry a parent key");
2952            let fork_root = TestForks::get_branch(&fork_root_key)
2953                .expect("fork_root must be loadable via sibling.parent");
2954 
2955            // Graph invariants
2956            assert_eq!(root.head, 3);      
2957            assert!(root.parent.is_none());
2958            assert_eq!(fork_root.head, 2); 
2959            assert!(fork_root.counter.is_empty());
2960            assert_eq!(sibling.head, 3);   
2961            assert_eq!(sibling.counter, vec![0u32]);
2962            
2963            // ----------------------- MoveToParentBranch ----------------------
2964
2965            // sibling[0] -> fork_root[]: parent pointer leads to fork_root.
2966            let p = TestForks::transition(&sibling, ForkAction::MoveToParentBranch)
2967                .expect("MoveToParentBranch from sibling must succeed");
2968            assert!(p.counter.is_empty(), );
2969            assert_eq!(p.head, fork_root.head);
2970
2971            // fork_root.parent was set by recovery to the canonical root.
2972            let fork_root_parent = TestForks::transition(&fork_root, ForkAction::MoveToParentBranch)
2973                .expect("MoveToParentBranch on fork_root must succeed");
2974
2975            // The parent must be the canonical root - same genesis, same counter shape.
2976            assert_eq!(fork_root_parent.genesis, root.genesis);
2977            assert!(fork_root_parent.counter.is_empty());
2978            assert_eq!(fork_root_parent.head, root.head);
2979            
2980            // ------------------- MoveToParentBranchBack(n) -------------------
2981 
2982            // n=0: no-op, returns self unchanged.
2983            let b = TestForks::transition(&sibling, ForkAction::MoveToParentBranchBack(0))
2984                .expect("MoveToParentBranchBack(0) must return self");
2985            assert_eq!(b.counter, sibling.counter);
2986            assert_eq!(b.head, sibling.head);
2987 
2988            // n=1: sibling -> fork_root.
2989            let b = TestForks::transition(&sibling, ForkAction::MoveToParentBranchBack(1))
2990                .expect("MoveToParentBranchBack(1) must succeed");
2991            assert!(b.counter.is_empty());
2992 
2993            // n=2: sibling -> fork_root -> canonical_root (fork_root has parent set by recovery)
2994            let b = TestForks::transition(&sibling, ForkAction::MoveToParentBranchBack(2))
2995                .expect("MoveToParentBranchBack(2) must succeed - sibling has 2 levels of ancestry");
2996            assert_eq!(
2997                b.genesis, root.genesis,
2998                "Back(2) from sibling must reach the canonical root"
2999            );
3000
3001            // n=3: exceeds actual ancestry depth -> None
3002            assert!(
3003                TestForks::transition(&sibling, ForkAction::MoveToParentBranchBack(3)).is_none(),
3004                "MoveToParentBranchBack(3) exceeds ancestry depth -> None"
3005            );
3006 
3007            // -------------------- MoveToChildBranch(index) -------------------
3008 
3009            let child = TestForks::transition(&fork_root, ForkAction::MoveToChildBranch(0))
3010                .expect("MoveToChildBranch(0) from fork_root must succeed");
3011            assert_eq!(child.counter, vec![0u32]);
3012 
3013            assert!(
3014                TestForks::transition(&fork_root, ForkAction::MoveToChildBranch(1)).is_none(),
3015                "MoveToChildBranch(1) where no child exists must return None"
3016            );
3017 
3018            // sibling has no children -> None.
3019            assert!(
3020                TestForks::transition(&sibling, ForkAction::MoveToChildBranch(0)).is_none(),
3021                "MoveToChildBranch(0) from a leaf branch must return None"
3022            );
3023 
3024            // --------------------- MoveToNextChildBranch ---------------------
3025 
3026            // fork_root -> sibling (child index 0).
3027            let child = TestForks::transition(&fork_root, ForkAction::MoveToNextChildBranch)
3028                .expect("MoveToNextChildBranch from fork_root must succeed");
3029            assert_eq!(child.counter, vec![0u32]);
3030 
3031            // sibling has no children -> None.
3032            assert!(
3033                TestForks::transition(&sibling, ForkAction::MoveToNextChildBranch).is_none(),
3034                "MoveToNextChildBranch from leaf must return None"
3035            );
3036 
3037            // ------------------- MoveToSiblingBranch(index) ------------------
3038 
3039            // fork_root (counter=[]) requesting index=0 -> sibling[0] (exists).
3040            let sib = TestForks::transition(&fork_root, ForkAction::MoveToSiblingBranch(0))
3041                .expect("MoveToSiblingBranch(0) from root must reach sibling[0]");
3042            assert_eq!(sib.counter, vec![0u32]);
3043 
3044            // sibling (counter=[0]) requesting index=0 -> same as self -> None.
3045            assert!(
3046                TestForks::transition(&sibling, ForkAction::MoveToSiblingBranch(0)).is_none(),
3047                "MoveToSiblingBranch(same index) must return None"
3048            );
3049 
3050            // fork_root requesting index=1 -> slot [1] does not exist -> None.
3051            assert!(
3052                TestForks::transition(&fork_root, ForkAction::MoveToSiblingBranch(1)).is_none(),
3053                "MoveToSiblingBranch to a non-existent slot must return None"
3054            );
3055 
3056            // -------------------- MoveToNextSiblingBranch --------------------
3057 
3058            // fork_root (counter=[]): last=None -> next_index=0 -> sibling[0] exists.
3059            let arrived = TestForks::transition(&fork_root, ForkAction::MoveToNextSiblingBranch)
3060                .expect("MoveToNextSiblingBranch from fork_root must succeed");
3061            assert_eq!(arrived.counter, vec![0u32]);
3062 
3063            // sibling (counter=[0]): last=0 -> next_index=1 -> slot [1] does not exist -> None.
3064            assert!(
3065                TestForks::transition(&sibling, ForkAction::MoveToNextSiblingBranch).is_none(),
3066                "MoveToNextSiblingBranch when next slot is empty must return None"
3067            );
3068 
3069            // ------------------ MoveToPreviousSiblingBranch ------------------
3070 
3071            // sibling (counter=[0]): last=0 -> immediately returns None (no index -1).
3072            assert!(
3073                TestForks::transition(&sibling, ForkAction::MoveToPreviousSiblingBranch).is_none(),
3074                "MoveToPreviousSiblingBranch at index 0 must return None"
3075            );
3076
3077            // fork_root (counter=[]): counter.last() = None -> None.
3078            assert!(
3079                TestForks::transition(&fork_root, ForkAction::MoveToPreviousSiblingBranch).is_none(),
3080                "MoveToPreviousSiblingBranch on a root (counter=[]) must return None"
3081            );
3082
3083            // ------------------------ MoveToRootBranch ------------------------
3084 
3085            // sibling -> fork_root -> canonical_root (parent=None) -> stops at canonical_root.
3086            let root_b = TestForks::transition(&sibling, ForkAction::MoveToRootBranch)
3087                .expect("MoveToRootBranch from sibling must succeed");
3088            assert!(root_b.parent.is_none());
3089            assert_eq!(root_b.genesis, root.genesis);
3090
3091            // fork_root also has a parent (canonical root), so MoveToRootBranch walks
3092            // one more level and lands on the canonical root too.
3093            let root_from_fork = TestForks::transition(&fork_root, ForkAction::MoveToRootBranch)
3094                .expect("MoveToRootBranch from fork_root must succeed");
3095            assert!(root_from_fork.parent.is_none());
3096            assert_eq!(root_from_fork.genesis, root.genesis);
3097        });
3098    }
3099
3100    // -------------------------------------------------------------------------
3101    // ```````````````````` TS 16 - SCOPE HANDLER OPERATIONS ```````````````````
3102    // -------------------------------------------------------------------------
3103
3104    /// Behavior: gen_scope_item_key produces a stable, deterministic 32-byte key.
3105    /// The same item always maps to the same key; different items produce different keys.
3106    ///
3107    /// Scenario: two distinct items encoded as byte slices.
3108    #[test]
3109    fn scope_handler_gen_scope_item_key_is_deterministic_and_distinct() {
3110        let item_a: Vec<u8> = b"key_a".to_vec();
3111        let item_b: Vec<u8> = b"key_b".to_vec();
3112
3113        let k1 = TestForks::gen_scope_item_key(&item_a);
3114        let k2 = TestForks::gen_scope_item_key(&item_a);
3115        let k3 = TestForks::gen_scope_item_key(&item_b);
3116
3117        // Deterministic
3118        assert_eq!(k1, k2);
3119
3120        // Distinct
3121        assert_ne!(k1, k3);
3122    }
3123
3124    /// Behavior: scope_item_exists returns Err(forks_not_enabled) when called
3125    /// before ForksHandler::start has built the fork graph.
3126    ///
3127    /// Scenario: no start() call, direct scope_item_exists at block 2.
3128    #[test]
3129    fn scope_handler_scope_item_exists_returns_err_when_fork_graph_not_initialized() {
3130        new_ocw_ext().execute_with(|| {
3131            register_block_hashes(0, 4);
3132            set_block(2);
3133
3134            let key = TestForks::gen_scope_item_key(&b"test_item".to_vec());
3135            let result = TestForks::scope_item_exists(&key, None, None);
3136
3137            assert_eq!(result, Err(DispatchError::Other("forks-not-enabled")));
3138        });
3139    }
3140
3141    /// Behavior: scope_item_exists returns Ok(false) for a key not yet added
3142    /// after the fork graph is initialized.
3143    ///
3144    /// Scenario: start() runs at block 2, key queried without prior add_to_scope.
3145    #[test]
3146    fn scope_handler_scope_item_exists_returns_false_for_absent_key() {
3147        new_ocw_ext().execute_with(|| {
3148            register_block_hashes(0, 4);
3149            set_block(2);
3150            TestForks::start(None, None, || {});
3151            set_block(3);
3152            TestForks::start(None, None, || {});
3153
3154            let key = TestForks::gen_scope_item_key(&b"absent".to_vec());
3155            let result = TestForks::scope_item_exists(&key, None, None);
3156
3157            assert_eq!(result, Ok(false));
3158        });
3159    }
3160
3161    /// Behavior: add_to_scope writes the item into local_keys of the current branch.
3162    /// scope_item_exists returns Ok(true) for the key on the same branch.
3163    ///
3164    /// Scenario: start() at block 2, add_to_scope at block 3, scope_item_exists at block 3.
3165    #[test]
3166    fn scope_handler_add_to_scope_makes_key_visible_in_local_scope() {
3167        new_ocw_ext().execute_with(|| {
3168            register_block_hashes(0, 5);
3169            set_block(2);
3170            TestForks::start(None, None, || {});
3171            set_block(3);
3172            TestForks::start(None, None, || {});
3173
3174            // add_to_scope writes into branch at block 2 (block - 1 = 2).
3175            let item = b"active_key".to_vec();
3176            let key = TestForks::add_to_scope(item.clone(), None, None).unwrap();
3177
3178            // scope_item_exists at block 3 reads branch at block 2.
3179            let exists = TestForks::scope_item_exists(&key, None, None).unwrap();
3180
3181            assert!(exists); 
3182        });
3183    }
3184
3185    /// Behavior: add_to_scope returns Err(forks_not_enabled) when the fork graph
3186    /// has not been initialized.
3187    ///
3188    /// Scenario: no start() call before add_to_scope.
3189    #[test]
3190    fn scope_handler_add_to_scope_returns_err_when_fork_graph_not_initialized() {
3191        new_ocw_ext().execute_with(|| {
3192            register_block_hashes(0, 4);
3193            set_block(2);
3194
3195            let result = TestForks::add_to_scope(b"item".to_vec(), None, None);
3196
3197            assert_eq!(result, Err(DispatchError::Other("forks-not-enabled")));
3198        });
3199    }
3200
3201    /// Behavior: a key added to local_keys propagates into inherited_keys of the
3202    /// next branch via accrete(), making it visible on the child branch.
3203    ///
3204    /// Scenario: add_to_scope at block 3, advance to block 4 (new branch created),
3205    /// scope_item_exists at block 4 finds key in inherited scope.
3206    #[test]
3207    fn scope_handler_local_key_propagates_to_inherited_on_next_branch() {
3208        new_ocw_ext().execute_with(|| {
3209            register_block_hashes(0, 6);
3210
3211            set_block(2);
3212            TestForks::start(None, None, || {});
3213            set_block(3);
3214            TestForks::start(None, None, || {});
3215
3216            let item = b"propagated_key".to_vec();
3217            let key = TestForks::add_to_scope(item.clone(), None, None).unwrap();
3218
3219            // Advance to block 4 - accrete() promotes local_keys into inherited_keys.
3220            set_block(4);
3221            TestForks::start(None, None, || {});
3222
3223            let exists = TestForks::scope_item_exists(&key, None, None).unwrap();
3224
3225            assert!(exists);
3226        });
3227    }
3228
3229    /// Behavior: remove_from_scope removes a key from local_keys on the current branch.
3230    /// scope_item_exists returns Ok(false) after removal.
3231    ///
3232    /// Scenario: add_to_scope then remove_from_scope on the same branch.
3233    #[test]
3234    fn scope_handler_remove_from_scope_removes_key_from_local_scope() {
3235        new_ocw_ext().execute_with(|| {
3236            register_block_hashes(0, 5);
3237            set_block(2);
3238            TestForks::start(None, None, || {});
3239            set_block(3);
3240            TestForks::start(None, None, || {});
3241
3242            let item = b"removable_key".to_vec();
3243            let key = TestForks::add_to_scope(item.clone(), None, None).unwrap();
3244
3245            // Key exists before removal.
3246            assert!(TestForks::scope_item_exists(&key, None, None).unwrap());
3247
3248            TestForks::remove_from_scope(&key, None, None).unwrap();
3249
3250            // Key is absent after removal.
3251            let exists = TestForks::scope_item_exists(&key, None, None).unwrap();
3252
3253            assert!(!exists);
3254        });
3255    }
3256
3257    /// Behavior: remove_from_scope removes a key from inherited_keys when it
3258    /// was promoted from a previous branch.
3259    ///
3260    /// Scenario: add_to_scope at block 3, advance to block 4 (key becomes inherited),
3261    /// remove_from_scope at block 4.
3262    #[test]
3263    fn scope_handler_remove_from_scope_removes_key_from_inherited_scope() {
3264        new_ocw_ext().execute_with(|| {
3265            register_block_hashes(0, 6);
3266
3267            set_block(2);
3268            TestForks::start(None, None, || {});
3269            set_block(3);
3270            TestForks::start(None, None, || {});
3271
3272            let item = b"inherited_key".to_vec();
3273            let key = TestForks::add_to_scope(item.clone(), None, None).unwrap();
3274
3275            set_block(4);
3276            TestForks::start(None, None, || {});
3277
3278            assert!(TestForks::scope_item_exists(&key, None, None).unwrap());
3279
3280            TestForks::remove_from_scope(&key, None, None).unwrap();
3281
3282            let exists = TestForks::scope_item_exists(&key, None, None).unwrap();
3283
3284            assert!(!exists);
3285        });
3286    }
3287
3288    /// Behavior: remove_from_scope is a no-op for a key that does not exist
3289    /// in either local or inherited scope. Returns Ok(()).
3290    ///
3291    /// Scenario: remove_from_scope called with a key that was never added.
3292    #[test]
3293    fn scope_handler_remove_from_scope_is_noop_for_absent_key() {
3294        new_ocw_ext().execute_with(|| {
3295            register_block_hashes(0, 4);
3296            set_block(2);
3297            TestForks::start(None, None, || {});
3298            set_block(3);
3299            TestForks::start(None, None, || {});
3300
3301            let key = TestForks::gen_scope_item_key(&b"never_added".to_vec());
3302            let result = TestForks::remove_from_scope(&key, None, None);
3303
3304            assert_eq!(result, Ok(()));
3305        });
3306    }
3307
3308    /// Behavior: remove_from_scope returns Err(forks_not_enabled) when the
3309    /// fork graph has not been initialized.
3310    ///
3311    /// Scenario: no start() call before remove_from_scope.
3312    #[test]
3313    fn scope_handler_remove_from_scope_returns_err_when_fork_graph_not_initialized() {
3314        new_ocw_ext().execute_with(|| {
3315            register_block_hashes(0, 4);
3316            set_block(2);
3317
3318            let key = TestForks::gen_scope_item_key(&b"item".to_vec());
3319            let result = TestForks::remove_from_scope(&key, None, None);
3320
3321            assert_eq!(result, Err(DispatchError::Other("forks-not-enabled")));
3322        });
3323    }
3324}