Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/app/firedancer-dev/commands/repair.c
Original file line number Diff line number Diff line change
Expand Up @@ -1139,10 +1139,10 @@ repair_cmd_fn_peers( args_t * args,

static const char * HELP =
"\n\n"
"usage: repair [-h] {catchup,forest,waterfall} ...\n"
"usage: repair [-h] {catchup,forest,inflight,requests,waterfall,peers,metrics} ...\n"
"\n"
"positional arguments:\n"
" {catchup,forest,inflight,requests,waterfall}\n"
" {catchup,forest,inflight,requests,waterfall,peers,metrics}\n"
" catchup runs Firedancer with a reduced topology that only repairs slots until catchup\n"
" eqvoc tests equivocation detection & repair path\n"
" forest prints the repair forest\n"
Expand Down
20 changes: 10 additions & 10 deletions src/app/firedancer-dev/commands/tower.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
fd_topo_run_tile_t
fdctl_tile_run( fd_topo_tile_t const * tile );

/* ctx_t is defined in fd_tower_tile.c, we just need to access it */
/* fd_tower_tile_t is defined in fd_tower_tile.c, we just need to access it */

static void
tower_ctx_wksp( args_t * args,
config_t * config,
ctx_t ** tower_ctx,
fd_topo_wksp_t ** tower_wksp ) {
tower_ctx_wksp( args_t * args,
config_t * config,
fd_tower_tile_t ** tower_ctx,
fd_topo_wksp_t ** tower_wksp ) {
(void)args;

fd_topo_t * topo = &config->topo;
Expand All @@ -41,14 +41,14 @@ tower_ctx_wksp( args_t * args,
if( FD_UNLIKELY( !scratch ) ) FD_LOG_ERR(( "Failed to access tower tile scratch memory" ));

FD_SCRATCH_ALLOC_INIT( l, scratch );
ctx_t * _tower_ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(ctx_t), sizeof(ctx_t) );
fd_tower_tile_t * _tower_ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_tower_tile_t), sizeof(fd_tower_tile_t) );

*tower_ctx = _tower_ctx;
*tower_wksp = _tower_wksp;
}

