Skip to content

Commit

Permalink
handholding for tmpl data structures
Browse files Browse the repository at this point in the history
Add debug time assertions to be used as an early bug oracle during fuzzing and other testing
* Only based on local information, so handholding can be used without any changes
* Focus on data structures currently in use
Drive-by: typo fixes, make magic unique, mark unreachable code with unreachable builtin
  • Loading branch information
two-heart committed Feb 17, 2025
1 parent c277117 commit e219f22
Show file tree
Hide file tree
Showing 37 changed files with 1,750 additions and 417 deletions.
1 change: 1 addition & 0 deletions config/extra/with-handholding.mk
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ CPPFLAGS+=-DFD_GHOST_USE_HANDHOLDING=1
CPPFLAGS+=-DFD_SCRATCH_USE_HANDHOLDING=1
CPPFLAGS+=-DFD_SPAD_USE_HANDHOLDING=1
CPPFLAGS+=-DFD_TOWER_USE_HANDHOLDING=1
CPPFLAGS+=-DFD_TMPL_USE_HANDHOLDING=1
CPPFLAGS+=-DFD_TXN_HANDHOLDING=1
CPPFLAGS+=-DFD_RUNTIME_ERR_HANDHOLDING=1
14 changes: 7 additions & 7 deletions src/flamenco/runtime/program/fd_vote_program.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ from_vote_state_1_14_11( fd_vote_state_t * vote_state,
!deq_fd_landed_vote_t_iter_done( vote_state->votes, iter );
iter = deq_fd_landed_vote_t_iter_next( vote_state->votes, iter ) ) {
fd_landed_vote_t const * landed_vote = deq_fd_landed_vote_t_iter_ele_const( vote_state->votes, iter );
deq_fd_vote_lockout_t_push_tail( vote_state_1_14_11->votes, landed_vote->lockout );
deq_fd_vote_lockout_t_push_tail_wrap( vote_state_1_14_11->votes, landed_vote->lockout );
}
}

