LCOV - code coverage report
Current view: top level - discof/restore/utils - fd_wfs.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 28 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 96 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_discof_restore_utils_fd_wfs_h
       2             : #define HEADER_fd_src_discof_restore_utils_fd_wfs_h
       3             : 
       4             : #include "../../../util/fd_util_base.h"
       5             : 
       6             : /* Wait-for-supermajority (WFS) is the coordinated-restart boot mode.
       7             :    Given a target (slot S, bank hash H) and a nonzero expected shred
       8             :    version V, the validator attempts to load full or full+incremental
       9             :    snapshot(s) reaching slot S.  It then verifies the bank hash, and
      10             :    refuses to replay or lead until a supermajority (>=80%) of stake is
      11             :    observed back online.  This lets every validator agree on the fork
      12             :    before resuming after a hard fork.
      13             : 
      14             :    Tiles that classify a boot must invoke fd_wfs_mode() and obey the
      15             :    per-mode contract below; the snapshot selection path only needs to
      16             :    know whether WFS is configured.
      17             : 
      18             :    The classification has one input tuple (S, H, V) from config and
      19             :    one runtime input (boot_slot): the latter is the effective slot the
      20             :    validator booted at, i.e. the resulting bank slot after loading the
      21             :    snapshot(s).  WFS is configured when (S!=0 && H!=0 && V!=0).
      22             :    The classifier is a pure function of its inputs and yields exactly
      23             :    one mode:
      24             : 
      25             :      DISABLED   : not configured, behave as a normal boot.
      26             :      UNRESOLVED : configured but boot_slot not yet known.
      27             :      MATCH      : configured and boot_slot==S.  The bank is verified,
      28             :                   and tiles must wait until a supermajority of stake
      29             :                   is observed back online.
      30             :      NOOP       : configured but boot_slot>S (network has moved on).
      31             :                   Treated as a normal boot.
      32             :      ERROR      : configured but boot_slot<S and no snapshot bridged
      33             :                   the gap.  The operator must supply a snapshot at S.
      34             : 
      35             :    Specific rules:
      36             :      - boot_slot is the last manifest before FD_SSMSG_DONE, which
      37             :        ssload makes the boot bank.  Take the latest, never the
      38             :        maximum: a reset can legitimately lower the slot.
      39             :      - Booting from genesis with WFS configured is not allowed (ERROR).
      40             :      - WFS completion is signalled once.  Consumers MUST be idempotent:
      41             :        a repeat signal after completion is dropped.
      42             :      - In MATCH mode the leader gate (the requirement that the
      43             :        validator's vote account is rooted before it may lead) is
      44             :        suppressed, otherwise a coordinated restart deadlocks: no
      45             :        validator may lead, so no vote can ever root.  The suppression
      46             :        is permanent for the lifetime of the process; it is not undone
      47             :        when WFS completes.
      48             : 
      49             :     Regarding snapshot(s) (down)load:
      50             :      - A coordinated WFS restart implies moving backward in slots, and
      51             :        a change in V.  That means that any local snapshot on disk from
      52             :        V_old could correspond to slot>S, i.e. it would appear to be in
      53             :        the future.
      54             :      - When WFS uses a full-only snapshot, the full snapshot's shred
      55             :        version is V.  However, when full+incr is used, the full
      56             :        snapshot's shred version might be V_old, and only the
      57             :        incremental's is V.  This is why the shred version is verified
      58             :        once on the boot bank after the last manifest, never
      59             :        per-snapshot.
      60             :      - At boot time, and especially around WFS, there is no trusted
      61             :        way to determine whether the network has moved past slot S.
      62             :        The validator needs to boot to observe the network, but it
      63             :        needs to know the network state to decide how to boot.
      64             :        The alternatives are to treat WFS configuration as:
      65             :          - strict:
      66             :              - if WFS is configured, the validator only boots at slot
      67             :                S, otherwise it crashes.  Only mode MATCH is supported.
      68             :              - Guarantees: (S, H, V) are verified.
      69             :              - Operational nuances: the operator must remove the WFS
      70             :                config right after the network moves past WFS, otherwise
      71             :                a subsequent validator restart will fail.
      72             :          - relaxed (Agave's behavior):
      73             :              - if WFS is configured, the validator has the option to
      74             :                treat it as a NOOP if it believes that the network has
      75             :                already moved forward.
      76             :              - Guarantees:
      77             :                  - in MATCH: (S, H, V) are verified.
      78             :                  - in NOOP: only (V) is verified;  (S, H) are skipped!
      79             :              - Operational nuances: during WFS, the operator must
      80             :                carefully choose "trusted" download sources (or copy
      81             :                the snapshots) and delete obsolete local snapshots.
      82             :        Firedancer chooses to follow Agave's behavior (relaxed).
      83             :      - The validator chooses between the local snapshot(s) and what it
      84             :        could download, keeping the local ones while they are recent
      85             :        enough.  WFS adds three constraints: a local snapshot short of
      86             :        S is not kept when downloading reaches S, a local incremental
      87             :        short of S is never kept (because it would be the boot), and a
      88             :        peer reaching S is preferred over one that cannot.
      89             :      - When WFS is configured and a candidate full snapshot is behind
      90             :        slot S, [snapshots.incremental_snapshots] is overridden to true
      91             :        so an incremental can reach S.  Provisioning is separate and
      92             :        always reserves for incrementals, since it runs before the mode
      93             :        is knowable (fd_wfs_needs_incr).
      94             : 
      95             :    In short: selection is WFS-agnostic, classification is WFS-aware.
      96             :    WFS contributes a constraint, never an objective; the mode above is
      97             :    a verdict on whatever slot selection landed on. */
      98             : 
      99           0 : #define FD_WFS_MODE_DISABLED   (0)
     100           0 : #define FD_WFS_MODE_UNRESOLVED (1)
     101           0 : #define FD_WFS_MODE_MATCH      (2)
     102           0 : #define FD_WFS_MODE_NOOP       (3)
     103           0 : #define FD_WFS_MODE_ERROR      (4)
     104             : 
     105             : FD_PROTOTYPES_BEGIN
     106             : 
     107             : /* fd_wfs_configured returns 1 iff the config enables WFS.  Arguments
     108             :    slot, hash_is_zero, and shred_version come from consensus config.
     109             :    All three conditions must hold together for WFS to be enabled.
     110             : 
     111             :    hash_is_zero is derived via string-empty check in topology.c and via
     112             :    byte-zero memcmp in tiles.  These are equivalent because config
     113             :    rejects the all-zeros base58 encoding. */
     114             : 
     115             : FD_FN_CONST static inline int
     116             : fd_wfs_configured( ulong slot,
     117             :                    int   hash_is_zero,
     118           0 :                    ulong shred_version ) {
     119           0 :   return slot!=0UL && !hash_is_zero && shred_version!=0UL;
     120           0 : }
     121             : 
     122             : /* fd_wfs_needs_incr returns whether to provision for incrementals;
     123             :    WFS forces it on, as the mode is unknowable before any load. */
     124             : 
     125             : FD_FN_CONST static inline int
     126             : fd_wfs_needs_incr( int   incremental_snapshots,
     127             :                    ulong slot,
     128             :                    int   hash_is_zero,
     129           0 :                    ulong shred_version ) {
     130           0 :   return incremental_snapshots || fd_wfs_configured( slot, hash_is_zero, shred_version );
     131           0 : }
     132             : 
     133             : /* fd_wfs_mode classifies WFS given the config triple and boot_slot,
     134             :    the effective boot slot (the bank slot of the last snapshot loaded).
     135             :    Pass boot_slot==ULONG_MAX until the boot snapshot is known
     136             :    (yields UNRESOLVED when configured). */
     137             : 
     138             : FD_FN_CONST static inline int
     139             : fd_wfs_mode( ulong slot,
     140             :              int   hash_is_zero,
     141             :              ulong shred_version,
     142           0 :              ulong boot_slot ) {
     143           0 :   if( !fd_wfs_configured( slot, hash_is_zero, shred_version ) ) return FD_WFS_MODE_DISABLED;
     144           0 :   if( boot_slot==ULONG_MAX ) return FD_WFS_MODE_UNRESOLVED;
     145           0 :   if( boot_slot==slot      ) return FD_WFS_MODE_MATCH;
     146           0 :   if( boot_slot>slot       ) return FD_WFS_MODE_NOOP;
     147           0 :   return FD_WFS_MODE_ERROR;
     148           0 : }
     149             : 
     150             : FD_FN_CONST static inline char const *
     151           0 : fd_wfs_mode_str( int mode ) {
     152           0 :   switch( mode ) {
     153           0 :     case FD_WFS_MODE_DISABLED:   return "disabled";
     154           0 :     case FD_WFS_MODE_UNRESOLVED: return "unresolved";
     155           0 :     case FD_WFS_MODE_MATCH:      return "match";
     156           0 :     case FD_WFS_MODE_NOOP:       return "no-op";
     157           0 :     case FD_WFS_MODE_ERROR:      return "error";
     158           0 :     default:                     return "unknown";
     159           0 :   }
     160           0 : }
     161             : 
     162             : FD_PROTOTYPES_END
     163             : 
     164             : #endif /* HEADER_fd_src_discof_restore_utils_fd_wfs_h */

Generated by: LCOV version 1.14