static void
print_all_forks( fd_wksp_t * wksp, ctx_t * tower_ctx, fd_tower_blocks_t * forks ) {
print_all_forks( fd_wksp_t * wksp, fd_tower_tile_t * tower_ctx, fd_tower_blocks_t * forks ) {
printf( "\n[Tower Forks]\n" );
printf( "=============\n" );
printf( "%-15s | %-15s | %-10s | %-10s\n", "Slot", "Parent Slot", "Voted", "Confirmed" );
Expand Down Expand Up @@ -148,7 +148,7 @@ tower_cmd_help( char const * arg ) {
static void
tower_cmd_fn_forks( args_t * args,
config_t * config ) {
ctx_t * tower_ctx;
fd_tower_tile_t * tower_ctx;
fd_topo_wksp_t * tower_wksp;
tower_ctx_wksp( args, config, &tower_ctx, &tower_wksp );

Expand All @@ -164,7 +164,7 @@ tower_cmd_fn_forks( args_t * args,
static void
tower_cmd_fn_ghost( args_t * args,
config_t * config ) {
ctx_t * tower_ctx;
fd_tower_tile_t * tower_ctx;
fd_topo_wksp_t * tower_wksp;
tower_ctx_wksp( args, config, &tower_ctx, &tower_wksp );

Expand All @@ -183,7 +183,7 @@ tower_cmd_fn_ghost( args_t * args,
static void
tower_cmd_fn_tower( args_t * args,
config_t * config ) {
ctx_t * tower_ctx;
fd_tower_tile_t * tower_ctx;
fd_topo_wksp_t * tower_wksp;
tower_ctx_wksp( args, config, &tower_ctx, &tower_wksp );

Expand Down
4 changes: 0 additions & 4 deletions src/ballet/shred/fd_shred.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,6 @@ FD_STATIC_ASSERT( sizeof(fd_bmtree_node_t) == FD_SHRED_MERKLE_ROOT_SZ, update FD

/* Maximum number of data shreds in a slot, also maximum number of parity shreds in a slot */
#define FD_SHRED_BLK_MAX (1 << 15UL) /* 32,768 shreds */
#define FD_SHRED_IDX_MAX (FD_SHRED_BLK_MAX - 1)

/* Maximum number of FEC sets in a slot / 32 shreds per FEC */
#define FD_SHRED_FEC_MAX (FD_SHRED_BLK_MAX / 32)

/* Many static bounds are specified around the assumption that this is a
protocol limit on the max number of shreds in a slot. If this limit
Expand Down
30 changes: 0 additions & 30 deletions src/choreo/notar/fd_notar.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ fd_notar_new( void * shmem,
FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_notar_align() ) == (ulong)shmem + footprint );

notar->root = ULONG_MAX;
notar->epoch = ULONG_MAX;
notar->slot_max = slot_max;
notar->slot_map = fd_notar_slot_new( slot_map, lg_slot_max, 0UL );
notar->blk_map = fd_notar_blk_new( blk_map, lg_blk_max, 0UL );
Expand Down Expand Up @@ -121,7 +120,6 @@ fd_notar_count_vote( fd_notar_t * notar,
notar_slot->is_leader = 0;
notar_slot->is_propagated = 0;
notar_slot->block_ids_cnt = 0;
fd_notar_slot_vtrs_null( notar_slot->prev_vtrs );
fd_notar_slot_vtrs_null( notar_slot->vtrs );
}
if( FD_UNLIKELY( vtr->bit==ULONG_MAX ) ) return NULL;
Expand All @@ -145,34 +143,6 @@ fd_notar_count_vote( fd_notar_t * notar,
return notar_blk;
}

void
fd_notar_update_voters( fd_notar_t * notar,
fd_tower_voters_t * voters,
ulong epoch ) {

notar->epoch = epoch;

for( ulong i = 0; i < fd_notar_vtr_key_max( notar->vtr_map ); i++ ) {
fd_notar_vtr_t * vtr = &notar->vtr_map[i];
if( fd_notar_vtr_key_inval( vtr->vote_acc ) ) continue;
vtr->prev_stake = vtr->stake;
vtr->stake = 0;
vtr->prev_bit = vtr->bit;
vtr->bit = ULONG_MAX;
}

ulong vtr_bit = 0;
for( fd_tower_voters_iter_t iter = fd_tower_voters_iter_init( voters );
!fd_tower_voters_iter_done( voters, iter );
iter = fd_tower_voters_iter_next( voters, iter ) ) {
fd_pubkey_t const * addr = &fd_tower_voters_iter_ele( voters, iter )->addr;
fd_notar_vtr_t * vtr = fd_notar_vtr_query( notar->vtr_map, *addr, NULL );
if( FD_UNLIKELY( !vtr ) ) vtr = fd_notar_vtr_insert( notar->vtr_map, *addr );
vtr->stake = fd_tower_voters_iter_ele( voters, iter )->stake;
vtr->bit = vtr_bit++;
}
}

void
fd_notar_publish( fd_notar_t * notar,
ulong root ) {
Expand Down
31 changes: 11 additions & 20 deletions src/choreo/notar/fd_notar.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ struct fd_notar_slot {
fd_hash_t block_ids[FD_VOTER_MAX]; /* one block id per voter per slot */
ulong block_ids_cnt; /* count of block ids */

fd_notar_slot_vtrs_t prev_vtrs[fd_notar_slot_vtrs_word_cnt]; /* who has voted for this slot, prev epoch */
fd_notar_slot_vtrs_t vtrs [fd_notar_slot_vtrs_word_cnt]; /* who has voted for this slot, curr epoch */
fd_notar_slot_vtrs_t vtrs[fd_notar_slot_vtrs_word_cnt]; /* who has voted for this slot, curr epoch */
};
typedef struct fd_notar_slot fd_notar_slot_t;

Expand Down Expand Up @@ -114,18 +113,16 @@ typedef struct fd_notar_blk fd_notar_blk_t;
#include "../../util/tmpl/fd_map_dynamic.c"

struct fd_notar_vtr {
fd_pubkey_t vote_acc; /* map key, vote account address */
uint hash; /* reserved for fd_map_dynamic */
ulong prev_stake; /* amount of stake this voter has in epoch - 1 */
ulong stake; /* amount of stake this voter has in epoch */
ulong prev_bit; /* bit position in fd_notar_slot_vtrs in epoch - 1 (ULONG_MAX if not set) */
ulong bit; /* bit position in fd_notar_slot_vtrs in epoch (ULONG_MAX if not set) */
fd_pubkey_t addr; /* map key, vote account address */
uint hash; /* reserved for fd_map_dynamic */
ulong bit; /* bit position in fd_notar_slot_vtrs in epoch (ULONG_MAX if not set) */
ulong stake; /* amount of stake this voter has in epoch */
};
typedef struct fd_notar_vtr fd_notar_vtr_t;

#define MAP_NAME fd_notar_vtr
#define MAP_T fd_notar_vtr_t
#define MAP_KEY vote_acc
#define MAP_KEY addr
#define MAP_KEY_T fd_pubkey_t
#define MAP_KEY_NULL pubkey_null
#define MAP_KEY_EQUAL_IS_SLOW 1
Expand All @@ -135,12 +132,11 @@ typedef struct fd_notar_vtr fd_notar_vtr_t;
#include "../../util/tmpl/fd_map_dynamic.c"

struct __attribute__((aligned(128UL))) fd_notar {
ulong root; /* current root */
ulong epoch; /* current epoch */
ulong slot_max; /* maximum number of slots notar can track */
fd_notar_slot_t * slot_map; /* tracks who has voted for a given slot */
fd_notar_blk_t * blk_map; /* tracks amount of stake for a given block (keyed by block id) */
fd_notar_vtr_t * vtr_map; /* tracks each voter's stake and prev vote */
ulong root; /* current root slot */
ulong slot_max; /* maximum number of slots notar can track */
fd_notar_slot_t * slot_map; /* tracks who has voted for a given slot */
fd_notar_blk_t * blk_map; /* tracks amount of stake for a given block (keyed by block id) */
fd_notar_vtr_t * vtr_map; /* tracks each voter's stake and prev vote */
};
typedef struct fd_notar fd_notar_t;

Expand Down Expand Up @@ -218,11 +214,6 @@ fd_notar_count_vote( fd_notar_t * notar,
ulong slot,
fd_hash_t const * block_id );

void
fd_notar_update_voters( fd_notar_t * notar,
fd_tower_voters_t * voters,
ulong epoch );

/* fd_notar_publish publishes root as the new notar root slot, removing
all blocks with slot numbers < the old notar root slot. Some slots
on minority forks that were pruned but > than the new root may remain
Expand Down
98 changes: 49 additions & 49 deletions src/choreo/notar/test_notar.c
Original file line number Diff line number Diff line change
@@ -1,68 +1,68 @@
#include "fd_notar.h"

void
test_update_voters( fd_wksp_t * wksp ) {
ulong slot_max = 8;
// void
// test_update_voters( fd_wksp_t * wksp ) {
// ulong slot_max = 8;

void * notar_mem = fd_wksp_alloc_laddr( wksp, fd_notar_align(), fd_notar_footprint( slot_max ), 1UL );
fd_notar_t * notar = fd_notar_join( fd_notar_new( notar_mem, slot_max ) );
FD_TEST( notar );
// void * notar_mem = fd_wksp_alloc_laddr( wksp, fd_notar_align(), fd_notar_footprint( slot_max ), 1UL );
// fd_notar_t * notar = fd_notar_join( fd_notar_new( notar_mem, slot_max ) );
// FD_TEST( notar );

void * tower_voters_mem = fd_wksp_alloc_laddr( wksp, fd_tower_voters_align(), fd_tower_voters_footprint( FD_VOTER_MAX ), 1UL );
fd_tower_voters_t * tower_voters = fd_tower_voters_join( fd_tower_voters_new( tower_voters_mem, FD_VOTER_MAX ) );
FD_TEST( tower_voters );
// void * tower_voters_mem = fd_wksp_alloc_laddr( wksp, fd_tower_voters_align(), fd_tower_voters_footprint( FD_VOTER_MAX ), 1UL );
// fd_tower_voters_t * tower_voters = fd_tower_voters_join( fd_tower_voters_new( tower_voters_mem, FD_VOTER_MAX ) );
// FD_TEST( tower_voters );

fd_tower_voters_t acct = { .addr = (fd_pubkey_t){ .key = { 1 } }, .stake = 10 };
fd_tower_voters_push_tail( tower_voters, acct );
// fd_tower_voters_t acct = { .addr = (fd_pubkey_t){ .key = { 1 } }, .stake = 10 };
// fd_tower_voters_push_tail( tower_voters, acct );

/* Voter should be accts. */
// /* Voter should be accts. */

fd_notar_publish( notar, 431998 );
// fd_notar_publish( notar, 431998 );

fd_notar_update_voters( notar, tower_voters, 1 );
FD_TEST( fd_notar_vtr_query( notar->vtr_map, acct.addr, NULL ) ); /* populate vtr map */
FD_TEST( fd_notar_count_vote( notar, &acct.addr, 431999, &((fd_hash_t){ .ul = { 431999 } }) ) );
// fd_notar_update_voters( notar, tower_voters, 1 );
// FD_TEST( fd_notar_vtr_query( notar->vtr_map, acct.addr, NULL ) ); /* populate vtr map */
// FD_TEST( fd_notar_count_vote( notar, &acct.addr, 431999, &((fd_hash_t){ .ul = { 431999 } }) ) );

/* Evict the voter from accts. */
// /* Evict the voter from accts. */

fd_tower_voters_pop_head( tower_voters );
fd_notar_update_voters( notar, tower_voters, 2 );
FD_TEST( !fd_notar_count_vote( notar, &acct.addr, 432000, &((fd_hash_t){ .ul = { 432000 } }) ) );
// fd_tower_voters_pop_head( tower_voters );
// fd_notar_update_voters( notar, tower_voters, 2 );
// FD_TEST( !fd_notar_count_vote( notar, &acct.addr, 432000, &((fd_hash_t){ .ul = { 432000 } }) ) );

// fd_hash_t block_id = { .ul = { slot } };
// ulong slot = 368778153;
// fd_hash_t bank_hash = { .ul = { slot } };
// // fd_hash_t block_id = { .ul = { slot } };
// // ulong slot = 368778153;
// // fd_hash_t bank_hash = { .ul = { slot } };

// fd_notar_blk_t * blk = fd_notar_blk_insert( notar->blk, block_id );
// blk->parent_slot = slot - 1;
// blk->bank_hash = bank_hash;
// blk->block_id = block_id;
// blk->stake = 0;
// blk->pro_conf = 0;
// blk->dup_conf = 0;
// blk->opt_conf = 0;
// blk->sup_conf = 0;
// // fd_notar_blk_t * blk = fd_notar_blk_insert( notar->blk, block_id );
// // blk->parent_slot = slot - 1;
// // blk->bank_hash = bank_hash;
// // blk->block_id = block_id;
// // blk->stake = 0;
// // blk->pro_conf = 0;
// // blk->dup_conf = 0;
// // blk->opt_conf = 0;
// // blk->sup_conf = 0;

// fd_pubkey_t pubkeys[4] = { { .key = { 1 } },
// { .key = { 2 } },
// { .key = { 3 } },
// { .key = { 4 } } };
// for( ulong i = 0; i < sizeof(pubkeys) / sizeof(fd_pubkey_t); i++ ) {
// fd_notar_vtr_t * vtr = fd_notar_vtr_insert( notar->vtr, pubkeys[i] );
// vtr->bit = i;
// }
// // fd_pubkey_t pubkeys[4] = { { .key = { 1 } },
// // { .key = { 2 } },
// // { .key = { 3 } },
// // { .key = { 4 } } };
// // for( ulong i = 0; i < sizeof(pubkeys) / sizeof(fd_pubkey_t); i++ ) {
// // fd_notar_vtr_t * vtr = fd_notar_vtr_insert( notar->vtr, pubkeys[i] );
// // vtr->bit = i;
// // }

// ulong stakes[4] = { 1, 2, 3, 4 };
// // ulong stakes[4] = { 1, 2, 3, 4 };

// mem = fd_wksp_alloc_laddr( wksp, fd_tower_align(), fd_tower_footprint(), 1UL );
// FD_TEST( mem );
// fd_tower_t * tower = fd_tower_join( fd_tower_new( mem ) );
// fd_tower_vote( tower, 368778153 );
// // mem = fd_wksp_alloc_laddr( wksp, fd_tower_align(), fd_tower_footprint(), 1UL );
// // FD_TEST( mem );
// // fd_tower_t * tower = fd_tower_join( fd_tower_new( mem ) );
// // fd_tower_vote( tower, 368778153 );

// fd_notar_vote( notar, &pubkeys[3], tower, ); /* first valid vote */
// // fd_notar_vote( notar, &pubkeys[3], tower, ); /* first valid vote */

fd_wksp_free_laddr( fd_notar_delete( fd_notar_leave( notar ) ) );
}
// fd_wksp_free_laddr( fd_notar_delete( fd_notar_leave( notar ) ) );
// }

int
main( int argc, char ** argv ) {
Expand All @@ -74,7 +74,7 @@ main( int argc, char ** argv ) {
fd_wksp_t * wksp = fd_wksp_new_anonymous( fd_cstr_to_shmem_page_sz( _page_sz ), page_cnt, fd_shmem_cpu_idx( numa_idx ), "wksp", 0UL );
FD_TEST( wksp );

test_update_voters( wksp );
// test_update_voters( wksp );
Comment on lines 74 to +77
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_update_voters (and its invocation) are commented out, leaving this unit test effectively doing nothing. Update/replace this test to exercise the new notar epoch/voter reindex behavior introduced by this PR so regressions are still caught in CI.

Copilot uses AI. Check for mistakes.

// fd_tower_restore( NULL, pubkey, );
// test_tower_vote();
Expand Down
1 change: 1 addition & 0 deletions src/choreo/tower/fd_tower_blocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
struct fd_tower_blk {
ulong slot; /* map key */
ulong parent_slot; /* parent slot */
ulong epoch; /* epoch of this slot */
int replayed; /* whether we've replayed this slot yet */
fd_hash_t replayed_block_id; /* the block_id we _first_ replayed for this slot */
int voted; /* whether we voted for this slot yet */
Expand Down
6 changes: 3 additions & 3 deletions src/choreo/tower/fd_tower_stakes.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ static const fd_tower_stakes_vtr_xid_t fd_tower_stakes_vtr_xid_null = { .addr =

struct fd_tower_stakes_vtr {
fd_tower_stakes_vtr_xid_t key;
ulong next;
ulong stake;
ulong prev;
ulong prev;
ulong next;
ulong stake;
};
typedef struct fd_tower_stakes_vtr fd_tower_stakes_vtr_t;

Expand Down
6 changes: 3 additions & 3 deletions src/discof/forest/fd_forest.c
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,7 @@ fd_forest_data_shred_insert( fd_forest_t * forest,
fd_hash_t * mr,
fd_hash_t * cmr ) {
VER_INC;
FD_TEST( shred_idx <= FD_SHRED_IDX_MAX );
FD_TEST( shred_idx < FD_SHRED_BLK_MAX );
fd_forest_blk_t * ele = query( forest, slot );
# if FD_FOREST_USE_HANDHOLDING
if( FD_UNLIKELY( !ele ) ) FD_LOG_ERR(( "fd_forest: fd_forest_data_shred_insert: ele %lu is not in the forest. data_shred_insert should be preceded by blk_insert", slot ));
Expand Down Expand Up @@ -1140,7 +1140,7 @@ fd_forest_data_shred_insert( fd_forest_t * forest,
fd_forest_blk_t *
fd_forest_fec_insert( fd_forest_t * forest, ulong slot, ulong parent_slot, uint last_shred_idx, uint fec_set_idx, int slot_complete, int ref_tick, fd_hash_t * mr, fd_hash_t * cmr ) {
VER_INC;
FD_TEST( last_shred_idx <= FD_SHRED_IDX_MAX );
FD_TEST( last_shred_idx < FD_SHRED_BLK_MAX );

fd_forest_blk_t * ele = query( forest, slot );
# if FD_FOREST_USE_HANDHOLDING
Expand Down Expand Up @@ -1206,7 +1206,7 @@ fd_forest_fec_insert( fd_forest_t * forest, ulong slot, ulong parent_slot, uint

fd_forest_blk_t *
fd_forest_code_shred_insert( fd_forest_t * forest, ulong slot, uint shred_idx ) {
FD_TEST( shred_idx <= FD_SHRED_IDX_MAX );
FD_TEST( shred_idx < FD_SHRED_BLK_MAX );
fd_forest_blk_t * ele = query( forest, slot );
if( FD_UNLIKELY( !ele ) ) {
return NULL;
Expand Down
Loading
Loading