diff --git a/src/app/fdctl/run/tiles/fd_eqvoc.c b/src/app/fdctl/run/tiles/fd_eqvoc.c index 984dea93b8..b57fc27161 100644 --- a/src/app/fdctl/run/tiles/fd_eqvoc.c +++ b/src/app/fdctl/run/tiles/fd_eqvoc.c @@ -202,12 +202,11 @@ after_frag( fd_eqvoc_tile_ctx_t * ctx, } return; + } else if ( FD_UNLIKELY( in_idx == ctx->shred_net_in_idx ) ) { + FD_LOG_NOTICE(( "got shred %lu %u", ctx->shred.slot, ctx->shred.idx )); + } else { + FD_LOG_WARNING(( "unexpected in_idx %lu", in_idx )); } - // } else if ( FD_UNLIKELY( in_idx == ctx->shred_net_in_idx ) ) { - // FD_LOG_NOTICE(( "got shred %lu %u", ctx->shred.slot, ctx->shred.idx )); - // } else { - // FD_LOG_WARNING(( "unexpected in_idx %lu", in_idx )); - // } } diff --git a/src/choreo/eqvoc/fd_eqvoc.c b/src/choreo/eqvoc/fd_eqvoc.c index a0e7bff2bd..a047caff91 100644 --- a/src/choreo/eqvoc/fd_eqvoc.c +++ b/src/choreo/eqvoc/fd_eqvoc.c @@ -15,22 +15,23 @@ fd_eqvoc_new( void * shmem, ulong fec_max, ulong proof_max, ulong seed ) { } FD_SCRATCH_ALLOC_INIT( l, shmem ); - fd_eqvoc_t * eqvoc = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_eqvoc_t), sizeof(fd_eqvoc_t) ); - void * fec_pool = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_fec_pool_align(), fd_eqvoc_fec_pool_footprint( fec_max ) ); - void * fec_map = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_fec_map_align(), fd_eqvoc_fec_map_footprint( fec_max ) ); - void * proof_pool = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_proof_pool_align(), fd_eqvoc_proof_pool_footprint( proof_max ) ); - void * proof_map = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_proof_map_align(), fd_eqvoc_proof_map_footprint( proof_max ) ); - void * sha512 = FD_SCRATCH_ALLOC_APPEND( l, fd_sha512_align(), fd_sha512_footprint() ); - void * bmtree_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_bmtree_commit_align(), fd_bmtree_commit_footprint( FD_SHRED_MERKLE_LAYER_CNT ) ); + fd_eqvoc_t * eqvoc = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_eqvoc_t), sizeof(fd_eqvoc_t) ); + void * fec_pool = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_fec_pool_align(), fd_eqvoc_fec_pool_footprint( fec_max ) ); + void * fec_map = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_fec_map_align(), fd_eqvoc_fec_map_footprint( fec_max ) ); + void * proof_pool = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_proof_pool_align(), fd_eqvoc_proof_pool_footprint( proof_max ) ); + void * proof_map = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_proof_map_align(), fd_eqvoc_proof_map_footprint( proof_max ) ); + void * proof_dlist = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_proof_dlist_align(), fd_eqvoc_proof_dlist_footprint() ); + void * sha512 = FD_SCRATCH_ALLOC_APPEND( l, fd_sha512_align(), fd_sha512_footprint() ); + void * bmtree_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_bmtree_commit_align(), fd_bmtree_commit_footprint( FD_SHRED_MERKLE_LAYER_CNT ) ); FD_SCRATCH_ALLOC_FINI( l, fd_eqvoc_align() ); eqvoc->fec_max = fec_max; eqvoc->proof_max = proof_max; - eqvoc->shred_version = 0; fd_eqvoc_fec_pool_new( fec_pool, fec_max ); fd_eqvoc_fec_map_new( fec_map, fec_max, seed ); fd_eqvoc_proof_pool_new( proof_pool, proof_max ); fd_eqvoc_proof_map_new( proof_map, proof_max, seed ); + fd_eqvoc_proof_dlist_new( proof_dlist ); fd_sha512_new( sha512 ); (void)bmtree_mem; /* does not require new */ @@ -51,21 +52,23 @@ fd_eqvoc_join( void * sheqvoc ) { } FD_SCRATCH_ALLOC_INIT( l, sheqvoc ); - fd_eqvoc_t * eqvoc = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_eqvoc_t), sizeof(fd_eqvoc_t) ); - void * fec_pool = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_fec_pool_align(), fd_eqvoc_fec_pool_footprint( eqvoc->fec_max ) ); - void * fec_map = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_fec_map_align(), fd_eqvoc_fec_map_footprint( eqvoc->fec_max ) ); - void * proof_pool = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_proof_pool_align(), fd_eqvoc_proof_pool_footprint( eqvoc->proof_max ) ); - void * proof_map = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_proof_map_align(), fd_eqvoc_proof_map_footprint( eqvoc->proof_max ) ); - void * sha512 = FD_SCRATCH_ALLOC_APPEND( l, fd_sha512_align(), fd_sha512_footprint() ); - void * bmtree_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_bmtree_commit_align(), fd_bmtree_commit_footprint( FD_SHRED_MERKLE_LAYER_CNT ) ); + fd_eqvoc_t * eqvoc = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_eqvoc_t), sizeof(fd_eqvoc_t) ); + void * fec_pool = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_fec_pool_align(), fd_eqvoc_fec_pool_footprint( eqvoc->fec_max ) ); + void * fec_map = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_fec_map_align(), fd_eqvoc_fec_map_footprint( eqvoc->fec_max ) ); + void * proof_pool = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_proof_pool_align(), fd_eqvoc_proof_pool_footprint( eqvoc->proof_max ) ); + void * proof_map = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_proof_map_align(), fd_eqvoc_proof_map_footprint( eqvoc->proof_max ) ); + void * proof_dlist = FD_SCRATCH_ALLOC_APPEND( l, fd_eqvoc_proof_dlist_align(), fd_eqvoc_proof_dlist_footprint() ); + void * sha512 = FD_SCRATCH_ALLOC_APPEND( l, fd_sha512_align(), fd_sha512_footprint() ); + void * bmtree_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_bmtree_commit_align(), fd_bmtree_commit_footprint( FD_SHRED_MERKLE_LAYER_CNT ) ); FD_SCRATCH_ALLOC_FINI( l, fd_eqvoc_align() ); - eqvoc->fec_pool = fd_eqvoc_fec_pool_join( fec_pool ); - eqvoc->fec_map = fd_eqvoc_fec_map_join( fec_map ); - eqvoc->proof_pool = fd_eqvoc_proof_pool_join( proof_pool ); - eqvoc->proof_map = fd_eqvoc_proof_map_join( proof_map ); - eqvoc->sha512 = fd_sha512_join( sha512 ); - eqvoc->bmtree_mem = bmtree_mem; /* does not require join */ + eqvoc->fec_pool = fd_eqvoc_fec_pool_join( fec_pool ); + eqvoc->fec_map = fd_eqvoc_fec_map_join( fec_map ); + eqvoc->proof_pool = fd_eqvoc_proof_pool_join( proof_pool ); + eqvoc->proof_map = fd_eqvoc_proof_map_join( proof_map ); + eqvoc->proof_dlist = fd_eqvoc_proof_dlist_join( proof_dlist ); + eqvoc->sha512 = fd_sha512_join( sha512 ); + eqvoc->bmtree_mem = bmtree_mem; /* does not require join */ return (fd_eqvoc_t *)sheqvoc; } @@ -97,11 +100,6 @@ fd_eqvoc_delete( void * eqvoc ) { return eqvoc; } -void -fd_eqvoc_init( fd_eqvoc_t * eqvoc, ulong shred_version ) { - eqvoc->shred_version = shred_version; -} - fd_eqvoc_fec_t * fd_eqvoc_fec_insert( fd_eqvoc_t * eqvoc, ulong slot, uint fec_set_idx ) { fd_slot_fec_t key = { slot, fec_set_idx }; @@ -112,15 +110,30 @@ fd_eqvoc_fec_insert( fd_eqvoc_t * eqvoc, ulong slot, uint fec_set_idx ) { /* FIXME eviction */ - if( FD_UNLIKELY( !fd_eqvoc_fec_pool_free( eqvoc->fec_pool ) ) ) FD_LOG_ERR(( "[%s] map full.", __func__ )); + if( FD_UNLIKELY( !fd_eqvoc_fec_pool_free( eqvoc->fec_pool ) ) ) { + fd_eqvoc_fec_t * fec = fd_eqvoc_fec_dlist_ele_pop_head( eqvoc->fec_dlist, eqvoc->fec_pool ); + fd_eqvoc_fec_t * ele = fd_eqvoc_fec_map_ele_remove( eqvoc->fec_map, &fec->key, NULL, eqvoc->fec_pool ); + #if FD_EQVOC_USE_HANDHOLDING + FD_TEST( fec == ele ); + #endif + fd_eqvoc_fec_pool_ele_release( eqvoc->fec_pool, fec ); + } fd_eqvoc_fec_t * fec = fd_eqvoc_fec_pool_ele_acquire( eqvoc->fec_pool ); + fec->key.slot = slot; fec->key.fec_set_idx = fec_set_idx; - fec->code_cnt = 0; - fec->data_cnt = 0; - fec->last_idx = FD_SHRED_IDX_NULL; + fec->prev = fd_eqvoc_proof_pool_idx_null( eqvoc->proof_pool ); + fec->next = fd_eqvoc_proof_pool_idx_null( eqvoc->proof_pool ); + fec->hash = fd_eqvoc_proof_pool_idx_null( eqvoc->proof_pool ); + + fec->code_cnt = 0; + fec->data_cnt = 0; + fec->last_idx = FD_SHRED_IDX_NULL; + + fd_eqvoc_fec_dlist_ele_push_tail( eqvoc->fec_dlist, fec, eqvoc->fec_pool ); fd_eqvoc_fec_map_ele_insert( eqvoc->fec_map, fec, eqvoc->fec_pool); + return fec; } @@ -208,24 +221,46 @@ fd_eqvoc_proof_insert( fd_eqvoc_t * eqvoc, ulong slot, fd_pubkey_t const * from if( FD_UNLIKELY( fd_eqvoc_proof_map_ele_query( eqvoc->proof_map, &key, NULL, eqvoc->proof_pool ) ) ) FD_LOG_ERR(( "[%s] key (%lu, %s) already in map.", __func__, slot, FD_BASE58_ENC_32_ALLOCA( from->uc ) )); #endif - /* FIXME eviction */ + if( FD_UNLIKELY( !fd_eqvoc_proof_pool_free( eqvoc->proof_pool ) ) ) { + fd_eqvoc_proof_t * proof = fd_eqvoc_proof_dlist_ele_pop_head( eqvoc->proof_dlist, eqvoc->proof_pool ); + fd_eqvoc_proof_t * ele = fd_eqvoc_proof_map_ele_remove( eqvoc->proof_map, &proof->key, NULL, eqvoc->proof_pool ); + #if FD_EQVOC_USE_HANDHOLDING + FD_TEST( proof == ele ); + #endif + fd_eqvoc_proof_pool_ele_release( eqvoc->proof_pool, proof ); + } fd_eqvoc_proof_t * proof = fd_eqvoc_proof_pool_ele_acquire( eqvoc->proof_pool ); - memset( proof, 0, sizeof(fd_eqvoc_proof_t) ); + proof->key.slot = slot; proof->key.hash = *from; + proof->prev = fd_eqvoc_proof_pool_idx_null( eqvoc->proof_pool ); + proof->next = fd_eqvoc_proof_pool_idx_null( eqvoc->proof_pool ); + proof->hash = fd_eqvoc_proof_pool_idx_null( eqvoc->proof_pool ); + + proof->producer = *fd_epoch_leaders_get( eqvoc->leaders, slot ); + proof->bmtree_mem = eqvoc->bmtree_mem; + proof->wallclock = 0; + proof->chunk_cnt = 0; + proof->chunk_sz = 0; + fd_eqvoc_proof_set_null( proof->set ); + + fd_eqvoc_proof_dlist_ele_push_tail( eqvoc->proof_dlist, proof, eqvoc->proof_pool ); fd_eqvoc_proof_map_ele_insert( eqvoc->proof_map, proof, eqvoc->proof_pool ); + return proof; } void fd_eqvoc_proof_chunk_insert( fd_eqvoc_proof_t * proof, fd_gossip_duplicate_shred_t const * chunk ) { if( FD_UNLIKELY( chunk->wallclock > proof->wallclock ) ) { - FD_LOG_WARNING(( "[%s] received newer chunk (slot: %lu from: %s). overwriting.", __func__, proof->key.slot, FD_BASE58_ENC_32_ALLOCA( proof->key.hash.uc ) )); + if( FD_UNLIKELY( proof->wallclock != 0 ) ) FD_LOG_WARNING(( "[%s] received newer chunk (slot: %lu from: %s). overwriting.", __func__, proof->key.slot, FD_BASE58_ENC_32_ALLOCA( proof->key.hash.uc ) )); proof->wallclock = chunk->wallclock; proof->chunk_cnt = chunk->num_chunks; - memset( proof->set, 0, 4 * sizeof(ulong) ); - // fd_eqvoc_proof_set_null( proof->set ); + if( FD_LIKELY( chunk->chunk_index != chunk->num_chunks - 1 ) ) { + proof->chunk_sz = chunk->chunk_len; + } + fd_eqvoc_proof_set_null( proof->set ); } if ( FD_UNLIKELY( chunk->wallclock < proof->wallclock ) ) { @@ -237,7 +272,6 @@ fd_eqvoc_proof_chunk_insert( fd_eqvoc_proof_t * proof, fd_gossip_duplicate_shred FD_LOG_WARNING(( "[%s] received incompatible chunk (slot: %lu from: %s). ignoring.", __func__, proof->key.slot, FD_BASE58_ENC_32_ALLOCA( proof->key.hash.uc ) )); return; } - if( FD_UNLIKELY( fd_eqvoc_proof_set_test( proof->set, chunk->chunk_index ) ) ) { FD_LOG_WARNING(( "[%s] already received chunk %u. slot: %lu from: %s. ignoring.", __func__, chunk->chunk_index, proof->key.slot, FD_BASE58_ENC_32_ALLOCA( proof->key.hash.uc ) )); @@ -248,20 +282,6 @@ fd_eqvoc_proof_chunk_insert( fd_eqvoc_proof_t * proof, fd_gossip_duplicate_shred fd_eqvoc_proof_set_insert( proof->set, chunk->chunk_index ); } -/* fd_eqvoc_proof_init initializes a new proof entry. */ - -void -fd_eqvoc_proof_init( fd_eqvoc_proof_t * proof, fd_pubkey_t const * producer, ulong wallclock, ulong chunk_cnt, ulong chunk_sz, void * bmtree_mem ) { - proof->producer = *producer; - proof->bmtree_mem = bmtree_mem; - proof->wallclock = wallclock; - proof->chunk_cnt = chunk_cnt; - proof->chunk_sz = chunk_sz; - memset( proof->set, 0, 4 * sizeof(ulong) ); - memset( proof->shreds, 0, 2472 ); -} - - void fd_eqvoc_proof_remove( fd_eqvoc_t * eqvoc, fd_slot_pubkey_t const * key ) { fd_eqvoc_proof_t * proof = fd_eqvoc_proof_map_ele_remove( eqvoc->proof_map, key, NULL, eqvoc->proof_pool ); @@ -269,11 +289,15 @@ fd_eqvoc_proof_remove( fd_eqvoc_t * eqvoc, fd_slot_pubkey_t const * key ) { FD_LOG_WARNING(( "[%s] key (%lu, %s) not in map.", __func__, key->slot, FD_BASE58_ENC_32_ALLOCA( key->hash.uc ) )); return; } + fd_eqvoc_proof_dlist_ele_remove( eqvoc->proof_dlist, proof, eqvoc->proof_pool ); fd_eqvoc_proof_pool_ele_release( eqvoc->proof_pool, proof ); } int fd_eqvoc_proof_verify( fd_eqvoc_proof_t const * proof ) { + #if FD_EQVOC_USE_HANDHOLDING + FD_TEST( fd_eqvoc_proof_complete( proof ) ); + #endif return fd_eqvoc_shreds_verify( fd_eqvoc_proof_shred1_const( proof ), fd_eqvoc_proof_shred2_const( proof ), &proof->producer, proof->bmtree_mem ); } diff --git a/src/choreo/eqvoc/fd_eqvoc.h b/src/choreo/eqvoc/fd_eqvoc.h index 40461feb63..1b5d62961d 100644 --- a/src/choreo/eqvoc/fd_eqvoc.h +++ b/src/choreo/eqvoc/fd_eqvoc.h @@ -40,7 +40,46 @@ #define FD_EQVOC_USE_HANDHOLDING 1 #endif -#define FD_EQVOC_FEC_MAX ( 67UL ) +/* The max # of data shreds in a FEC set */ + +#define FD_EQVOC_FEC_MAX (67UL) + +/* An equivocation proof is 2 shreds both prepended with a ulong (their + size). So the max sz is 2 * FD_SHRED_MAX_SZ + 2 * sizeof(ulong). */ + +#define FD_EQVOC_PROOF_MAX ( 2*FD_SHRED_MAX_SZ + 2*sizeof(ulong) ) + +/* CHUNK_MAX is standard MTU - IP / UDP headers - DuplicateShred headers + + IPv6 MTU - IP / UDP headers = 1232 + DuplicateShredMaxPayloadSize = 1232 - 115 + DuplicateShred headers = 63 + + https://github.com/anza-xyz/agave/blob/v2.0.3/gossip/src/cluster_info.rs#L113 + + CHUNK_MIN is ceil(max payload sz / UCHAR_MAX) + + CHUNK_CNT is by default the maximum size of a proof divided by + CHUNK_MAX (3) */ + +#define FD_EQVOC_PROOF_CHUNK_MAX ( 1232UL - 115UL - 63UL ) /* 1054 */ +#define FD_EQVOC_PROOF_CHUNK_CNT ( ( FD_EQVOC_PROOF_MAX / FD_EQVOC_PROOF_CHUNK_MAX ) + 1 ) /* 3 */ +#define FD_EQVOC_PROOF_CHUNK_MIN ( ( FD_EQVOC_PROOF_MAX / UCHAR_MAX ) + 1 ) /* 20 */ + +/* fd_eqvoc_proof_verify return codes */ + +#define FD_EQVOC_PROOF_VERIFY_FAILURE (0) +#define FD_EQVOC_PROOF_VERIFY_SUCCESS_SIGNATURE (1) +#define FD_EQVOC_PROOF_VERIFY_SUCCESS_META (2) +#define FD_EQVOC_PROOF_VERIFY_SUCCESS_LAST (3) +#define FD_EQVOC_PROOF_VERIFY_SUCCESS_OVERLAP (4) +#define FD_EQVOC_PROOF_VERIFY_SUCCESS_CHAINED (5) + +#define FD_EQVOC_PROOF_VERIFY_ERR_SLOT (-1) /* different slot */ +#define FD_EQVOC_PROOF_VERIFY_ERR_VERSION (-2) /* different shred version */ +#define FD_EQVOC_PROOF_VERIFY_ERR_TYPE (-3) /* wrong shred type (must be chained {resigned} merkle) */ +#define FD_EQVOC_PROOF_VERIFY_ERR_MERKLE (-4) /* merkle root failed */ +#define FD_EQVOC_PROOF_VERIFY_ERR_SIGNATURE (-5) /* sig verify of shred producer failed */ struct fd_slot_fec { ulong slot; @@ -48,17 +87,19 @@ struct fd_slot_fec { }; typedef struct fd_slot_fec fd_slot_fec_t; -/* clang-format off */ static const fd_slot_fec_t fd_slot_fec_null = { 0 }; #define FD_SLOT_FEC_NULL fd_slot_fec_null #define FD_SLOT_FEC_INVAL(key) (!((key).slot) & !((key).fec_set_idx)) #define FD_SLOT_FEC_EQ(k0,k1) (!(((k0).slot) ^ ((k1).slot))) & !(((k0).fec_set_idx) ^ (((k1).fec_set_idx))) #define FD_SLOT_FEC_HASH(key) ((uint)(((key).slot)<<15UL) | (((key).fec_set_idx))) -/* clang-format on */ struct fd_eqvoc_fec { - fd_slot_fec_t key; - ulong next; + fd_slot_fec_t key; + ulong prev; /* reserved. used by dlist */ + ulong next; /* reserved. used by map_chain and pool */ + ulong hash; /* reserved. used by map_chain. pool idx of + next element in hash chain */ + ulong code_cnt; ulong data_cnt; uint last_idx; @@ -70,59 +111,34 @@ typedef struct fd_eqvoc_fec fd_eqvoc_fec_t; #define POOL_T fd_eqvoc_fec_t #include "../../util/tmpl/fd_pool.c" -/* clang-format off */ +#define DLIST_NAME fd_eqvoc_fec_dlist +#define DLIST_ELE_T fd_eqvoc_fec_t +#include "../../util/tmpl/fd_dlist.c" + #define MAP_NAME fd_eqvoc_fec_map #define MAP_ELE_T fd_eqvoc_fec_t #define MAP_KEY_T fd_slot_fec_t +#define MAP_NEXT hash #define MAP_KEY_EQ(k0,k1) (FD_SLOT_FEC_EQ(*k0,*k1)) #define MAP_KEY_HASH(key,seed) (FD_SLOT_FEC_HASH(*key)^seed) #include "../../util/tmpl/fd_map_chain.c" -/* clang-format on */ - -#define FD_EQVOC_PROOF_MAX ( 2*FD_SHRED_MAX_SZ + 2*sizeof(ulong) ) /* 2 shreds prefixed with sz */ - -/* This is the standard MTU - - IPv6 MTU - IP / UDP headers = 1232 - DuplicateShredMaxPayloadSize = 1232 - 115 - DuplicateShred headers = 63 - - https://github.com/anza-xyz/agave/blob/v2.0.3/gossip/src/cluster_info.rs#L113 */ -#define FD_EQVOC_PROOF_CHUNK_MAX ( 1232UL - 115UL - 63UL ) -#define FD_EQVOC_PROOF_CHUNK_CNT ( ( FD_EQVOC_PROOF_MAX / FD_EQVOC_PROOF_CHUNK_MAX ) + 1 ) /* 3 */ - -/* The chunk_cnt is encoded in a UCHAR_MAX, so you can have at most - UCHAR_MAX chunks */ -#define FD_EQVOC_PROOF_CHUNK_MIN ( ( FD_EQVOC_PROOF_MAX / UCHAR_MAX ) + 1 ) /* 20 */ - -#define FD_EQVOC_PROOF_VERIFY_FAILURE (0) -#define FD_EQVOC_PROOF_VERIFY_SUCCESS_SIGNATURE (1) -#define FD_EQVOC_PROOF_VERIFY_SUCCESS_META (2) -#define FD_EQVOC_PROOF_VERIFY_SUCCESS_LAST (3) -#define FD_EQVOC_PROOF_VERIFY_SUCCESS_OVERLAP (4) -#define FD_EQVOC_PROOF_VERIFY_SUCCESS_CHAINED (5) - -#define FD_EQVOC_PROOF_VERIFY_ERR_SLOT (-1) /* different slot */ -#define FD_EQVOC_PROOF_VERIFY_ERR_VERSION (-2) /* different shred version */ -#define FD_EQVOC_PROOF_VERIFY_ERR_TYPE (-3) /* wrong shred type (must be chained {resigned} merkle) */ -#define FD_EQVOC_PROOF_VERIFY_ERR_MERKLE (-4) /* merkle root failed */ -#define FD_EQVOC_PROOF_VERIFY_ERR_SIGNATURE (-5) /* sig verify of shred producer failed */ #define SET_NAME fd_eqvoc_proof_set #define SET_MAX 256 #include "../../util/tmpl/fd_set.c" struct fd_eqvoc_proof { - fd_slot_pubkey_t key; - ulong prev; /* reserved for data structure use */ - ulong next; /* reserved for data structure use*/ - - fd_pubkey_t producer; /* producer of shreds' pubkey */ - void * bmtree_mem; /* scratch space for reconstructing - the merkle root */ - ulong wallclock; /* `wallclock` */ - ulong chunk_cnt; /* `num_chunks` */ - ulong chunk_sz; /* `chunk_len` */ + fd_slot_pubkey_t key; + ulong prev; /* reserved. used by dlist */ + ulong next; /* reserved. used by map_chain and pool */ + ulong hash; /* reserved. used by map_chain. pool idx of + the next element in hash chain */ + + fd_pubkey_t producer; /* producer of shreds' pubkey */ + void * bmtree_mem; /* merkle root reconstruction */ + ulong wallclock; /* fd_gossip_duplicate_shred_t `wallclock` */ + ulong chunk_cnt; /* fd_gossip_duplicate_shred_t `num_chunks` */ + ulong chunk_sz; /* fd_gossip_duplicate_shred_t `chunk_len` */ /* static declaration of an fd_set that occupies 4 words ie. 256 bits that tracks which proof chunks have been received. */ @@ -139,11 +155,7 @@ struct fd_eqvoc_proof { shred2_sz --------- shred2 - --------- - - Each shred is prepended with its size in bytes, before being - chunked. - */ + --------- */ uchar shreds[2 * FD_SHRED_MAX_SZ + 2 * sizeof(ulong)]; }; @@ -153,33 +165,36 @@ typedef struct fd_eqvoc_proof fd_eqvoc_proof_t; #define POOL_T fd_eqvoc_proof_t #include "../../util/tmpl/fd_pool.c" -/* clang-format off */ +#define DLIST_NAME fd_eqvoc_proof_dlist +#define DLIST_ELE_T fd_eqvoc_proof_t +#include "../../util/tmpl/fd_dlist.c" + #define MAP_NAME fd_eqvoc_proof_map #define MAP_ELE_T fd_eqvoc_proof_t #define MAP_KEY_T fd_slot_pubkey_t +#define MAP_NEXT hash #define MAP_KEY_EQ(k0,k1) (FD_SLOT_PUBKEY_EQ(k0,k1)) #define MAP_KEY_HASH(key,seed) (FD_SLOT_PUBKEY_HASH(key,seed)) #include "../../util/tmpl/fd_map_chain.c" -/* clang-format on */ struct fd_eqvoc { /* primitives */ fd_pubkey_t me; /* our pubkey */ - ulong fec_max; - ulong proof_max; - ulong shred_version; /* shred version we expect in all shreds in eqvoc-related msgs. */ + ulong fec_max; + ulong proof_max; /* owned */ - fd_eqvoc_fec_t * fec_pool; - fd_eqvoc_fec_map_t * fec_map; - // fd_eqvoc_fec_dlist_t * fec_dlist; - fd_eqvoc_proof_t * proof_pool; - fd_eqvoc_proof_map_t * proof_map; - fd_sha512_t * sha512; - void * bmtree_mem; + fd_eqvoc_fec_t * fec_pool; + fd_eqvoc_fec_dlist_t * fec_dlist; + fd_eqvoc_fec_map_t * fec_map; + fd_eqvoc_proof_t * proof_pool; + fd_eqvoc_proof_dlist_t * proof_dlist; + fd_eqvoc_proof_map_t * proof_map; + fd_sha512_t * sha512; + void * bmtree_mem; /* borrowed */ @@ -218,6 +233,7 @@ fd_eqvoc_footprint( ulong fec_max, ulong proof_max ) { fd_bmtree_commit_align(), fd_bmtree_commit_footprint( FD_SHRED_MERKLE_LAYER_CNT ) ), fd_eqvoc_align() ); } + /* clang-format on */ /* fd_eqvoc_new formats an unused memory region for use as a eqvoc. @@ -253,11 +269,6 @@ fd_eqvoc_leave( fd_eqvoc_t const * eqvoc ); void * fd_eqvoc_delete( void * sheqvoc ); -/* fd_eqvoc_init initializes eqvoc with the expected shred version. */ - -void -fd_eqvoc_init( fd_eqvoc_t * eqvoc, ulong shred_version ); - /* fd_eqvoc_fec_query queries for FEC set metadata on (slot, fec_set_idx). At least one coding shred most be inserted to populate code_cnt, data_cnt, and the last data shred in the slot to populate @@ -358,11 +369,14 @@ fd_eqvoc_proof_complete( fd_eqvoc_proof_t const * proof ) { } /* fd_eqvoc_proof_verify verifies that the two shreds contained in - `proof` do in fact equivocate. + `proof` do in fact equivocate. Caller MUST ensure that + fd_eqvoc_proof_complete returns 1 (ie. all chunks are received) + before calling this function. - Returns: FD_EQVOC_VERIFY_FAILURE if they do not - FD_EQVOC_VERIFY_SUCCESS_{REASON} if they do - FD_EQVOC_VERIFY_ERR_{REASON} if the shreds were not valid inputs + Returns: + FD_EQVOC_VERIFY_FAILURE if the proof does not verify + FD_EQVOC_VERIFY_SUCCESS_{REASON} if the proof does verify + FD_EQVOC_VERIFY_ERR_{REASON} if the proof's inputs are invalid Two shreds equivocate if they satisfy any of the following: @@ -404,7 +418,7 @@ fd_eqvoc_proof_complete( fd_eqvoc_proof_t const * proof ) { int fd_eqvoc_proof_verify( fd_eqvoc_proof_t const * proof ); -/* fd_eqvoc_proof_shreds_verify is a lower-level API for +/* fd_eqvoc_shreds_verify is a lower-level API for fd_eqvoc_proof_verify. Refer above for documentation. */ int @@ -441,13 +455,6 @@ fd_eqvoc_proof_shred2_const( fd_eqvoc_proof_t const * proof ) { return (fd_shred_t const *)fd_type_pun_const( proof->shreds + shred1_sz + 2*sizeof(ulong) ); } -/* fd_eqvoc_verify verifies `slot` has FEC sets with merkle roots that - correctly chain, including that the first FEC set in slot's merkle - hash chains from the last FEC set in parent slot's merkle hash. */ - -int -fd_eqvoc_slot_verify( fd_eqvoc_t const * eqvoc, fd_blockstore_t * blockstore, ulong slot ); - /* fd_eqvoc_from_chunks reconstructs shred1_out and shred2_out from `chunks` which is an array of "duplicate shred" gossip msgs. Shred1 and shred2 comprise a "duplicate shred proof", ie. proof of two diff --git a/src/choreo/eqvoc/test_eqvoc.c b/src/choreo/eqvoc/test_eqvoc.c index 914fb0f208..5fb84bd63f 100644 --- a/src/choreo/eqvoc/test_eqvoc.c +++ b/src/choreo/eqvoc/test_eqvoc.c @@ -67,7 +67,7 @@ test_eqvoc_proof_verify( fd_eqvoc_t * eqvoc ) { } void -test_eqvoc_proof_from_chunks( fd_eqvoc_t * eqvoc, +test_eqvoc_proof_from_chunks( FD_PARAM_UNUSED fd_eqvoc_t * eqvoc, fd_alloc_t * alloc, ulong shred1_sz, ulong shred2_sz, @@ -110,7 +110,6 @@ test_eqvoc_proof_from_chunks( fd_eqvoc_t * eqvoc, } fd_eqvoc_proof_t * proof = fd_alloc_malloc( alloc, alignof(fd_eqvoc_proof_t), sizeof(fd_eqvoc_proof_t) ); - fd_eqvoc_proof_init( proof, &producer, chunks[0].wallclock, chunks[0].num_chunks, chunks[0].chunk_len, eqvoc->bmtree_mem ); fd_memset( proof->set, 0, sizeof(proof->set) ); proof->producer = producer; fd_eqvoc_proof_from_chunks( chunks, proof ); @@ -254,7 +253,6 @@ main( int argc, char ** argv ) { eqvoc->me = (fd_pubkey_t){ .uc = { 0 } }; eqvoc->fec_max = fec_max; eqvoc->proof_max = proof_max; - eqvoc->shred_version = 42; eqvoc->leaders = &leaders; void * alloc_mem = fd_wksp_alloc_laddr( wksp, fd_alloc_align(), fd_alloc_footprint(), 1UL );