LCOV - code coverage report
Current view: top level - choreo/eqvoc - fd_eqvoc.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 77 0.0 %
Date: 2025-09-19 04:41:14 Functions: 0 30 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 "../../ballet/shred/fd_shred.h"
       5             : #include "../../flamenco/leaders/fd_leaders.h"
       6             : #include "../../flamenco/gossip/fd_gossip_types.h"
       7             : #include "../fd_choreo_base.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 shred index but
      25             :    different data payloads.  An indirect proof contains two shreds with
      26             :    different shred indices, and the metadata on the shreds implies there
      27             :    must be two or more versions of a block for that slot.  See
      28             :    `fd_eqvoc_proof_verify` for more details.
      29             : 
      30             :    Every FEC set must have the same signature for every shred in the
      31             :    set, so a different signature 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           0 : #define FD_EQVOC_FEC_MAX ( 67UL )
      44             : 
      45             : struct fd_slot_fec {
      46             :   ulong slot;
      47             :   uint  fec_set_idx;
      48             : };
      49             : typedef struct fd_slot_fec fd_slot_fec_t;
      50             : 
      51             : /* clang-format off */
      52             : static const fd_slot_fec_t     fd_slot_fec_null = { 0 };
      53             : #define FD_SLOT_FEC_NULL       fd_slot_fec_null
      54             : #define FD_SLOT_FEC_INVAL(key) (!((key).slot) & !((key).fec_set_idx))
      55           0 : #define FD_SLOT_FEC_EQ(k0,k1)  (!(((k0).slot) ^ ((k1).slot))) & !(((k0).fec_set_idx) ^ (((k1).fec_set_idx)))
      56           0 : #define FD_SLOT_FEC_HASH(key)  ((uint)(((key).slot)<<15UL) | (((key).fec_set_idx)))
      57             : /* clang-format on */
      58             : 
      59             : struct fd_eqvoc_fec {
      60             :   fd_slot_fec_t    key;
      61             :   ulong            next;
      62             :   ulong            code_cnt;
      63             :   ulong            data_cnt;
      64             :   uint             last_idx;
      65             :   fd_ed25519_sig_t sig;
      66             : };
      67             : typedef struct fd_eqvoc_fec fd_eqvoc_fec_t;
      68             : 
      69             : #define POOL_NAME fd_eqvoc_fec_pool
      70           0 : #define POOL_T    fd_eqvoc_fec_t
      71             : #include "../../util/tmpl/fd_pool.c"
      72             : 
      73             : /* clang-format off */
      74             : #define MAP_NAME               fd_eqvoc_fec_map
      75             : #define MAP_ELE_T              fd_eqvoc_fec_t
      76             : #define MAP_KEY_T              fd_slot_fec_t
      77           0 : #define MAP_KEY_EQ(k0,k1)      (FD_SLOT_FEC_EQ(*k0,*k1))
      78           0 : #define MAP_KEY_HASH(key,seed) (FD_SLOT_FEC_HASH(*key)^seed)
      79             : #include "../../util/tmpl/fd_map_chain.c"
      80             : /* clang-format on */
      81             : 
      82             : /* This is the standard MTU
      83             : 
      84             :    IPv6 MTU - IP / UDP headers = 1232
      85             :    DuplicateShredMaxPayloadSize = 1232 - 115
      86             :    DuplicateShred headers = 63
      87             : 
      88             :    https://github.com/anza-xyz/agave/blob/v2.0.3/gossip/src/cluster_info.rs#L113 */
      89             : 
      90           0 : #define FD_EQVOC_PROOF_CHUNK_SZ  (1232UL - 115UL - 63UL)
      91           0 : #define FD_EQVOC_PROOF_CHUNK_CNT (( FD_EQVOC_PROOF_SZ / FD_EQVOC_PROOF_CHUNK_SZ ) + 1) /* 3 */
      92           0 : #define FD_EQVOC_PROOF_SZ (2*FD_SHRED_MAX_SZ + 2*sizeof(ulong)) /* 2 shreds prefixed with sz, encoded in 3 chunks */
      93             : 
      94             : FD_STATIC_ASSERT( FD_EQVOC_PROOF_CHUNK_SZ==FD_GOSSIP_DUPLICATE_SHRED_MAX_CHUNKS, "Update duplicate shred max chunks size" );
      95             : 
      96             : /* The chunk_cnt is encoded in a UCHAR_MAX, so you can have at most
      97             :    UCHAR_MAX chunks */
      98             : 
      99             : #define FD_EQVOC_PROOF_CHUNK_MIN ( ( FD_EQVOC_PROOF_SZ / UCHAR_MAX ) + 1 ) /* 20 */
     100             : 
     101           0 : #define FD_EQVOC_PROOF_VERIFY_FAILURE           (0)
     102           0 : #define FD_EQVOC_PROOF_VERIFY_SUCCESS_SIGNATURE (1)
     103           0 : #define FD_EQVOC_PROOF_VERIFY_SUCCESS_META      (2)
     104           0 : #define FD_EQVOC_PROOF_VERIFY_SUCCESS_LAST      (3)
     105           0 : #define FD_EQVOC_PROOF_VERIFY_SUCCESS_OVERLAP   (4)
     106           0 : #define FD_EQVOC_PROOF_VERIFY_SUCCESS_CHAINED   (5)
     107             : 
     108           0 : #define FD_EQVOC_PROOF_VERIFY_ERR_SLOT      (-1) /* different slot */
     109           0 : #define FD_EQVOC_PROOF_VERIFY_ERR_VERSION   (-2) /* different shred version */
     110           0 : #define FD_EQVOC_PROOF_VERIFY_ERR_TYPE      (-3) /* wrong shred type (must be chained {resigned} merkle) */
     111           0 : #define FD_EQVOC_PROOF_VERIFY_ERR_MERKLE    (-4) /* merkle root failed */
     112           0 : #define FD_EQVOC_PROOF_VERIFY_ERR_SIGNATURE (-5) /* sig verify of shred producer failed */
     113             : 
     114             : #define SET_NAME fd_eqvoc_proof_set
     115             : #define SET_MAX  256
     116             : #include "../../util/tmpl/fd_set.c"
     117             : 
     118             : struct fd_eqvoc_proof {
     119             :   fd_slot_pubkey_t     key;
     120             :   ulong                prev; /* reserved for data structure use */
     121             :   ulong                next; /* reserved for data structure use*/
     122             : 
     123             :   fd_pubkey_t         producer;   /* producer of shreds' pubkey */
     124             :   void *              bmtree_mem; /* scratch space for reconstructing
     125             :                                      the merkle root */
     126             :   long                wallclock;  /* `wallclock` (nanos) */
     127             :   ulong               chunk_cnt;  /* `num_chunks` */
     128             :   ulong               chunk_sz;   /* `chunk_len` */
     129             : 
     130             :   /* static declaration of an fd_set that occupies 4 words ie. 256 bits
     131             :      that tracks which proof chunks have been received. */
     132             : 
     133             :   fd_eqvoc_proof_set_t set[UCHAR_MAX / sizeof( ulong )];
     134             : 
     135             :   /* DuplicateShred messages are serialized in the following format:
     136             : 
     137             :      ---------
     138             :      shred1_sz
     139             :      ---------
     140             :      shred1
     141             :      ---------
     142             :      shred2_sz
     143             :      ---------
     144             :      shred2
     145             :      ---------
     146             : 
     147             :      Each shred is prepended with its size in bytes, before being
     148             :      chunked.
     149             :   */
     150             : 
     151             :    uchar shreds[2 * FD_SHRED_MAX_SZ + 2 * sizeof(ulong)];
     152             : };
     153             : typedef struct fd_eqvoc_proof fd_eqvoc_proof_t;
     154             : 
     155             : #define POOL_NAME fd_eqvoc_proof_pool
     156           0 : #define POOL_T    fd_eqvoc_proof_t
     157             : #include "../../util/tmpl/fd_pool.c"
     158             : 
     159             : /* clang-format off */
     160             : #define MAP_NAME               fd_eqvoc_proof_map
     161             : #define MAP_ELE_T              fd_eqvoc_proof_t
     162             : #define MAP_KEY_T              fd_slot_pubkey_t
     163           0 : #define MAP_KEY_EQ(k0,k1)      (FD_SLOT_PUBKEY_EQ(k0,k1))
     164           0 : #define MAP_KEY_HASH(key,seed) (FD_SLOT_PUBKEY_HASH(key,seed))
     165             : #include "../../util/tmpl/fd_map_chain.c"
     166             : /* clang-format on */
     167             : 
     168             : struct fd_eqvoc {
     169             : 
     170             :   /* primitives */
     171             : 
     172             :   fd_pubkey_t me; /* our pubkey */
     173             :   ulong fec_max;
     174             :   ulong proof_max;
     175             :   ulong shred_version; /* shred version we expect in all shreds in eqvoc-related msgs. */
     176             : 
     177             :   /* owned */
     178             : 
     179             :   fd_eqvoc_fec_t *       fec_pool;
     180             :   fd_eqvoc_fec_map_t *   fec_map;
     181             :   // fd_eqvoc_fec_dlist_t * fec_dlist;
     182             :   fd_eqvoc_proof_t *     proof_pool;
     183             :   fd_eqvoc_proof_map_t * proof_map;
     184             :   fd_sha512_t *          sha512;
     185             :   void *                 bmtree_mem;
     186             : 
     187             :   /* borrowed  */
     188             : 
     189             :   fd_epoch_leaders_t const * leaders;
     190             : };
     191             : typedef struct fd_eqvoc fd_eqvoc_t;
     192             : 
     193             : /* clang-format off */
     194             : 
     195             : /* fd_eqvoc_{align,footprint} return the required alignment and
     196             :    footprint of a memory region suitable for use as eqvoc with up to
     197             :    node_max nodes and vote_max votes. */
     198             : 
     199             : FD_FN_CONST static inline ulong
     200           0 : fd_eqvoc_align( void ) {
     201           0 :   return alignof(fd_eqvoc_t);
     202           0 : }
     203             : 
     204             : FD_FN_CONST static inline ulong
     205           0 : fd_eqvoc_footprint( ulong fec_max, ulong proof_max ) {
     206           0 :   return FD_LAYOUT_FINI(
     207           0 :     FD_LAYOUT_APPEND(
     208           0 :     FD_LAYOUT_APPEND(
     209           0 :     FD_LAYOUT_APPEND(
     210           0 :     FD_LAYOUT_APPEND(
     211           0 :     FD_LAYOUT_APPEND(
     212           0 :     FD_LAYOUT_APPEND(
     213           0 :     FD_LAYOUT_APPEND(
     214           0 :     FD_LAYOUT_INIT,
     215           0 :       alignof(fd_eqvoc_t),         sizeof(fd_eqvoc_t) ),
     216           0 :       fd_eqvoc_fec_pool_align(),   fd_eqvoc_fec_pool_footprint( fec_max ) ),
     217           0 :       fd_eqvoc_fec_map_align(),    fd_eqvoc_fec_map_footprint( fec_max ) ),
     218           0 :       fd_eqvoc_proof_pool_align(), fd_eqvoc_proof_pool_footprint( proof_max ) ),
     219           0 :       fd_eqvoc_proof_map_align(),  fd_eqvoc_proof_map_footprint( proof_max ) ),
     220           0 :       fd_sha512_align(),           fd_sha512_footprint() ),
     221           0 :       fd_bmtree_commit_align(),    fd_bmtree_commit_footprint( FD_SHRED_MERKLE_LAYER_CNT ) ),
     222           0 :    fd_eqvoc_align() );
     223           0 : }
     224             : /* clang-format on */
     225             : 
     226             : /* fd_eqvoc_new formats an unused memory region for use as a eqvoc.
     227             :    mem is a non-NULL pointer to this region in the local address space
     228             :    with the required footprint and alignment. */
     229             : 
     230             : void *
     231             : fd_eqvoc_new( void * shmem, ulong fec_max, ulong proof_max, ulong seed );
     232             : 
     233             : /* fd_eqvoc_join joins the caller to the eqvoc.  eqvoc points to the
     234             :    first byte of the memory region backing the eqvoc in the caller's
     235             :    address space.
     236             : 
     237             :    Returns a pointer in the local address space to eqvoc on success. */
     238             : 
     239             : fd_eqvoc_t *
     240             : fd_eqvoc_join( void * sheqvoc );
     241             : 
     242             : /* fd_eqvoc_leave leaves a current local join.  Returns a pointer to the
     243             :    underlying shared memory region on success and NULL on failure (logs
     244             :    details).  Reasons for failure include eqvoc is NULL. */
     245             : 
     246             : void *
     247             : fd_eqvoc_leave( fd_eqvoc_t const * eqvoc );
     248             : 
     249             : /* fd_eqvoc_delete unformats a memory region used as a eqvoc.
     250             :    Assumes only the nobody is joined to the region.  Returns a
     251             :    pointer to the underlying shared memory region or NULL if used
     252             :    obviously in error (e.g. eqvoc is obviously not a eqvoc ... logs
     253             :    details).  The ownership of the memory region is transferred to the
     254             :    caller. */
     255             : 
     256             : void *
     257             : fd_eqvoc_delete( void * sheqvoc );
     258             : 
     259             : /* fd_eqvoc_init initializes eqvoc with the expected shred version. */
     260             : 
     261             : void
     262             : fd_eqvoc_init( fd_eqvoc_t * eqvoc, ulong shred_version );
     263             : 
     264             : /* fd_eqvoc_fec_query queries for FEC set metadata on (slot,
     265             :    fec_set_idx).  At least one coding shred most be inserted to populate
     266             :    code_cnt, data_cnt, and the last data shred in the slot to populate
     267             :    last_idx.  Otherwise fields are defaulted to 0, 0, FD_SHRED_IDX_NULL
     268             :    respectively.  Callers should check whether fields are the default
     269             :    values before using them. */
     270             : 
     271             : FD_FN_PURE static inline fd_eqvoc_fec_t const *
     272           0 : fd_eqvoc_fec_query( fd_eqvoc_t const * eqvoc, ulong slot, uint fec_set_idx ) {
     273           0 :   fd_slot_fec_t key = { slot, fec_set_idx };
     274           0 :   return fd_eqvoc_fec_map_ele_query_const( eqvoc->fec_map, &key, NULL, eqvoc->fec_pool );
     275           0 : }
     276             : 
     277             : /* fd_eqvoc_fec_insert inserts a new FEC entry into eqvoc, indexed by
     278             :    (slot, fec_set_idx). */
     279             : 
     280             : fd_eqvoc_fec_t *
     281             : fd_eqvoc_fec_insert( fd_eqvoc_t * eqvoc, ulong slot, uint fec_set_idx );
     282             : 
     283             : /* fd_eqvoc_fec_search searches for whether `shred` implies equivocation
     284             :    by checking for a conflict in the currently indexed FEC sets. Returns
     285             :    the conflicting entry if there is one, NULL otherwise.
     286             : 
     287             :    A FEC set "overlaps" with another if they both contain a data shred
     288             :    at the samed idx.  For example, say we have a FEC set containing data
     289             :    shreds in the idx interval [13, 15] and another containing idxs [15,
     290             :    20].  The first FEC set has fec_set_idx 13 and data_cnt 3. The second
     291             :    FEC set has fec_set_idx 15 and data_cnt 6.  They overlap because they
     292             :    both contain a data shred at idx 15.  Therefore, these two FEC sets
     293             :    imply equivocation.
     294             : 
     295             :    This overlap can be detected arithmetically by adding the data_cnt to
     296             :    the fec_set_idx that starts earlier.  If the result is greater than
     297             :    the fec_set_idx that starts later, we know at least one data shred
     298             :    idx must overlap.  In this example, 13 + 3 > 15, which indicates
     299             :    equivocation.
     300             : 
     301             :    We can check for this overlap both backwards and forwards.  We know
     302             :    the max number of data shred idxs in a valid FEC set is 67.  So we
     303             :    need to look back at most 67 FEC set idxs to find the previous FEC
     304             :    set.  Similarly, we look forward at most data_cnt idxs to find the
     305             :    next FEC set. */
     306             : 
     307             : fd_eqvoc_fec_t const *
     308             : fd_eqvoc_fec_search( fd_eqvoc_t const * eqvoc, fd_shred_t const * shred );
     309             : 
     310             : /* fd_eqvoc_proof_query queries for the proof at (slot, from). */
     311             : 
     312             : FD_FN_PURE static inline fd_eqvoc_proof_t *
     313           0 : fd_eqvoc_proof_query( fd_eqvoc_t * eqvoc, ulong slot, fd_pubkey_t const * from ) {
     314           0 :   fd_slot_pubkey_t key = { slot, *from };
     315           0 :   return fd_eqvoc_proof_map_ele_query( eqvoc->proof_map, &key, NULL, eqvoc->proof_pool );
     316           0 : }
     317             : 
     318             : /* fd_eqvoc_proof_query_const is the const version of the above. */
     319             : 
     320             : FD_FN_PURE static inline fd_eqvoc_proof_t const *
     321           0 : fd_eqvoc_proof_query_const( fd_eqvoc_t const * eqvoc, ulong slot, fd_pubkey_t const * from ) {
     322           0 :   fd_slot_pubkey_t key = { slot, *from };
     323           0 :   return fd_eqvoc_proof_map_ele_query_const( eqvoc->proof_map, &key, NULL, eqvoc->proof_pool );
     324           0 : }
     325             : 
     326             : /* fd_eqvoc_proof_insert inserts a proof entry into eqvoc, keyed by
     327             :    (slot, from) where from is the pubkey that generated the proof. */
     328             : 
     329             : fd_eqvoc_proof_t *
     330             : fd_eqvoc_proof_insert( fd_eqvoc_t * eqvoc, ulong slot, fd_pubkey_t const * from );
     331             : 
     332             : void
     333             : fd_eqvoc_proof_init( fd_eqvoc_proof_t * proof, fd_pubkey_t const * producer, long wallclock, ulong chunk_cnt, ulong chunk_sz, void * bmtree_mem );
     334             : 
     335             : /* fd_eqvoc_proof_chunk_insert inserts a proof chunk into the proof.
     336             :    Proofs are divided into chunks before they are transmitted via
     337             :    gossip, so this function is necessary for reconstruction. */
     338             : 
     339             : void
     340             : fd_eqvoc_proof_chunk_insert( fd_eqvoc_proof_t * proof, fd_gossip_duplicate_shred_t const * chunk );
     341             : 
     342             : /* fd_eqvoc_shreds_chunk_insert is a lower-level API for the above. */
     343             : 
     344             : void
     345             : fd_eqvoc_shreds_chunk_insert( fd_shred_t * shred1, fd_shred_t * shred2, fd_gossip_duplicate_shred_t const * chunk );
     346             : 
     347             : /* fd_eqvoc_proof_remove removes the proof entry associated with key. */
     348             : 
     349             : void
     350             : fd_eqvoc_proof_remove( fd_eqvoc_t * eqvoc, fd_slot_pubkey_t const * key );
     351             : 
     352             : /* fd_eqvoc_proof_complete checks whether the proof has received all
     353             :    chunks ie. is complete.  Returns 1 if so, 0 otherwise. */
     354             : 
     355             : static inline int
     356           0 : fd_eqvoc_proof_complete( fd_eqvoc_proof_t const * proof ) {
     357           0 :   for( uchar i = 0; i < proof->chunk_cnt; i++ ) {
     358           0 :     if( !fd_eqvoc_proof_set_test( proof->set, i ) ) return 0;
     359           0 :   }
     360           0 :   return 1;
     361           0 : }
     362             : 
     363             : /* fd_eqvoc_proof_verify verifies that the two shreds contained in
     364             :    `proof` do in fact equivocate.
     365             : 
     366             :    Returns: FD_EQVOC_VERIFY_FAILURE if they do not
     367             :      FD_EQVOC_VERIFY_SUCCESS_{REASON} if they do
     368             :      FD_EQVOC_VERIFY_ERR_{REASON} if the shreds were not valid inputs
     369             : 
     370             :    Two shreds equivocate if they satisfy any of the following:
     371             : 
     372             :    1. They are in the same FEC set but have different signatures.
     373             :    2. They are in the same FEC set and are both coding shreds, but have
     374             :       different coding metadata ie. code_cnt, data_cnt, first_code_idx.
     375             :    3. They are in the same FEC set and are both data shreds.  One shred
     376             :       is marked as the last data shred in the slot
     377             :       (FD_SHRED_DATA_FLAG_SLOT_COMPLETE), but the other shred has a
     378             :       higher data shred index.
     379             :    4. They are in different FEC sets and the shred with a lower FEC set
     380             :       index is a coding shred, whereas the shred with the higher FEC set
     381             :       index is either a coding or data shred.  The lower coding shred's
     382             :       `data_cnt` implies the lower FEC set intersects with the higher
     383             :       FEC set ie. the FEC sets are overlapping.
     384             :    5. They are in different FEC sets and the shred with a lower FEC set
     385             :       index is a coding shred, and the FEC sets are adjacent ie. the
     386             :       last data shred index in the lower FEC set is one less than the
     387             :       first data shred index in the higher FEC set.  The merkle root of
     388             :       the lower FEC set is different from the chained merkle root of the
     389             :       higher FEC set.
     390             : 
     391             :    Note: two shreds are in the same FEC set if they have the same slot
     392             :    and same FEC set index.
     393             : 
     394             :    To prevent false positives, this function also performs the following
     395             :    input validation on the shreds:
     396             : 
     397             :    1. shred1 and shred2 are both the expected shred_version.
     398             :    2. shred1 and shred2 are for the same slot.
     399             :    3. shred1 and shred2 are either chained merkle or chained resigned
     400             :       merkle variants.
     401             :    4. shred1 and shred2 contain valid signatures signed by the same
     402             :       producer pubkey.
     403             : 
     404             :    If any of the above input validation fail, this function returns
     405             :    FD_EQVOC_VERIFY_ERR_{REASON} for the appropriate reason. */
     406             : 
     407             : int
     408             : fd_eqvoc_proof_verify( fd_eqvoc_proof_t const * proof );
     409             : 
     410             : /* fd_eqvoc_proof_shreds_verify is a lower-level API for
     411             :    fd_eqvoc_proof_verify.  Refer above for documentation.  */
     412             : 
     413             : int
     414             : fd_eqvoc_shreds_verify( fd_shred_t const * shred1, fd_shred_t const * shred2, fd_pubkey_t const * producer, void * bmtree_mem );
     415             : 
     416             : /* fd_eqvoc_proof_shred1 returns a pointer to shred1 in `proof`. */
     417             : 
     418             : static inline fd_shred_t *
     419           0 : fd_eqvoc_proof_shred1( fd_eqvoc_proof_t * proof ) {
     420           0 :   return (fd_shred_t *)fd_type_pun_const( proof->shreds + sizeof(ulong) );
     421           0 : }
     422             : 
     423             : /* fd_eqvoc_proof_shred1_const returns a const pointer to shred1 in
     424             :    `proof`. */
     425             : 
     426             : static inline fd_shred_t const *
     427           0 : fd_eqvoc_proof_shred1_const( fd_eqvoc_proof_t const * proof ) {
     428           0 :   return (fd_shred_t const *)fd_type_pun_const( proof->shreds + sizeof(ulong) );
     429           0 : }
     430             : 
     431             : /* fd_eqvoc_proof_shred2 returns a pointer to shred2 in `proof`. */
     432             : 
     433             : static inline fd_shred_t *
     434           0 : fd_eqvoc_proof_shred2( fd_eqvoc_proof_t * proof ) {
     435           0 :   ulong shred1_sz = *(ulong *)fd_type_pun( proof->shreds );
     436           0 :   return (fd_shred_t *)fd_type_pun( proof->shreds + shred1_sz + 2*sizeof(ulong) );
     437           0 : }
     438             : 
     439             : /* fd_eqvoc_proof_shred2_const returns a const pointer to shred2 in `proof`. */
     440             : 
     441             : static inline fd_shred_t const *
     442           0 : fd_eqvoc_proof_shred2_const( fd_eqvoc_proof_t const * proof ) {
     443           0 :   ulong shred1_sz = *(ulong const *)fd_type_pun_const( proof->shreds );
     444           0 :   return (fd_shred_t const *)fd_type_pun_const( proof->shreds + shred1_sz + 2*sizeof(ulong) );
     445           0 : }
     446             : 
     447             : /* fd_eqvoc_verify verifies `slot` has FEC sets with merkle roots that
     448             :    correctly chain, including that the first FEC set in slot's merkle
     449             :    hash chains from the last FEC set in parent slot's merkle hash. */
     450             : 
     451             : int
     452             : fd_eqvoc_slot_verify( fd_eqvoc_t const * eqvoc, ulong slot );
     453             : 
     454             : /* fd_eqvoc_from_chunks reconstructs shred1_out and shred2_out from
     455             :    `chunks` which is an array of "duplicate shred" gossip msgs. Shred1
     456             :    and shred2 comprise a "duplicate shred proof", ie. proof of two
     457             :    shreds that conflict and therefore demonstrate the shreds' producer
     458             :    has equivocated.
     459             : 
     460             :    Assumes `chunks` is non-NULL and contains at least one valid array
     461             :    member chunks[0] to extract header information.  Caller's
     462             :    responsibility to guarantee this.  Also assumes the `chunk` field in
     463             :    `fd_gossip_duplicate_shred_t` is a pointer to valid memory and
     464             :    consistent with the metadata presented in the header of the first
     465             :    array member, eg. if the header says there are 4 chunks then this
     466             :    implementation assumes this is true.  These assumptions should be
     467             :    already upheld by caller if using deserializers in `fd_types.h`.
     468             :    Behavior is undefined otherwise.
     469             : 
     470             :    Does additional sanity-check validation eg. checking chunk_len <=
     471             :    FD_EQVOC_PROOF_SZ.
     472             : 
     473             :    This function is expected to be deprecated once chunks are specified
     474             :    to be fixed-length in the gossip protocol. */
     475             : 
     476             : void
     477             : fd_eqvoc_proof_from_chunks( fd_gossip_duplicate_shred_t const * chunks,
     478             :                             fd_eqvoc_proof_t * proof_out );
     479             : 
     480             : /* fd_eqvoc_to_chunks constructs an array of DuplicateShred gossip msgs
     481             :    (`chunks_out`) from shred1 and shred2.
     482             : 
     483             :    Shred1 and shred2 are concatenated (the concatenation is implemented
     484             :    virtually) and then spliced into chunks of FD_EQVOC_PROOF_CHUNK_SZ
     485             :    size. These chunks are embedded in the body of each DuplicateShred
     486             :    msg, along with a common header across all msgs.
     487             : 
     488             :    Caller supplies `chunks_out`, which is an array that MUST contain
     489             :    `ceil(shred1_payload_sz + shred2_payload_sz /
     490             :    FD_EQVOC_PROOF_CHUNK_SZ)` elements.  Each chunk in `chunks_out` MUST
     491             :    have a buffer of at least `chunk_len` size available in its `chunk`
     492             :    pointer field.  Behavior is undefined otherwise.
     493             : 
     494             :    IMPORTANT SAFETY TIP!  The lifetime of each chunk in `chunks_out`
     495             :    must be at least as long as the lifetime of the array of
     496             :    duplicate_shreds.  Caller is responsible for ensuring this memory
     497             :    safety guarantee. */
     498             : 
     499             : void
     500             : fd_eqvoc_proof_to_chunks( fd_eqvoc_proof_t * proof, fd_gossip_duplicate_shred_t * chunks_out );
     501             : 
     502             : #endif /* HEADER_fd_src_choreo_eqvoc_fd_eqvoc_h */

Generated by: LCOV version 1.14