LCOV - code coverage report
Current view: top level - choreo/eqvoc - fd_eqvoc.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 6 14 42.9 %
Date: 2026-02-14 05:50:46 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef HEADER_fd_src_choreo_eqvoc_fd_eqvoc_h
       2             : #define HEADER_fd_src_choreo_eqvoc_fd_eqvoc_h
       3             : 
       4             : #include "../fd_choreo_base.h"
       5             : #include "../../ballet/shred/fd_shred.h"
       6             : #include "../../flamenco/leaders/fd_leaders.h"
       7             : #include "../../flamenco/gossip/fd_gossip_types.h"
       8             : 
       9             : /* fd_eqvoc presents an API for detecting and sending & receiving proofs
      10             :    of equivocation.
      11             : 
      12             :    APIs prefixed with `fd_eqvoc_proof` relate to constructing and
      13             :    verifying equivocation proofs from shreds.
      14             : 
      15             :    APIs prefixed with `fd_eqvoc_fec` relate to shred and FEC set
      16             :    metadata indexing to detect equivocating shreds.
      17             : 
      18             :    Equivocation is when a shred producer produces two or more versions
      19             :    of a shred for the same (slot, idx).  An equivocation proof comprises
      20             :    two shreds that conflict in a way that imply the shreds' producer
      21             :    equivocated.
      22             : 
      23             :    The proof can be both direct and indirect (implied).  A direct proof,
      24             :    for example, contains two shreds with the same slot and shred index
      25             :    but different data payloads.  An indirect proof contains two shreds
      26             :    with different shred indices, and the metadata on the shreds implies
      27             :    there must be two or more versions of a block for that slot.  See
      28             :    `construct_proof` or `verify_proof` in fd_eqvoc.c for more details.
      29             : 
      30             :    Every shred in a FEC set must have the same signature, so a different
      31             :    value in the signature field would indicate equivocation.  Note in
      32             :    the case of merkle shreds, the shred signature is signed on the FEC
      33             :    set's merkle root, so every shred in the same FEC set must have the
      34             :    same signature. */
      35             : 
      36             : /* FD_EQVOC_USE_HANDHOLDING:  Define this to non-zero at compile time
      37             :    to turn on additional runtime checks and logging. */
      38             : 
      39             : #ifndef FD_EQVOC_USE_HANDHOLDING
      40             : #define FD_EQVOC_USE_HANDHOLDING 1
      41             : #endif
      42             : 
      43             : /* zero means nothing to do (no proof has been verified) */
      44             : 
      45           9 : #define FD_EQVOC_SUCCESS (0) /* shreds do not equivocate */
      46             : 
      47             : /* positive error codes means there is a proof of equivocation */
      48             : 
      49          18 : #define FD_EQVOC_VERIFIED_MERKLE  (1)
      50           9 : #define FD_EQVOC_VERIFIED_META    (2)
      51           9 : #define FD_EQVOC_VERIFIED_LAST    (3)
      52           9 : #define FD_EQVOC_VERIFIED_OVERLAP (4)
      53           9 : #define FD_EQVOC_VERIFIED_CHAINED (5)
      54             : 
      55             : /* negative error codes mean the shreds in the proof were not valid inputs */
      56             : 
      57           0 : #define FD_EQVOC_ERR_SER     (-1) /* invalid serialization */
      58           0 : #define FD_EQVOC_ERR_SLOT    (-2) /* different slot */
      59           0 : #define FD_EQVOC_ERR_VERSION (-3) /* different shred version */
      60           0 : #define FD_EQVOC_ERR_TYPE    (-4) /* wrong shred type (must be chained merkle) */
      61           0 : #define FD_EQVOC_ERR_MERKLE  (-5) /* failed to derive merkle root */
      62           0 : #define FD_EQVOC_ERR_SIG     (-6) /* failed to sigverify */
      63             : 
      64             : /* FD_EQVOC_CHUNK_CNT: the count of chunks is hardcoded because Agave
      65             :    discards any chunks where count != 3 (even though technically the
      66             :    schema supports it).
      67             : 
      68             :    See: https://github.com/anza-xyz/agave/blob/v3.1/gossip/src/duplicate_shred_handler.rs#L21 */
      69             : 
      70           0 : #define FD_EQVOC_CHUNK_CNT (3)
      71             : 
      72             : /* FD_EQVOC_CHUNK_SZ: the size of data in each chunk Firedancer produces
      73             :                       in a DuplicateShred message is derived below.
      74             : 
      75             :    IPv6 MTU - IP / UDP headers = 1232
      76             :    DuplicateShredMaxPayloadSize = 1232 - 115
      77             :    DuplicateShred headers = 63
      78             : 
      79             :    This is not enforce on receive (Firedancer will accept smaller chunk
      80             :    payloads).
      81             : 
      82             :    See: https://github.com/anza-xyz/agave/blob/v2.0.3/gossip/src/cluster_info.rs#L113 */
      83             : 
      84           0 : #define FD_EQVOC_CHUNK_SZ  (1232UL - 115UL - 63UL)
      85             : FD_STATIC_ASSERT( FD_EQVOC_CHUNK_SZ==FD_GOSSIP_DUPLICATE_SHRED_MAX_CHUNKS, "DuplicateShred chunk max mismatch" );
      86             : 
      87             : typedef struct fd_eqvoc       fd_eqvoc_t;
      88             : typedef struct fd_eqvoc_proof fd_eqvoc_proof_t;
      89             : 
      90             : /* fd_eqvoc_{align,footprint} return the required alignment and
      91             :    footprint of a memory region suitable for use as eqvoc with up to
      92             :    shred_max shreds and chunk_max chunks. */
      93             : 
      94             : FD_FN_CONST ulong
      95             : fd_eqvoc_align( void );
      96             : 
      97             : FD_FN_CONST ulong
      98             : fd_eqvoc_footprint( ulong shred_max,
      99             :                     ulong slot_max,
     100             :                     ulong from_max );
     101             : 
     102             : /* fd_eqvoc_new formats an unused memory region for use as a eqvoc.
     103             :    mem is a non-NULL pointer to this region in the local address space
     104             :    with the required footprint and alignment. */
     105             : 
     106             : void *
     107             : fd_eqvoc_new( void * shmem,
     108             :               ulong  shred_max,
     109             :               ulong  cache_max,
     110             :               ulong  proof_max,
     111             :               ulong  seed );
     112             : 
     113             : /* fd_eqvoc_join joins the caller to the eqvoc.  eqvoc points to the
     114             :    first byte of the memory region backing the eqvoc in the caller's
     115             :    address space.
     116             : 
     117             :    Returns a pointer in the local address space to eqvoc on success. */
     118             : 
     119             : fd_eqvoc_t *
     120             : fd_eqvoc_join( void * sheqvoc );
     121             : 
     122             : /* fd_eqvoc_leave leaves a current local join.  Returns a pointer to the
     123             :    underlying shared memory region on success and NULL on failure (logs
     124             :    details).  Reasons for failure include eqvoc is NULL. */
     125             : 
     126             : void *
     127             : fd_eqvoc_leave( fd_eqvoc_t const * eqvoc );
     128             : 
     129             : /* fd_eqvoc_delete unformats a memory region used as a eqvoc.  Assumes
     130             :    only the nobody is joined to the region.  Returns a pointer to the
     131             :    underlying shared memory region or NULL if used obviously in error
     132             :    (e.g. eqvoc is obviously not a eqvoc ... logs details).  The
     133             :    ownership of the memory region is transferred to the caller. */
     134             : 
     135             : void *
     136             : fd_eqvoc_delete( void * sheqvoc );
     137             : 
     138             : /* fd_eqvoc_set_shred_version sets the shred version on eqvoc. */
     139             : 
     140             : void
     141             : fd_eqvoc_set_shred_version( fd_eqvoc_t * eqvoc,
     142             :                             ushort       version );
     143             : 
     144             : /* fd_eqvoc_set_leader_schedule sets the leader schedule on eqvoc. */
     145             : 
     146             : void
     147             : fd_eqvoc_set_leader_schedule( fd_eqvoc_t *               eqvoc,
     148             :                               fd_epoch_leaders_t const * lsched );
     149             : 
     150             : /* fd_eqvoc_shred_insert inserts the shred into eqvoc.  Returns an error
     151             :    code (FD_EQVOC_{SUCCESS,PROOF_{...},ERR_{...}}) indicating whether
     152             :    eqvoc found a shred that conflicts with another shred, indicating
     153             :    equivocation.  If the error code is positive, chunks_out will be
     154             :    populated with a DuplicateShred proof that can be sent over gossip.
     155             :    Assumes shred has already been validated by the shred tile. */
     156             : 
     157             : int
     158             : fd_eqvoc_shred_insert( fd_eqvoc_t *                eqvoc,
     159             :                        fd_shred_t const *          shred,
     160             :                        fd_gossip_duplicate_shred_t chunks_out[static FD_EQVOC_CHUNK_CNT] );
     161             : 
     162             : /* fd_eqvoc_chunk_insert inserts the DuplicateShred chunk from gossip
     163             :    into eqvoc.  Returns one of FD_EQVOC_{SUCCESS,PROOF_{...},ERR_{...}},
     164             :    an error code indicating whether eqvoc was able to verify the proof.
     165             :    If eqvoc hasn't received all the chunks, returns FD_EQVOC_SUCCESS. */
     166             : 
     167             : int
     168             : fd_eqvoc_chunk_insert( fd_eqvoc_t                        * eqvoc,
     169             :                        fd_pubkey_t const                 * from,
     170             :                        fd_gossip_duplicate_shred_t const * chunk );
     171             : 
     172             : #endif /* HEADER_fd_src_choreo_eqvoc_fd_eqvoc_h */

Generated by: LCOV version 1.14