LCOV - code coverage report
Current view: top level - discof/repair - fd_repair.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 31 45 68.9 %
Date: 2026-09-17 04:28:31 Functions: 6 115 5.2 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_discof_repair_fd_repair_h
       2             : #define HEADER_fd_src_discof_repair_fd_repair_h
       3             : 
       4             : /* fd_repair implements the Solana Repair protocol.  In a nutshell,
       5             :    Repair is a protocol for recovering shreds that the validator is
       6             :    expecting but has not received from Turbine.  Neither the logic for
       7             :    how the validator determines it should be expecting a shred nor the
       8             :    logic for determining which peer validator to request the shred from
       9             :    is implemented in this file (see fd_policy.h instead); rather, this
      10             :    is an implementation of the protocol itself for requesting shreds
      11             :    from other validators.
      12             : 
      13             :    The repair protocol supports seven different message types on the
      14             :    client side:
      15             : 
      16             :    - Pong( ping_token )
      17             : 
      18             :      This is a response message to address validation via a Ping-Pong
      19             :      protocol.  When a validator receives a repair request from another
      20             :      validator it does not recognize, it will ignore the request and
      21             :      instead respond with its own Ping message to the requesting
      22             :      validator.  The Ping contains a 32-byte token that the requesting
      23             :      validator needs to hash and sign as part of a Pong response.  The
      24             :      scheme is as follows: the Ping token is concatenated with the
      25             :      prefix "SOLANA_PING_PONG", which is then piped in as the preimage
      26             :      into SHA-256.  The resulting hash is then signed and the signature
      27             :      along with the actual hash is packed into a Pong.
      28             : 
      29             :    - Shred( slot, shred_idx )
      30             : 
      31             :      This is a request for a specific shred in the provided slot.  The
      32             :      (slot, shred index) generally uniquely identifies a shred except in
      33             :      certain exceptional conditions (equivocation).  The responding
      34             :      validator will return the shred if it has it.
      35             : 
      36             :    - HighestShred( slot, shred_idx )
      37             : 
      38             :      This is a request for the highest shred in the provided slot that
      39             :      is greater than or equal to shred_idx, or a lower shred marked as
      40             :      the last shred in the slot.  Note this is not necessarily the last
      41             :      shred in the slot, as it depends on what the responding validator
      42             :      has available.  The responding validator will return the highest
      43             :      shred it has that meets the condition.
      44             : 
      45             :    - Orphan( slot )
      46             : 
      47             :      This is a request for up to 11 shreds, where each shred is the
      48             :      prior one's ancestor, beginning from and including slot.  For
      49             :      example, an orphan request for slot 10 will return the highest
      50             :      shred for slots 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 and 0 (assuming
      51             :      no skips).
      52             : 
      53             :   The below are repair request types introduced by Alpenglow.
      54             : 
      55             :    - ParentAndFecSetCount( slot, block_id )
      56             : 
      57             :      This is a request for the parent slot and FEC set count for the
      58             :      provided block_id.  The responding validator will return the
      59             :      parent slot and FEC set count it has for the provided block_id.
      60             : 
      61             :    - FecSetRoot( slot, block_id, fec_set_idx )
      62             : 
      63             :      This is a request for the FEC set root for the provided block_id
      64             :      and FEC set index.  The responding validator will return the FEC
      65             :      set root it has for the provided block_id and FEC set index.
      66             : 
      67             :    - ShredForBlockId( slot, shred_idx, block_id )
      68             : 
      69             :      This is a request for the shred at the provided slot, shred index
      70             :      and block_id.  The responding validator will return the shred it
      71             :      has for the provided slot, shred index and block_id.
      72             : 
      73             :     All 7 repair request types are prefixed with a common header of from
      74             :     pubkey, to pubkey, ulong timestamp and uint nonce.  The timestamp is
      75             :     a standard UNIX epoch (milliseconds since 1970-01-01T00:00:00Z) and
      76             :     the nonce is echoed back by the responding validator in the repair
      77             :     response.  Unlike a typical cryptographic nonce that prevents replay
      78             :     attacks, the repair server implementation ignores the nonce and this
      79             :     implementation leaves it up to the calling application to manage the
      80             :     nonce.  Note the 4 nonce bytes are appended after the end of a shred
      81             :     in a repair response.
      82             : 
      83             :     All communication across the wire is done with bincode serialization
      84             :     encoding. */
      85             : 
      86             : #include "../../ballet/ed25519/fd_ed25519.h"
      87             : #include "../../flamenco/fd_flamenco_base.h"
      88             : #include "../../ballet/shred/fd_shred.h"
      89             : #include "../../disco/shred/fd_fec_set.h"
      90             : 
      91             : /* FD_REPAIR_KIND_{PONG,SHRED,HIGHEST_SHRED,ORPHAN,ANCESTOR_HASHES} specify
      92             :   discriminant values the protocol uses to distinguish message types. */
      93             : 
      94           0 : #define FD_REPAIR_KIND_PING            (0U)
      95             : #define AG_REPAIR_KIND_PING            (2U)
      96             : 
      97          33 : #define FD_REPAIR_KIND_PONG            (7U)
      98       23772 : #define FD_REPAIR_KIND_SHRED           (8U)
      99        6519 : #define FD_REPAIR_KIND_HIGHEST_SHRED   (9U)
     100        6336 : #define FD_REPAIR_KIND_ORPHAN          (10U)
     101           0 : #define FD_REPAIR_KIND_ANCESTOR_HASHES (11U)
     102        6951 : #define AG_REPAIR_KIND_PARENT_FEC_COUNT   (12U)
     103        7014 : #define AG_REPAIR_KIND_FEC_ROOT           (13U)
     104       16725 : #define AG_REPAIR_KIND_SHRED_FOR_BLOCK_ID (14U)
     105             : 
     106             : /* fd_repair_pong describes the schema of a Pong. */
     107             : 
     108             : struct __attribute__((packed)) fd_repair_pong {
     109             :   fd_pubkey_t      from; /* pubkey of the validator responding with the pong */
     110             :   fd_hash_t        hash; /* sha-256 hash generated from a ping hash */
     111             :   fd_ed25519_sig_t sig;  /* from's signature over the preceding hash field */
     112             : };
     113             : typedef struct fd_repair_pong fd_repair_pong_t;
     114             : 
     115             : /* REQ_HDR defines the common header of Repair request types. */
     116             : 
     117             : #define REQ_HDR                                                                     \
     118             :   fd_ed25519_sig_t sig;   /* ed25519 signature over all the subsequent fields */    \
     119             :   fd_pubkey_t      from;  /* pubkey of the validator that sent the request */       \
     120             :   fd_pubkey_t      to;    /* pubkey of the validator that is being requested */     \
     121             :   ulong            ts;    /* timestamp in milliseconds since unix epoch */          \
     122             :   uint             nonce; /* nonce to be echoed back by the responding validator */ \
     123             : 
     124             : /* fd_repair_shred requests the specific shred at slot and shred_idx
     125             :    from a peer validator. */
     126             : 
     127             : /* TODO: remove _req suffix from below */
     128             : struct __attribute__((packed)) fd_repair_shred_req {
     129             :   REQ_HDR
     130             :   ulong slot;
     131             :   ulong shred_idx;
     132             : };
     133             : typedef struct fd_repair_shred_req fd_repair_shred_req_t;
     134             : 
     135             : /* fd_repair_highest_shred requests the highest shred in slot greater
     136             :    than shred_idx that a peer validator has.  Note this is not
     137             :    necessarily the last shred in the slot, as it depends on what the
     138             :    peer has available. */
     139             : 
     140             : struct __attribute__((packed)) fd_repair_highest_shred_req {
     141             :   REQ_HDR
     142             :   ulong slot;
     143             :   ulong shred_idx;
     144             : };
     145             : typedef struct fd_repair_highest_shred_req fd_repair_highest_shred_req_t;
     146             : 
     147             : /* fd_repair_orphan requests the ancestors of slot (an "orphaned" slot)
     148             :    from a peer validator.  The peer can respond with shreds for up to 11
     149             :    slots (including the requested slot itself), where every shred is
     150             :    the highest shred for that slot. */
     151             : 
     152             : struct __attribute__((packed)) fd_repair_orphan_req {
     153             :   REQ_HDR
     154             :   ulong slot;
     155             : };
     156             : typedef struct fd_repair_orphan_req fd_repair_orphan_req_t;
     157             : 
     158             : struct __attribute__((packed)) ag_repair_parent_fec_count_req {
     159             :   REQ_HDR
     160             :   ulong slot;
     161             :   fd_hash_t block_id;
     162             : };
     163             : typedef struct ag_repair_parent_fec_count_req ag_repair_parent_fec_count_req_t;
     164             : 
     165             : struct __attribute__((packed)) ag_repair_fec_root_req {
     166             :   REQ_HDR
     167             :   ulong slot;
     168             :   fd_hash_t block_id;
     169             :   uint fec_set_idx;
     170             : };
     171             : typedef struct ag_repair_fec_root_req ag_repair_fec_root_req_t;
     172             : 
     173             : struct __attribute__((packed)) ag_repair_shred_block_id_req {
     174             :   REQ_HDR
     175             :   ulong     slot;
     176             :   uint      shred_idx;
     177             :   fd_hash_t block_id;
     178             : };
     179             : typedef struct ag_repair_shred_block_id_req ag_repair_shred_block_id_req_t;
     180             : 
     181             : /* fd_repair_req_header gives a view into the header of the SHRED,
     182             :    HIGHEST_SHRED, and ORPHAN request types. */
     183             : struct __attribute__((packed)) fd_repair_req_header {
     184             :   REQ_HDR
     185             : };
     186             : typedef struct fd_repair_req_header fd_repair_req_header_t;
     187             : 
     188             : /* fd_repair_msg_t defines the schema of all Repair message types. */
     189             : 
     190             : struct __attribute__((packed)) fd_repair_msg {
     191             :   uint kind; /* FD_REPAIR_KIND_{...} */
     192             :   union {
     193             :     fd_repair_pong_t              pong;
     194             :     fd_repair_shred_req_t         shred;
     195             :     fd_repair_highest_shred_req_t highest_shred;
     196             :     fd_repair_orphan_req_t        orphan;
     197             :     fd_repair_req_header_t        header;
     198             : 
     199             :     ag_repair_parent_fec_count_req_t   parent_fec_set_count;
     200             :     ag_repair_fec_root_req_t           fec_set_root;
     201             :     ag_repair_shred_block_id_req_t shred_block_id;
     202             :   };
     203             : };
     204             : typedef struct fd_repair_msg fd_repair_msg_t;
     205             : 
     206             : struct __attribute__((packed)) fd_repair_ping {
     207             :   uint kind;
     208             :   fd_repair_pong_t ping;
     209             : };
     210             : typedef struct fd_repair_ping fd_repair_ping_t;
     211             : 
     212             : /* alpenglow blockid repair response types */
     213             : 
     214             : typedef uchar ag_proof_node_t[FD_SHRED_MERKLE_NODE_SZ];
     215             : #define AG_MAX_FEC_PROOF_NODE_CNT  (1U + (63 - __builtin_clzl( FD_SHRED_BLK_MAX_RAISED/FD_FEC_SHRED_CNT ))) /* 24 = 1 node for parent block_id + 23 for log2 of the most FEC sets any configuration allows */
     216             : 
     217             : struct ag_parent_fec_count_res {
     218             :   uint      fec_set_count;
     219             :   ulong     parent_slot;
     220             :   fd_hash_t parent_block_id;
     221             :   ulong     proof_len; /* number of proof nodes in parent_proof */
     222             :   ag_proof_node_t parent_proof[ AG_MAX_FEC_PROOF_NODE_CNT ]; /* variable-length */
     223             : };
     224             : typedef struct ag_parent_fec_count_res ag_parent_fec_count_res_t;
     225             : struct ag_fec_root_res {
     226             :   ag_proof_node_t root; /* 20-byte FEC-set merkle root prefix */
     227             :   ulong     proof_len; /* number of proof nodes in fec_proof */
     228             :   ag_proof_node_t fec_proof[ AG_MAX_FEC_PROOF_NODE_CNT ]; /* variable-length */
     229             : };
     230             : typedef struct ag_fec_root_res ag_fec_root_res_t;
     231             : 
     232          90 : #define AG_REPAIR_RESPONSE_PARENT_FEC_SET_COUNT (0U)
     233         186 : #define AG_REPAIR_RESPONSE_FEC_SET_ROOT         (1U)
     234             : struct ag_repair_response {
     235             :   uint kind;
     236             :   union {
     237             :     ag_parent_fec_count_res_t parent_fec_set_res;
     238             :     ag_fec_root_res_t         fec_set_root;
     239             :   };
     240             :   uint nonce;
     241             : };
     242             : typedef struct ag_repair_response ag_repair_response_t;
     243             : 
     244             : /* Max payload size of a blockid repair response */
     245             : #define AG_REPAIR_RESPONSE_MAX_SZ (sizeof(ag_repair_response_t))
     246             : 
     247             : /* FD_REPAIR_PONG_PREIMAGE_PREFIX is used by Repair's Ping-Pong protocol.
     248             :    Both a Ping and Pong contain a hash token, that is generated from a
     249             :    preimage prefixed with the below.  */
     250             : 
     251           0 : #define FD_REPAIR_PONG_PREIMAGE_PREFIX "SOLANA_PING_PONG"
     252           0 : #define FD_REPAIR_PONG_PREIMAGE_SZ (48UL)
     253             : 
     254             : /* FD_REPAIR_MAX_PREIMAGE_SZ is the maximum size of a preimage for a
     255             :    repair request. This is the size of the largest repair request
     256             :    (highest_shred or shred) without the signature. */
     257             : 
     258           0 : #define FD_REPAIR_MAX_PREIMAGE_SZ (sizeof(fd_repair_msg_t) - sizeof(fd_ed25519_sig_t))
     259             : 
     260             : static const fd_pubkey_t null_pubkey = {{ 0 }};
     261             : 
     262             : /* fd_repair_sign_fn defines the function signature for a user-provided
     263             :    signing callback. */
     264             : 
     265             : typedef void (fd_repair_sign_fn)( void * ctx, fd_repair_msg_t * msg, uchar * sig );
     266             : 
     267             : struct fd_repair {
     268             :   fd_pubkey_t         identity_key; /* validator identity key */
     269             :   fd_repair_sign_fn * sign_fn;      /* user-provided signing callback */
     270             :   void *              sign_ctx;     /* user-provided context for signing callback */
     271             :   fd_repair_msg_t     msg;          /* buffer for outgoing repair requests */
     272             : };
     273             : typedef struct fd_repair fd_repair_t;
     274             : 
     275             : /* Constructors */
     276             : 
     277             : /* fd_repair_{align,footprint} return the required alignment and
     278             :    footprint of a memory region suitable for use as repair.  Declaration
     279             :    friendly (e.g. a memory region declared as "fd_repair_t repair[1];"
     280             :    will automatically have the needed alignment and footprint). */
     281             : 
     282             : FD_FN_CONST static inline ulong
     283         135 : fd_repair_align( void ) {
     284         135 :   return alignof(fd_repair_t);
     285         135 : }
     286             : 
     287             : FD_FN_CONST static inline ulong
     288          90 : fd_repair_footprint( void ) {
     289          90 :   return sizeof(fd_repair_t);
     290          90 : }
     291             : 
     292             : /* fd_repair_new formats an unused memory region for use as a repair.
     293             :    mem is a non-NULL pointer to this region in the local address space
     294             :    with the required footprint and alignment.
     295             :    Initializes repair with the public identity key. */
     296             : 
     297             : void *
     298             : fd_repair_new( void * shmem, fd_pubkey_t * identity_key );
     299             : 
     300             : /* fd_repair_join joins the caller to the repair.  repair points to the
     301             :    first byte of the memory region backing the repair in the caller's
     302             :    address space.  Returns a pointer in the local address space to
     303             :    repair on success. */
     304             : 
     305             : fd_repair_t *
     306             : fd_repair_join( void * repair );
     307             : 
     308             : /* fd_repair_leave leaves a current local join.  Returns a pointer to
     309             :    the underlying shared memory region on success and NULL on failure
     310             :    (logs details).  Reasons for failure include repair is NULL. */
     311             : 
     312             : void *
     313             : fd_repair_leave( fd_repair_t const * repair );
     314             : 
     315             : /* fd_repair_delete unformats a memory region used as a repair.  Assumes
     316             :    only the nobody is joined to the region.  Returns a pointer to the
     317             :    underlying shared memory region or NULL if used obviously in error
     318             :    (e.g. repair is obviously not a repair ... logs details).  The
     319             :    ownership of the memory region is transferred to the caller. */
     320             : 
     321             : void *
     322             : fd_repair_delete( void * repair );
     323             : 
     324             : /* fd_repair_ping_de and fd_repair_ping_ser deserialize and serialize a
     325             :    ping message. */
     326             : int
     327             : fd_repair_ping_de( fd_repair_ping_t * ping,
     328             :                    uchar const      * buf,
     329             :                    ulong              buf_sz );
     330             : 
     331             : int
     332             : fd_repair_ping_ser( fd_repair_ping_t const * ping,
     333             :                     uchar                    buf[static sizeof(fd_repair_ping_t)],
     334             :                     ulong                    buf_sz );
     335             : 
     336             : /* fd_repair_{pong,shred,highest_shred,orphan} creates and returns a
     337             :    pointer to a serialized {Pong,Shred,HighestShred,Orphan} message.
     338             :    Does not require the caller to provide memory, as Repair itself
     339             :    maintains a dedicated memory region (repair->msg) for buffering
     340             :    requests.  Assumes repair->msg is not already buffering an existing
     341             :    request and can be overwritten.  Returns a pointer to repair->msg,
     342             :    cannot fail. */
     343             : 
     344             : fd_repair_msg_t * fd_repair_pong         ( fd_repair_t * repair, fd_hash_t * ping_token );
     345             : fd_repair_msg_t * fd_repair_shred        ( fd_repair_t * repair, fd_pubkey_t const * to, ulong ts, uint nonce, ulong slot, ulong shred_idx );
     346             : fd_repair_msg_t * fd_repair_highest_shred( fd_repair_t * repair, fd_pubkey_t const * to, ulong ts, uint nonce, ulong slot, ulong shred_idx );
     347             : fd_repair_msg_t * fd_repair_orphan       ( fd_repair_t * repair, fd_pubkey_t const * to, ulong ts, uint nonce, ulong slot );
     348             : 
     349             : fd_repair_msg_t *
     350             : ag_repair_parent_and_fec_set_count( fd_repair_t * repair, fd_pubkey_t const * to, ulong ts, uint nonce, ulong slot, fd_hash_t const * block_id );
     351             : 
     352             : fd_repair_msg_t *
     353             : ag_repair_fec_set_root( fd_repair_t * repair, fd_pubkey_t const * to, ulong ts, uint nonce, ulong slot, fd_hash_t const * block_id, uint fec_set_idx );
     354             : 
     355             : fd_repair_msg_t *
     356             : ag_repair_shred_block_id( fd_repair_t * repair, fd_pubkey_t const * to, ulong ts, uint nonce, ulong slot, fd_hash_t const * block_id, uint shred_idx );
     357             : 
     358             : /* ag_repair_response_de deserializes a general Alpenglow repair metadata
     359             :    response from buf into response.
     360             : 
     361             :      u32 tag: 0=ParentFecSetCount, 1=FecSetRoot
     362             :      tag 0: u32 fec_set_count, u64 parent_slot, u8[32] parent_block_id,
     363             :             u64 proof_sz, u8[proof_sz] proof
     364             :      tag 1: u8[32] fec_set_root, u64 proof_sz, u8[proof_sz] proof
     365             :      u32 nonce
     366             : 
     367             :    Proofs are a concatenation of 20-byte merkle nodes (proof_sz must be
     368             :    a multiple of FD_SHRED_MERKLE_NODE_SZ).  Ping responses (tag 2) are
     369             :    not handled here; they are the same sz as legacy repair pings and
     370             :    should be routed to the ping path.  fec_set_max bounds the FEC sets
     371             :    a block may hold (max_shreds_per_block/FD_FEC_SHRED_CNT).  Returns 0
     372             :    on success and -1 if the response is malformed.
     373             :    Does NOT verify the merkle proofs. */
     374             : int
     375             : ag_repair_response_de( ag_repair_response_t * response,
     376             :                        uchar const *          buf,
     377             :                        ulong                  buf_sz,
     378             :                        ulong                  fec_set_max );
     379             : 
     380             : /* ag_repair_parent_fec_count_verify / ag_repair_fec_set_root_verify
     381             :    verifies a deserialized Alpenglow repair metadata response against
     382             :    the block id (double-merkle root) the request was made for.  Both
     383             :    return 0 if the response's merkle proof is valid for block_id, -1
     384             :    otherwise. */
     385             : int
     386             : ag_repair_parent_fec_count_verify( ag_parent_fec_count_res_t const * res,
     387             :                                    fd_hash_t const *                 block_id );
     388             : int
     389             : ag_repair_fec_set_root_verify( ag_fec_root_res_t const * res,
     390             :                                fd_hash_t const *         block_id,
     391             :                                uint                      fec_set_idx );
     392             : 
     393             : /* fd_repair_sz returns the bincode-serialized sz of msg. */
     394             : 
     395             : static inline ulong
     396        4302 : fd_repair_sz( fd_repair_msg_t const * msg ) {
     397        4302 :    switch( msg->kind ) {
     398           0 :      case FD_REPAIR_KIND_PONG:               return sizeof(uint) + sizeof(fd_repair_pong_t);
     399          72 :      case FD_REPAIR_KIND_SHRED:              return sizeof(uint) + sizeof(fd_repair_shred_req_t);
     400          54 :      case FD_REPAIR_KIND_HIGHEST_SHRED:      return sizeof(uint) + sizeof(fd_repair_highest_shred_req_t);
     401           0 :      case FD_REPAIR_KIND_ORPHAN:             return sizeof(uint) + sizeof(fd_repair_orphan_req_t);
     402         120 :      case AG_REPAIR_KIND_PARENT_FEC_COUNT:   return sizeof(uint) + sizeof(ag_repair_parent_fec_count_req_t);
     403         210 :      case AG_REPAIR_KIND_FEC_ROOT:           return sizeof(uint) + sizeof(ag_repair_fec_root_req_t);
     404        3846 :      case AG_REPAIR_KIND_SHRED_FOR_BLOCK_ID: return sizeof(uint) + sizeof(ag_repair_shred_block_id_req_t);
     405           0 :      default:                                FD_LOG_ERR(( "Unhandled repair kind %u", msg->kind ));
     406        4302 :    }
     407        4302 : }
     408             : 
     409             : /* preimage_pong creates the signing payload for a pong message. */
     410             : 
     411             : static inline uchar *
     412             : preimage_pong( fd_hash_t const * ping_token,
     413           0 :                uchar             preimage_buf[ static FD_REPAIR_PONG_PREIMAGE_SZ ] ) {
     414           0 :   ulong prefix_sz = sizeof(FD_REPAIR_PONG_PREIMAGE_PREFIX) - 1 /* subtract NUL */;
     415           0 :   memcpy( preimage_buf,             FD_REPAIR_PONG_PREIMAGE_PREFIX, prefix_sz         );
     416           0 :   memcpy( preimage_buf + prefix_sz, ping_token,                     sizeof(fd_hash_t) );
     417           0 :   return preimage_buf;
     418           0 : }
     419             : 
     420             : /* preimage_req takes a repair request populated with all fields except
     421             :    for the signature, and returns a pointer to a preimage that can be
     422             :    signed.  Modifies the msg in place.
     423             : 
     424             :    At the start of this function, the repair_msg_t should contain
     425             : 
     426             :      [ discriminant ] [ empty sig ] [ repair request fields ]
     427             :      ^                ^             ^
     428             :      0                4             68
     429             : 
     430             :      https://github.com/solana-labs/solana/blob/master/core/src/repair/serve_repair.rs#L1258
     431             : 
     432             :      We want to sign over
     433             :      [ discriminant ] [ payload ]
     434             :       ^                ^
     435             :       buffer           buffer+4
     436             : 
     437             :    We can do this without using any extra memory copying the discriminant
     438             :    to the last 4 bytes of the sig field, and returning a pointer to
     439             :    that copied location.  The sig field should be overwritten with the
     440             :    actual signature value later, else the fd_repair_msg_t will be
     441             :    incorrect. */
     442             : 
     443             : static inline uchar *
     444        2151 : preimage_req( fd_repair_msg_t * msg, ulong * preimage_sz ) {
     445        2151 :   uchar * preimage = (uchar *)fd_type_pun(msg);
     446        2151 :   preimage += sizeof(fd_ed25519_sig_t);
     447        2151 :   FD_STORE( uint, preimage, msg->kind ); /* copy discriminant over */
     448        2151 :   *preimage_sz = fd_repair_sz( msg ) - sizeof(fd_ed25519_sig_t);
     449        2151 :   return preimage;
     450        2151 : }
     451             : #endif /* HEADER_fd_src_discof_repair_fd_repair_h */

Generated by: LCOV version 1.14