Expand Down Expand Up @@ -584,7 +584,7 @@ increment_credits( fd_vote_state_t * self, ulong epoch, ulong credits ) {
// https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L643
if( FD_UNLIKELY( deq_fd_vote_epoch_credits_t_empty( self->epoch_credits ) ) ) {
// https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L644
deq_fd_vote_epoch_credits_t_push_tail(
deq_fd_vote_epoch_credits_t_push_tail_wrap(
self->epoch_credits,
( fd_vote_epoch_credits_t ){ .epoch = epoch, .credits = 0, .prev_credits = 0 } );
} else if( FD_LIKELY( epoch !=
Expand All @@ -596,7 +596,7 @@ increment_credits( fd_vote_state_t * self, ulong epoch, ulong credits ) {

// https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L648
if( FD_LIKELY( credits != prev_credits ) ) {
deq_fd_vote_epoch_credits_t_push_tail(
deq_fd_vote_epoch_credits_t_push_tail_wrap(
self->epoch_credits,
( fd_vote_epoch_credits_t ){
.epoch = epoch, .credits = credits, .prev_credits = credits } );
Expand Down Expand Up @@ -653,7 +653,7 @@ process_next_vote_slot( fd_vote_state_t * self,
}

// https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L634
deq_fd_landed_vote_t_push_tail( self->votes, landed_vote );
deq_fd_landed_vote_t_push_tail_wrap( self->votes, landed_vote );
double_lockouts( self );
}

Expand Down Expand Up @@ -1431,7 +1431,7 @@ process_new_vote_state( fd_vote_state_t * vote_state,
!deq_fd_landed_vote_t_iter_done( new_state, iter );
iter = deq_fd_landed_vote_t_iter_next( new_state, iter ) ) {
fd_landed_vote_t * landed_vote = deq_fd_landed_vote_t_iter_ele( new_state, iter );
deq_fd_landed_vote_t_push_tail( vote_state->votes, *landed_vote );
deq_fd_landed_vote_t_push_tail_wrap( vote_state->votes, *landed_vote );
}

return FD_EXECUTOR_INSTR_SUCCESS;
Expand Down Expand Up @@ -1737,7 +1737,7 @@ process_vote( fd_vote_state_t * vote_state,
iter = deq_ulong_iter_next( vote->slots, iter ) ) {
ulong * ele = deq_ulong_iter_ele( vote->slots, iter );
if( FD_UNLIKELY( *ele >= earliest_slot_in_history ) ) {
vote_slots = deq_ulong_push_tail( vote_slots, *ele );
vote_slots = deq_ulong_push_tail_wrap( vote_slots, *ele );
}
}

Expand Down Expand Up @@ -1909,7 +1909,7 @@ do_process_vote_state_update( fd_vote_state_t * vote_state,
iter = deq_fd_vote_lockout_t_iter_next( vote_state_update->lockouts, iter ) ) {
fd_vote_lockout_t * lockout =
deq_fd_vote_lockout_t_iter_ele( vote_state_update->lockouts, iter );
deq_fd_landed_vote_t_push_tail( landed_votes,
deq_fd_landed_vote_t_push_tail_wrap( landed_votes,
( fd_landed_vote_t ){ .latency = 0, .lockout = *lockout } );
}

Expand Down
88 changes: 82 additions & 6 deletions src/util/tmpl/fd_deque.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@
// Advanced API for zero-copy usage
my_ele_t * my_deque_peek_head ( my_ele_t * deque ); // peeks at head, returned ptr lifetime is until next op on deque
// caller guarantees that deque is not empty
my_ele_t * my_deque_peek_tail ( my_ele_t * deque ); // peeks at tail, returned ptr lifetime is until next op on deque
// caller guarantees that deque is not empty
my_ele_t * my_deque_peek_index ( my_ele_t * deque, ulong idx ); // peeks at index, returned ptr lifetime is until next op on deque
// caller guarantees that deque is not empty
// idx is wrapped to [0,cnt)
my_ele_t * my_deque_insert_head( my_ele_t * deque ); // inserts uninitialized element at head, returns deque
my_ele_t * my_deque_insert_tail( my_ele_t * deque ); // inserts uninitialized element at tail, returns deque
my_ele_t * my_deque_remove_head( my_ele_t * deque ); // removes head, returns deque
Expand Down Expand Up @@ -107,7 +111,6 @@
remove operation (remove_all is fine on an empty deque). */

#include "../bits/fd_bits.h"

#include <stddef.h>

#ifndef DEQUE_NAME
Expand All @@ -131,6 +134,17 @@
#error "DEQUE_MAX must be positive"
#endif

/* FD_TMPL_USE_HANDHOLDING is disabled by default in production */

#ifndef FD_TMPL_USE_HANDHOLDING
#define FD_UNDEF_HANDHOLDING
#define FD_TMPL_USE_HANDHOLDING 0
#endif

#if FD_TMPL_USE_HANDHOLDING
#include "../log/fd_log.h"
#endif

/* Implementation *****************************************************/

#define DEQUE_(x) FD_EXPAND_THEN_CONCAT3(DEQUE_NAME,_,x)
Expand Down Expand Up @@ -191,6 +205,10 @@ FD_FN_CONST static inline ulong DEQUE_(footprint)( void ) { return sizeof (DEQUE

static inline void *
DEQUE_(new)( void * shmem ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( !shmem ) ) FD_LOG_ERR(( "NULL shmem" ));
if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, DEQUE_(align)() ) ) ) FD_LOG_ERR(( "unaligned shmem" ));
#endif
DEQUE_(private_t) * hdr = (DEQUE_(private_t) *)shmem;
/* These values are large enough that underflow/overflow will never
happen in practical usage. For example, it would take hundreds of
Expand All @@ -211,8 +229,16 @@ DEQUE_(join)( void * shdeque ) {
return hdr->deque;
}

static inline void * DEQUE_(leave) ( DEQUE_T * deque ) { return (void *)DEQUE_(private_hdr_from_deque)( deque ); }
static inline void * DEQUE_(delete)( void * shdeque ) { return shdeque; }
static inline void * DEQUE_(leave) ( DEQUE_T * deque ) { return (void *)DEQUE_(private_hdr_from_deque)( deque ); }

static inline void *
DEQUE_(delete)( void * shdeque ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( !shdeque ) ) FD_LOG_ERR(( "NULL shdeque" ));
if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shdeque, DEQUE_(align)() ) ) ) FD_LOG_ERR(( "unaligned shdeque" ));
#endif
return shdeque;
}

FD_FN_CONST static inline ulong DEQUE_(max)( DEQUE_T const * deque ) { (void)deque; return (ulong)(DEQUE_MAX); }

Expand Down Expand Up @@ -243,6 +269,9 @@ DEQUE_(full)( DEQUE_T const * deque ) {
static inline DEQUE_T *
DEQUE_(push_head)( DEQUE_T * deque,
DEQUE_T ele ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(full)( deque ) ) ) FD_LOG_ERR(( "cannot push to full deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
hdr->start--;
hdr->deque[ DEQUE_(private_slot)( hdr->start ) ] = ele;
Expand All @@ -252,6 +281,9 @@ DEQUE_(push_head)( DEQUE_T * deque,
static inline DEQUE_T *
DEQUE_(push_tail)( DEQUE_T * deque,
DEQUE_T ele ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(full)( deque ) ) ) FD_LOG_ERR(( "cannot push to full deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
hdr->deque[ DEQUE_(private_slot)( hdr->end ) ] = ele;
hdr->end++;
Expand All @@ -260,6 +292,9 @@ DEQUE_(push_tail)( DEQUE_T * deque,

static inline DEQUE_T
DEQUE_(pop_head)( DEQUE_T * deque ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(empty)( deque ) ) ) FD_LOG_ERR(( "cannot pop from empty deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
DEQUE_T ele = hdr->deque[ DEQUE_(private_slot)( hdr->start ) ];
hdr->start++;
Expand All @@ -268,6 +303,9 @@ DEQUE_(pop_head)( DEQUE_T * deque ) {

static inline DEQUE_T
DEQUE_(pop_tail)( DEQUE_T * deque ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(empty)( deque ) ) ) FD_LOG_ERR(( "cannot pop from empty deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
hdr->end--;
return hdr->deque[ DEQUE_(private_slot)( hdr->end ) ];
Expand Down Expand Up @@ -321,6 +359,10 @@ DEQUE_(push_tail_wrap)( DEQUE_T * deque,

static inline DEQUE_T
DEQUE_(pop_idx_tail)( DEQUE_T * deque, ulong idx ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(empty)( deque ) ) ) FD_LOG_ERR(( "cannot pop from empty deque" ));
if( FD_UNLIKELY( idx>=DEQUE_(cnt)( deque ) ) ) FD_LOG_ERR(( "index out of bounds" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
DEQUE_T * cur = &hdr->deque[ DEQUE_(private_slot)( hdr->start + idx ) ];
DEQUE_T ele = *cur;
Expand Down Expand Up @@ -351,8 +393,14 @@ DEQUE_(peek_tail)( DEQUE_T * deque ) {
return hdr->deque + DEQUE_(private_slot)( hdr->end-1UL );
}

FD_FN_PURE static inline DEQUE_T *
#if !FD_TMPL_USE_HANDHOLDING
FD_FN_PURE
#endif
static inline DEQUE_T *
DEQUE_(peek_index)( DEQUE_T * deque, ulong idx ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( idx>=DEQUE_(cnt)( deque ) ) ) FD_LOG_ERR(( "index out of bounds" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
return hdr->deque + DEQUE_(private_slot)( hdr->start + idx );
}
Expand All @@ -373,8 +421,14 @@ DEQUE_(peek_tail_const)( DEQUE_T const * deque ) {
return hdr->deque + DEQUE_(private_slot)( hdr->end-1UL );
}

FD_FN_PURE static inline DEQUE_T const *
#if !FD_TMPL_USE_HANDHOLDING
FD_FN_PURE
#endif
static inline DEQUE_T const *
DEQUE_(peek_index_const)( DEQUE_T const * deque, ulong idx ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( idx>=DEQUE_(cnt)( deque ) ) ) FD_LOG_ERR(( "index out of bounds" ));
#endif
DEQUE_(private_t) const * hdr = DEQUE_(private_const_hdr_from_deque)( deque );
return hdr->deque + DEQUE_(private_slot)( hdr->start + idx );
}
Expand All @@ -386,13 +440,19 @@ static inline DEQUE_T * DEQUE_(remove_tail)( DEQUE_T * deque ) { DEQUE_(private_

static inline DEQUE_T *
DEQUE_(push_head_nocopy)( DEQUE_T * deque ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(full)( deque ) ) ) FD_LOG_ERR(( "cannot push to full deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
hdr->start--;
return &hdr->deque[ DEQUE_(private_slot)( hdr->start ) ];
}

static inline DEQUE_T *
DEQUE_(push_tail_nocopy)( DEQUE_T * deque ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(full)( deque ) ) ) FD_LOG_ERR(( "cannot push to full deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
DEQUE_T * ele = &hdr->deque[ DEQUE_(private_slot)( hdr->end ) ];
hdr->end++;
Expand All @@ -401,6 +461,9 @@ DEQUE_(push_tail_nocopy)( DEQUE_T * deque ) {

static inline DEQUE_T *
DEQUE_(pop_head_nocopy)( DEQUE_T * deque ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(empty)( deque ) ) ) FD_LOG_ERR(( "cannot pop from empty deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
DEQUE_T * ele = &hdr->deque[ DEQUE_(private_slot)( hdr->start ) ];
hdr->start++;
Expand All @@ -409,6 +472,9 @@ DEQUE_(pop_head_nocopy)( DEQUE_T * deque ) {

static inline DEQUE_T *
DEQUE_(pop_tail_nocopy)( DEQUE_T * deque ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(empty)( deque ) ) ) FD_LOG_ERR(( "cannot pop from empty deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
hdr->end--;
return &hdr->deque[ DEQUE_(private_slot)( hdr->end ) ];
Expand Down Expand Up @@ -463,13 +529,19 @@ DEQUE_(iter_prev)( DEQUE_T const * deque, DEQUE_(iter_t) iter ) {

static inline DEQUE_T *
DEQUE_(iter_ele)( DEQUE_T * deque, DEQUE_(iter_t) iter ) {
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( (iter<hdr->start) | (iter>hdr->end) ) ) FD_LOG_ERR(( "iter out of bounds" ));
#endif
return &hdr->deque[ DEQUE_(private_slot)( iter ) ];
}

static inline DEQUE_T const *
DEQUE_(iter_ele_const)( DEQUE_T const * deque, DEQUE_(iter_t) iter ) {
DEQUE_(private_t) const * hdr = DEQUE_(private_const_hdr_from_deque)( deque );
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( (iter<hdr->start) | (iter>hdr->end) ) ) FD_LOG_ERR(( "iter out of bounds" ));
#endif
return &hdr->deque[ DEQUE_(private_slot)( iter ) ];
}

Expand All @@ -480,3 +552,7 @@ FD_PROTOTYPES_END
#undef DEQUE_MAX
#undef DEQUE_T
#undef DEQUE_NAME
#ifdef FD_UNDEF_HANDHOLDING
#undef FD_TMPL_USE_HANDHOLDING
#undef FD_UNDEF_HANDHOLDING
#endif
Loading

0 comments on commit e219f22

Please sign in to comment.