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-03-10 13:31:57 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_message.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             : /* zero means nothing to do (no proof has been verified) */
      37             : 
      38          12 : #define FD_EQVOC_SUCCESS (0) /* shreds do not equivocate */
      39             : 
      40             : /* positive error codes means there is a proof of equivocation */
      41             : 
      42          24 : #define FD_EQVOC_VERIFIED_MERKLE  (1)
      43          12 : #define FD_EQVOC_VERIFIED_META    (2)
      44          12 : #define FD_EQVOC_VERIFIED_LAST    (3)
      45          12 : #define FD_EQVOC_VERIFIED_OVERLAP (4)
      46          12 : #define FD_EQVOC_VERIFIED_CHAINED (5)
      47             : 
      48             : /* negative error codes mean the shreds in the proof were not valid inputs */
      49             : 
      50           0 : #define FD_EQVOC_ERR_SER     (-1) /* invalid serialization */
      51           0 : #define FD_EQVOC_ERR_SLOT    (-2) /* different slot */
      52           0 : #define FD_EQVOC_ERR_VERSION (-3) /* different shred version */
      53           0 : #define FD_EQVOC_ERR_TYPE    (-4) /* wrong shred type (must be chained merkle) */
      54           0 : #define FD_EQVOC_ERR_MERKLE  (-5) /* failed to derive merkle root */
      55           0 : #define FD_EQVOC_ERR_SIG     (-6) /* failed to sigverify */
      56             : 
      57             : /* FD_EQVOC_CHUNK_CNT: the count of chunks is hardcoded because Agave
      58             :    discards any chunks where count != 3 (even though technically the
      59             :    schema supports it).
      60             : 
      61             :    See: https://github.com/anza-xyz/agave/blob/v3.1/gossip/src/duplicate_shred_handler.rs#L21 */
      62             : 
      63           0 : #define FD_EQVOC_CHUNK_CNT (3)
      64             : 
      65             : /* FD_EQVOC_CHUNK_SZ: the size of data in each chunk Firedancer produces
      66             :                       in a DuplicateShred message is derived below.
      67             : 
      68             :    IPv6 MTU - IP / UDP headers = 1232
      69             :    DuplicateShredMaxPayloadSize = 1232 - 115
      70             :    DuplicateShred headers = 63
      71             : 
      72             :    This is not enforce on receive (Firedancer will accept smaller chunk
      73             :    payloads).
      74             : 
      75             :    See: https://github.com/anza-xyz/agave/blob/v2.0.3/gossip/src/cluster_info.rs#L113 */
      76             : 
      77           0 : #define FD_EQVOC_CHUNK_SZ  (1232UL - 115UL - 63UL)
      78             : FD_STATIC_ASSERT( FD_EQVOC_CHUNK_SZ<=sizeof(((fd_gossip_duplicate_shred_t*)0)->chunk), "DuplicateShred chunk max mismatch" );
      79             : 
      80             : typedef struct fd_eqvoc       fd_eqvoc_t;
      81             : typedef struct fd_eqvoc_proof fd_eqvoc_proof_t;
      82             : 
      83             : /* fd_eqvoc_{align,footprint} return the required alignment and
      84             :    footprint of a memory region suitable for use as eqvoc with up to
      85             :    shred_max shreds and chunk_max chunks. */
      86             : 
      87             : FD_FN_CONST ulong
      88             : fd_eqvoc_align( void );
      89             : 
      90             : FD_FN_CONST ulong
      91             : fd_eqvoc_footprint( ulong shred_max,
      92             :                     ulong slot_max,
      93             :                     ulong from_max );
      94             : 
      95             : /* fd_eqvoc_new formats an unused memory region for use as a eqvoc.
      96             :    mem is a non-NULL pointer to this region in the local address space
      97             :    with the required footprint and alignment. */
      98             : 
      99             : void *
     100             : fd_eqvoc_new( void * shmem,
     101             :               ulong  shred_max,
     102             :               ulong  cache_max,
     103             :               ulong  proof_max,
     104             :               ulong  seed );
     105             : 
     106             : /* fd_eqvoc_join joins the caller to the eqvoc.  eqvoc points to the
     107             :    first byte of the memory region backing the eqvoc in the caller's
     108             :    address space.
     109             : 
     110             :    Returns a pointer in the local address space to eqvoc on success. */
     111             : 
     112             : fd_eqvoc_t *
     113             : fd_eqvoc_join( void * sheqvoc );
     114             : 
     115             : /* fd_eqvoc_leave leaves a current local join.  Returns a pointer to the
     116             :    underlying shared memory region on success and NULL on failure (logs
     117             :    details).  Reasons for failure include eqvoc is NULL. */
     118             : 
     119             : void *
     120             : fd_eqvoc_leave( fd_eqvoc_t const * eqvoc );
     121             : 
     122             : /* fd_eqvoc_delete unformats a memory region used as a eqvoc.  Assumes
     123             :    only the nobody is joined to the region.  Returns a pointer to the
     124             :    underlying shared memory region or NULL if used obviously in error
     125             :    (e.g. eqvoc is obviously not a eqvoc ... logs details).  The
     126             :    ownership of the memory region is transferred to the caller. */
     127             : 
     128             : void *
     129             : fd_eqvoc_delete( void * sheqvoc );
     130             : 
     131             : /* fd_eqvoc_set_shred_version sets the shred version on eqvoc. */
     132             : 
     133             : void
     134             : fd_eqvoc_set_shred_version( fd_eqvoc_t * eqvoc,
     135             :                             ushort       version );
     136             : 
     137             : /* fd_eqvoc_set_leader_schedule sets the leader schedule on eqvoc. */
     138             : 
     139             : void
     140             : fd_eqvoc_set_leader_schedule( fd_eqvoc_t *               eqvoc,
     141             :                               fd_epoch_leaders_t const * lsched );
     142             : 
     143             : /* fd_eqvoc_shred_insert inserts the shred into eqvoc.  Returns an error
     144             :    code (FD_EQVOC_{SUCCESS,PROOF_{...},ERR_{...}}) indicating whether
     145             :    eqvoc found a shred that conflicts with another shred, indicating
     146             :    equivocation.  If the error code is positive, chunks_out will be
     147             :    populated with a DuplicateShred proof that can be sent over gossip.
     148             :    Assumes shred has already been validated by the shred tile. */
     149             : 
     150             : int
     151             : fd_eqvoc_shred_insert( fd_eqvoc_t *                eqvoc,
     152             :                        fd_shred_t const *          shred,
     153             :                        fd_gossip_duplicate_shred_t chunks_out[static FD_EQVOC_CHUNK_CNT] );
     154             : 
     155             : /* fd_eqvoc_chunk_insert inserts the DuplicateShred chunk from gossip
     156             :    into eqvoc.  Returns one of FD_EQVOC_{SUCCESS,PROOF_{...},ERR_{...}},
     157             :    an error code indicating whether eqvoc was able to verify the proof.
     158             :    If eqvoc hasn't received all the chunks, returns FD_EQVOC_SUCCESS. */
     159             : 
     160             : int
     161             : fd_eqvoc_chunk_insert( fd_eqvoc_t                        * eqvoc,
     162             :                        fd_pubkey_t const                 * from,
     163             :                        fd_gossip_duplicate_shred_t const * chunk );
     164             : 
     165             : #endif /* HEADER_fd_src_choreo_eqvoc_fd_eqvoc_h */

Generated by: LCOV version 1.14