LCOV - code coverage report
Current view: top level - discof/admin - fd_adminctl.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 43 64 67.2 %
Date: 2026-11-12 04:25:03 Functions: 2 19 10.5 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_discof_admin_fd_adminctl_h
       2             : #define HEADER_fd_src_discof_admin_fd_adminctl_h
       3             : 
       4             : #include "../../util/fd_util_base.h"
       5             : 
       6             : /* fd_adminctl_t provides APIs for out-of-band command-and-control
       7             :    signals to the firedancer process via the admin tile.  It provides a
       8             :    ring of shared-memory command slots between command processes and the
       9             :    admin tile.
      10             : 
      11             :    Each slot is owned by one CAS word that packs state, process pid,
      12             :    request sequence number, and reservation timestamp.  Command
      13             :    processes send commands to the main app process via a reserve and
      14             :    publish scheme.  A call to fd_adminctl_reserve claims a command slot;
      15             :    the command process then has exclusive write access to writing the
      16             :    command payload.  The fd_adminctl_publish publishes the command to
      17             :    the app process and effectively transfers ownership of the slot to
      18             :    the app process.  The app process will poll for a command via
      19             :    fd_adminctl_poll, process the command, and send back a result via
      20             :    fd_adminctl_complete.  The command process receives the result via
      21             :    fd_adminctl_wait which blocks on the result.  At this point, the slot
      22             :    is free again and is free to be claimed by another command process.
      23             : 
      24             :    If a command process dies while it has ownership of a slot (after
      25             :    a reservation has been made, but before a publish OR while a command
      26             :    result is available but not consumed), then other command processes
      27             :    are free to claim the slot.  If for some reason the command process
      28             :    is hung, the caller will be responsible for cleaning up and killing
      29             :    the process.
      30             : 
      31             :    All input into fd_adminctl_t must be trusted.  If the adminctl memory
      32             :    layout changes, adminctl magic must be updated. */
      33             : 
      34         252 : #define FD_ADMINCTL_CMD_IDLE                   (0UL)
      35           3 : #define FD_ADMINCTL_CMD_ADD_AUTH_VOTER         (1UL)
      36           0 : #define FD_ADMINCTL_CMD_SET_IDENTITY           (2UL)
      37           0 : #define FD_ADMINCTL_CMD_GET_IDENTITY           (3UL)
      38           0 : #define FD_ADMINCTL_CMD_REMOVE_ALL_AUTH_VOTERS (4UL)
      39           0 : #define FD_ADMINCTL_CMD_SNAP_CREATE            (5UL)
      40        1605 : #define FD_ADMINCTL_CMD_FAILOVER_PROMOTE       (6UL)
      41             : 
      42          30 : #define FD_ADMINCTL_ALIGN       (8UL)
      43          84 : #define FD_ADMINCTL_PAYLOAD_MAX (32768UL)
      44         627 : #define FD_ADMINCTL_SLOT_CNT    (4UL)
      45         156 : #define FD_ADMINCTL_STEP_MAX    (256UL) /* a step line, with its NUL */
      46           0 : #define FD_ADMINCTL_STEP_CNT    (16UL)  /* step lines a slot keeps for its command process */
      47             : 
      48             : /* Shared command result codes. */
      49         603 : #define FD_ADMINCTL_RESULT_SUCCESS              (0UL)
      50          42 : #define FD_ADMINCTL_RESULT_UNKNOWN_COMMAND      (1UL)
      51           0 : #define FD_ADMINCTL_RESULT_ABI_VERSION_MISMATCH (2UL)
      52          18 : #define FD_ADMINCTL_RESULT_ABI_SIZE_MISMATCH    (3UL)
      53           0 : #define FD_ADMINCTL_RESULT_UNSUPPORTED          (4UL)
      54             : 
      55             : /* App-specific command result codes.
      56             :    NOTE: It is important these codes start at least 5UL. */
      57             : 
      58           0 : #define FD_ADD_AUTHORIZED_VOTER_RESULT_KEYPAIR_MISMATCH     (0x1001UL)
      59           0 : #define FD_ADD_AUTHORIZED_VOTER_RESULT_MAX_AUTH_VOTERS      (0x1002UL)
      60           0 : #define FD_ADD_AUTHORIZED_VOTER_RESULT_DUPLICATE_AUTH_VOTER (0x1003UL)
      61           3 : #define FD_ADD_AUTHORIZED_VOTER_RESULT_FAILOVER_IDENTITY    (0x1004UL)
      62             : 
      63           0 : #define FD_SNAPSHOT_CREATE_RESULT_BUSY                      (0x2001UL)
      64           0 : #define FD_SNAPSHOT_CREATE_RESULT_NOT_READY                 (0x2003UL)
      65           0 : #define FD_SNAPSHOT_CREATE_RESULT_SLOT_IN_PAST              (0x2004UL)
      66             : 
      67           3 : #define FD_SET_IDENTITY_RESULT_KEYPAIR_MISMATCH             (0x3001UL)
      68           0 : #define FD_SET_IDENTITY_RESULT_INVALID_VOTE_HISTORY         (0x3002UL)
      69           0 : #define FD_SET_IDENTITY_RESULT_SAME_IDENTITY                (0x3003UL)
      70           9 : #define FD_SET_IDENTITY_RESULT_AUTHORIZED_VOTER             (0x3004UL)
      71             : 
      72             : /* Failover command results. */
      73           3 : #define FD_FAILOVER_CONTROL_RESULT_BUSY              (0x4001UL)
      74          12 : #define FD_FAILOVER_CONTROL_RESULT_NOT_HOLDER        (0x4002UL)
      75           3 : #define FD_FAILOVER_CONTROL_RESULT_IN_PROGRESS       (0x4003UL)
      76          18 : #define FD_FAILOVER_CONTROL_RESULT_HANDOFF_ABORTED   (0x4004UL)
      77           0 : #define FD_FAILOVER_CONTROL_RESULT_PEER_HOLDS        (0x4005UL)
      78           3 : #define FD_FAILOVER_CONTROL_RESULT_NO_FINAL_HISTORY  (0x4006UL)
      79           3 : #define FD_FAILOVER_CONTROL_RESULT_NO_HOLDER_ADDRESS (0x4007UL)
      80          12 : #define FD_FAILOVER_CONTROL_RESULT_REPLAY_BEHIND     (0x4008UL)
      81          27 : #define FD_FAILOVER_CONTROL_RESULT_TIMEOUT           (0x4009UL)
      82          15 : #define FD_FAILOVER_CONTROL_RESULT_PEER_RESTARTED    (0x400AUL)
      83           6 : #define FD_FAILOVER_CONTROL_RESULT_ADOPTION_FAILED   (0x400BUL)
      84           0 : #define FD_FAILOVER_CONTROL_RESULT_SWITCH_FAILED     (0x400CUL)
      85           6 : #define FD_FAILOVER_CONTROL_RESULT_HOLDS_OTHER       (0x400DUL)
      86          36 : #define FD_FAILOVER_CONTROL_RESULT_IDENTITY_CHANGED  (0x400EUL)
      87          27 : #define FD_FAILOVER_CONTROL_RESULT_HOLDER_LIVE       (0x400FUL)
      88           3 : #define FD_FAILOVER_CONTROL_RESULT_NO_PEER           (0x4010UL)
      89           3 : #define FD_FAILOVER_CONTROL_RESULT_ALREADY_HOLDS     (0x4011UL)
      90         240 : #define FD_FAILOVER_CONTROL_RESULT_HANDED_OFF        (0x4012UL)
      91             : 
      92             : struct fd_adminctl_add_auth_voter_v1 {
      93             :   ulong version; /* ==FD_ADMINCTL_ADD_AUTH_VOTER_PAYLOAD_VERSION */
      94             :   uchar keypair[ 64UL ];
      95             : };
      96             : typedef struct fd_adminctl_add_auth_voter_v1 fd_adminctl_add_auth_voter_t;
      97           3 : #define FD_ADMINCTL_ADD_AUTH_VOTER_PAYLOAD_VERSION (1UL)
      98             : 
      99             : struct fd_adminctl_snap_create_v1 {
     100             :   ulong version; /* ==FD_ADMINCTL_SNAP_CREATE_PAYLOAD_VERSION */
     101             :   ulong slot;    /* 0 to create a snapshot of the published root
     102             :                     immediately, else stop rooting at the first rooted
     103             :                     slot >= this slot and snapshot it */
     104             : };
     105             : typedef struct fd_adminctl_snap_create_v1 fd_adminctl_snap_create_t;
     106           0 : #define FD_ADMINCTL_SNAP_CREATE_PAYLOAD_VERSION (1UL)
     107             : 
     108             : struct fd_adminctl_set_identity_v4 {
     109             :   ulong version;           /* ==FD_ADMINCTL_SET_IDENTITY_PAYLOAD_VERSION */
     110             :   uchar keypair[ 64UL ];
     111             :   ulong vote_history_slot; /* scanned by the command from the vote history file, 0 if none was provided */
     112             : };
     113             : typedef struct fd_adminctl_set_identity_v4 fd_adminctl_set_identity_t;
     114             : FD_STATIC_ASSERT( sizeof(fd_adminctl_set_identity_t)<=FD_ADMINCTL_PAYLOAD_MAX, set_identity );
     115           0 : #define FD_ADMINCTL_SET_IDENTITY_PAYLOAD_VERSION (4UL)
     116             : 
     117             : struct fd_adminctl_get_identity_req_v1 {
     118             :   ulong version; /* ==FD_ADMINCTL_GET_IDENTITY_PAYLOAD_VERSION */
     119             : };
     120             : typedef struct fd_adminctl_get_identity_req_v1 fd_adminctl_get_identity_req_t;
     121             : 
     122             : struct fd_adminctl_get_identity_resp_v1 {
     123             :   ulong version; /* ==FD_ADMINCTL_GET_IDENTITY_PAYLOAD_VERSION */
     124             :   uchar identity_pubkey[ 32UL ];
     125             : };
     126             : typedef struct fd_adminctl_get_identity_resp_v1 fd_adminctl_get_identity_resp_t;
     127           0 : #define FD_ADMINCTL_GET_IDENTITY_PAYLOAD_VERSION (1UL)
     128             : 
     129             : struct fd_adminctl_remove_all_auth_voters_v1 {
     130             :   ulong version; /* ==FD_ADMINCTL_REMOVE_ALL_AUTH_VOTERS_PAYLOAD_VERSION */
     131             : };
     132             : typedef struct fd_adminctl_remove_all_auth_voters_v1 fd_adminctl_remove_all_auth_voters_t;
     133           0 : #define FD_ADMINCTL_REMOVE_ALL_AUTH_VOTERS_PAYLOAD_VERSION (1UL)
     134             : 
     135             : /* Failover commands, forwarded to the failover tile. */
     136         644 : #define FD_ADMINCTL_FAILOVER_CMD_HANDOFF   (0UL)
     137        1297 : #define FD_ADMINCTL_FAILOVER_CMD_PROMOTE   (1UL)
     138          60 : #define FD_ADMINCTL_FAILOVER_CMD_PREFLIGHT (2UL)
     139          39 : #define FD_ADMINCTL_FAILOVER_CMD_CNT       (3UL)
     140             : 
     141         542 : #define FD_ADMINCTL_FAILOVER_FLAG_YES      (1UL)
     142         809 : #define FD_ADMINCTL_FAILOVER_FLAG_FORCE    (2UL)
     143        1270 : #define FD_ADMINCTL_FAILOVER_FLAG_TAKEOVER (4UL)
     144             : 
     145             : /* The command as the operator typed it. */
     146             : static inline char const *
     147             : fd_adminctl_failover_cmd_typed( ulong cmd,
     148          27 :                                 ulong flags ) {
     149          27 :   if( FD_UNLIKELY( cmd>=FD_ADMINCTL_FAILOVER_CMD_CNT ) ) return "unknown";
     150          27 :   if( FD_LIKELY( !( flags & FD_ADMINCTL_FAILOVER_FLAG_TAKEOVER ) ) ) return "failover promote";
     151          12 :   return ( flags & FD_ADMINCTL_FAILOVER_FLAG_FORCE ) ? "failover takeover --force" : "failover takeover";
     152          27 : }
     153             : 
     154             : struct fd_adminctl_failover_req_v1 {
     155             :   ulong  version;      /* ==FD_ADMINCTL_FAILOVER_PAYLOAD_VERSION */
     156             :   ulong  cmd;          /* FD_ADMINCTL_FAILOVER_CMD_* */
     157             :   ulong  flags;        /* FD_ADMINCTL_FAILOVER_FLAG_* */
     158             :   uint   addr;         /* HANDOFF only, the machine running the identity to dial in network byte order, 0 to find it in gossip */
     159             :   ushort port;         /* HANDOFF only, the port to dial it on in host byte order, 0 for the default port */
     160             :   uchar  target[ 32 ]; /* PREFLIGHT: the identity the keypair names.  PROMOTE: the identity the command's handoff was for, zero for whatever the target is; another is refused IDENTITY_CHANGED */
     161             : };
     162             : typedef struct fd_adminctl_failover_req_v1 fd_adminctl_failover_req_t;
     163             : 
     164             : /* Optional promote payload. */
     165             : struct fd_adminctl_failover_prepare_v1 {
     166             :   fd_adminctl_failover_req_t req;
     167             :   uchar                      keypair[ 64 ];
     168             : };
     169             : typedef struct fd_adminctl_failover_prepare_v1 fd_adminctl_failover_prepare_t;
     170             : 
     171             : struct fd_adminctl_failover_resp_v1 {
     172             :   ulong version; /* ==FD_ADMINCTL_FAILOVER_PAYLOAD_VERSION */
     173             :   uchar identity[ 32 ];
     174             :   ulong slot;    /* on success the last vote cast before hand-over, ULONG_MAX for none */
     175             : };
     176             : typedef struct fd_adminctl_failover_resp_v1 fd_adminctl_failover_resp_t;
     177         246 : #define FD_ADMINCTL_FAILOVER_PAYLOAD_VERSION (1UL)
     178             : 
     179             : FD_STATIC_ASSERT( sizeof(fd_adminctl_failover_req_t )==64UL, failover_req_v1_layout  );
     180             : FD_STATIC_ASSERT( sizeof(fd_adminctl_failover_resp_t)==48UL, failover_resp_v1_layout );
     181             : 
     182             : typedef struct fd_adminctl_private fd_adminctl_t;
     183             : 
     184             : FD_PROTOTYPES_BEGIN
     185             : 
     186             : FD_FN_CONST ulong
     187             : fd_adminctl_align( void );
     188             : 
     189             : FD_FN_CONST ulong
     190             : fd_adminctl_footprint( void );
     191             : 
     192             : void *
     193             : fd_adminctl_new( void * shmem );
     194             : 
     195             : fd_adminctl_t *
     196             : fd_adminctl_join( void * shadminctl );
     197             : 
     198             : /* fd_adminctl_reserve claims a command slot and returns an identifier
     199             :    for the command reservation (index into the command buffer).  Returns
     200             :    ULONG_MAX if every slot is busy or reserved.  If a reservation is
     201             :    successful, payload_out receives a pointer into shared memory valid
     202             :    until publish completes or the reservation is abandoned by process
     203             :    death. */
     204             : 
     205             : ulong
     206             : fd_adminctl_reserve( fd_adminctl_t * adminctl,
     207             :                      void **         payload_out,
     208             :                      ulong *         payload_max_out );
     209             : 
     210             : /* fd_adminctl_publish validates the reservation and publishes the
     211             :    command to the admin tile.  This should only be called by a command
     212             :    process after a successful reservation.  After this function is
     213             :    called, the ownership of the slot is transferred to the app process.
     214             :    If a publish is made after a reservation, it will always succeed. */
     215             : 
     216             : void
     217             : fd_adminctl_publish( fd_adminctl_t * adminctl,
     218             :                      ulong           slot_id,
     219             :                      ulong           cmd_id,
     220             :                      ulong           payload_sz );
     221             : 
     222             : /* fd_adminctl_wait waits for the command identified by slot_id to
     223             :    complete and returns the command result.  This command should only be
     224             :    called by a command process after a successful publish.  After the
     225             :    function returns, the command slot will be reclaimed.  The command
     226             :    process result is returned. */
     227             : 
     228             : ulong
     229             : fd_adminctl_wait( fd_adminctl_t * adminctl,
     230             :                   ulong           slot_id );
     231             : 
     232             : /* fd_adminctl_wait_steps is fd_adminctl_wait_response that also calls
     233             :    step_fn with each step line the admin tile adds while the command
     234             :    runs, in order.  A command process that falls more than
     235             :    FD_ADMINCTL_STEP_CNT-1 lines behind skips the oldest. */
     236             : 
     237             : typedef void (* fd_adminctl_step_fn_t)( char const * step );
     238             : 
     239             : ulong
     240             : fd_adminctl_wait_steps( fd_adminctl_t *       adminctl,
     241             :                         ulong                 slot_id,
     242             :                         void *                resp,
     243             :                         ulong                 resp_max,
     244             :                         ulong *               resp_sz_out,
     245             :                         fd_adminctl_step_fn_t step_fn );
     246             : 
     247             : /* fd_adminctl_wait_response is fd_adminctl_wait for commands that also
     248             :    return a response payload.  Before the slot is reclaimed, up to
     249             :    resp_max bytes of the response payload are copied into resp and the
     250             :    response payload size is stored in resp_sz_out. */
     251             : 
     252             : ulong
     253             : fd_adminctl_wait_response( fd_adminctl_t * adminctl,
     254             :                            ulong           slot_id,
     255             :                            void *          resp,
     256             :                            ulong           resp_max,
     257             :                            ulong *         resp_sz_out );
     258             : 
     259             : /* fd_adminctl_poll checks a command slot at a time and returns the
     260             :    command id and payload if a command is available.  The command is now
     261             :    ready to be processed by the app process.  If no command is
     262             :    available, the function returns FD_ADMINCTL_CMD_IDLE.  Under the
     263             :    hood, it checks one slot at a time and advances the poll cursor.
     264             :    This function should be called repeatedly by only the main app
     265             :    process. */
     266             : 
     267             : ulong
     268             : fd_adminctl_poll( fd_adminctl_t * adminctl,
     269             :                   ulong *         slot_id_out,
     270             :                   void **         payload_out,
     271             :                   ulong *         payload_sz_out );
     272             : 
     273             : /* fd_adminctl_complete publishes the result for the command that has
     274             :    finished being processed.  It should only be called by the app
     275             :    process after the command has been processed. */
     276             : 
     277             : void
     278             : fd_adminctl_complete( fd_adminctl_t * adminctl,
     279             :                       ulong           slot_id,
     280             :                       ulong           result );
     281             : 
     282             : /* fd_adminctl_complete_response is fd_adminctl_complete for commands
     283             :    that also return a response payload.  The request payload is zeroed
     284             :    and replaced with the resp_sz bytes at resp before the result is
     285             :    published. */
     286             : 
     287             : void
     288             : fd_adminctl_complete_response( fd_adminctl_t * adminctl,
     289             :                                ulong           slot_id,
     290             :                                ulong           result,
     291             :                                void const *    resp,
     292             :                                ulong           resp_sz );
     293             : 
     294             : /* fd_adminctl_step adds a step line to the command being processed in
     295             :    slot_id, for its command process to show.  Only the app process
     296             :    calls it, between poll and complete.  The line is truncated to
     297             :    FD_ADMINCTL_STEP_MAX-1 bytes. */
     298             : 
     299             : void
     300             : fd_adminctl_step( fd_adminctl_t * adminctl,
     301             :                   ulong           slot_id,
     302             :                   char const *    step );
     303             : 
     304             : FD_PROTOTYPES_END
     305             : 
     306             : #endif /* HEADER_fd_src_discof_admin_fd_adminctl_h */

Generated by: LCOV version 1.14