Skip to content

Commit

Permalink
docs(blockstore): polish documentation on block limits
Browse files Browse the repository at this point in the history
  • Loading branch information
lidatong committed Jan 27, 2025
1 parent b616a87 commit 247c9fe
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 27 deletions.
8 changes: 4 additions & 4 deletions src/app/fdctl/run/tiles/fd_replay.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ scratch_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
for( ulong i = 0UL; i<FD_PACK_MAX_BANK_TILES; i++ ) {
l = FD_LAYOUT_APPEND( l, FD_BMTREE_COMMIT_ALIGN, FD_BMTREE_COMMIT_FOOTPRINT(0) );
}
l = FD_LAYOUT_APPEND( l, 128UL, FD_MBATCH_MAX );
l = FD_LAYOUT_APPEND( l, 128UL, FD_BLOCK_BATCH_SZ_MAX );
l = FD_LAYOUT_APPEND( l, FD_SCRATCH_ALIGN_DEFAULT, tile->replay.tpool_thread_count * TPOOL_WORKER_MEM_SZ );
ulong thread_spad_size = fd_spad_footprint( FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_DEFAULT );
l = FD_LAYOUT_APPEND( l, fd_spad_align(), tile->replay.tpool_thread_count * fd_ulong_align_up( thread_spad_size, fd_spad_align() ) );
Expand Down Expand Up @@ -1324,7 +1324,7 @@ prepare_new_block_execution( fd_replay_tile_ctx_t * ctx,
ctx->blockstore,
curr_slot,
ctx->mbatch,
FD_MBATCH_MAX,
FD_BLOCK_BATCH_SZ_MAX,
fork->slot_ctx.slot_bank.tick_height,
fork->slot_ctx.slot_bank.max_tick_height,
fork->slot_ctx.epoch_ctx->epoch_bank.hashes_per_tick
Expand Down Expand Up @@ -1390,7 +1390,7 @@ replay_mbatch( fd_replay_tile_ctx_t * ctx, uint shred_idx_start ) {
int err = fd_blockstore_batch_assemble( blockstore,
slot,
shred_idx_start,
FD_MBATCH_MAX,
FD_BLOCK_BATCH_SZ_MAX,
ctx->mbatch,
&mbatch_sz );
FD_TEST( err == FD_BLOCKSTORE_OK );
Expand Down Expand Up @@ -2373,7 +2373,7 @@ unprivileged_init( fd_topo_t * topo,
for( ulong i = 0UL; i<FD_PACK_MAX_BANK_TILES; i++ ) {
ctx->bmtree[i] = FD_SCRATCH_ALLOC_APPEND( l, FD_BMTREE_COMMIT_ALIGN, FD_BMTREE_COMMIT_FOOTPRINT(0) );
}
void * mbatch_mem = FD_SCRATCH_ALLOC_APPEND( l, 128UL, FD_MBATCH_MAX );
void * mbatch_mem = FD_SCRATCH_ALLOC_APPEND( l, 128UL, FD_BLOCK_BATCH_SZ_MAX );
void * tpool_worker_mem = FD_SCRATCH_ALLOC_APPEND( l, FD_SCRATCH_ALIGN_DEFAULT, tile->replay.tpool_thread_count * TPOOL_WORKER_MEM_SZ );
ulong thread_spad_size = fd_spad_footprint( FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_DEFAULT );
void * spad_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_spad_align(), tile->replay.tpool_thread_count * fd_ulong_align_up( thread_spad_size, fd_spad_align() ) );
Expand Down
5 changes: 1 addition & 4 deletions src/ballet/shred/fd_shred.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
payloads of no more than 1015 bytes.
In general, shreds that are chained or resigned should have smaller
payloads and a tigher bound. */
#define FD_SHRED_DATA_PAYLOAD_MAX (FD_SHRED_MIN_SZ-FD_SHRED_DATA_HEADER_SZ)
#define FD_SHRED_DATA_PAYLOAD_SZ_MAX (FD_SHRED_MIN_SZ-FD_SHRED_DATA_HEADER_SZ)

/* FD_SHRED_TYPE_* identifies the type of a shred.
It is located at the four high bits of byte 0x40 (64) of the shred header
Expand Down Expand Up @@ -149,9 +149,6 @@ typedef uchar fd_shred_merkle_t[FD_SHRED_MERKLE_NODE_SZ];
/* Maximum number of data shreds in a slot, also maximum number of parity shreds in a slot */
#define FD_SHRED_MAX_PER_SLOT (1 << 15UL) /* 32,768 shreds */

/* 36,536,320 bytes per slot */
#define FD_SHRED_DATA_PAYLOAD_MAX_PER_SLOT (FD_SHRED_DATA_PAYLOAD_MAX * FD_SHRED_MAX_PER_SLOT)

/* Offset of the shred variant. Used for parsing. */
#define FD_SHRED_VARIANT_OFF 0x40

Expand Down
10 changes: 5 additions & 5 deletions src/flamenco/runtime/fd_blockstore.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,10 +465,10 @@ fd_blockstore_scan_block( fd_blockstore_t * blockstore, ulong slot, fd_block_t *

fd_block_micro_t * micros = fd_alloc_malloc( fd_blockstore_alloc( blockstore ),
alignof( fd_block_micro_t ),
sizeof( *micros ) * FD_MICROBLOCK_MAX_PER_SLOT );
sizeof( *micros ) * FD_BLOCK_MICRO_CNT_MAX );
fd_block_txn_t * txns = fd_alloc_malloc( fd_blockstore_alloc( blockstore ),
alignof( fd_block_txn_t ),
sizeof( *txns ) * FD_TXN_MAX_PER_SLOT );
sizeof( *txns ) * FD_BLOCK_TXN_CNT_MAX );

/*
* Agave decodes precisely one array of microblocks from each batch.
Expand Down Expand Up @@ -498,7 +498,7 @@ fd_blockstore_scan_block( fd_blockstore_t * blockstore, ulong slot, fd_block_t *
for( ulong mblk = 0; mblk < mcount; ++mblk ) {
if( blockoff + sizeof( fd_microblock_hdr_t ) > batch_end_off )
FD_LOG_ERR(( "premature end of batch" ));
if( micros_cnt < FD_MICROBLOCK_MAX_PER_SLOT ) {
if( micros_cnt < FD_BLOCK_MICRO_CNT_MAX ) {
fd_block_micro_t * m = micros + ( micros_cnt++ );
m->off = blockoff;
}
Expand Down Expand Up @@ -548,7 +548,7 @@ fd_blockstore_scan_block( fd_blockstore_t * blockstore, ulong slot, fd_block_t *
elem->meta_gaddr = 0;
elem->meta_sz = 0;

if( txns_cnt < FD_TXN_MAX_PER_SLOT ) {
if( txns_cnt < FD_BLOCK_TXN_CNT_MAX ) {
fd_block_txn_t * ref = &txns[txns_cnt++];
ref->txn_off = blockoff;
ref->id_off = (ulong)( sigs + j ) - (ulong)data;
Expand Down Expand Up @@ -1468,7 +1468,7 @@ fd_blockstore_batch_assemble( fd_blockstore_t * blockstore,
|| (shreds[idx].hdr.data.flags & FD_SHRED_DATA_FLAG_SLOT_COMPLETE);
}

if( FD_UNLIKELY( payload_sz > FD_SHRED_DATA_PAYLOAD_MAX ) ) return FD_BLOCKSTORE_ERR_SHRED_INVALID;
if( FD_UNLIKELY( payload_sz > FD_SHRED_DATA_PAYLOAD_SZ_MAX ) ) return FD_BLOCKSTORE_ERR_SHRED_INVALID;
if( FD_UNLIKELY( mbatch_sz + payload_sz > batch_data_max ) ) return FD_BLOCKSTORE_ERR_NO_MEM;
fd_memcpy( batch_data_out + mbatch_sz, payload, payload_sz );
fd_blockstore_end_read( blockstore );
Expand Down
44 changes: 32 additions & 12 deletions src/flamenco/runtime/fd_blockstore.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,42 @@

/* TODO this can be removed if we explicitly manage a memory pool for
the fd_block_map_t entries */

#define FD_BLOCKSTORE_CHILD_SLOT_MAX (32UL) /* the maximum # of children a slot can have */
#define FD_BLOCKSTORE_ARCHIVE_MIN_SIZE (1UL << 26UL) /* 64MB := ceil(MAX_DATA_SHREDS_PER_SLOT*1228) */

/* Maximum size of an entry batch is the entire block */
#define FD_MBATCH_MAX (FD_SHRED_DATA_PAYLOAD_MAX_PER_SLOT)
/* 64 ticks per slot, and then one min size transaction per microblock
for all the remaining microblocks.
/* FD_BLOCK_SZ_MAX defines the maximum size (in bytes) of a block. In
the worst case this is the maximum number of shreds in a block * the
maximum payload size of a data shred. */

#define FD_BLOCK_SZ_MAX (FD_SHRED_DATA_PAYLOAD_SZ_MAX * FD_SHRED_MAX_PER_SLOT)

/* FD_BLOCK_BATCH_SZ_MAX defines the maximum size of a microblock batch. In
the worst case the entire block is transmitted in a single microblock
batch, so this bound equals FD_BLOCK_SZ_MAX. */

#define FD_BLOCK_BATCH_SZ_MAX (FD_BLOCK_SZ_MAX)

/* FD_BLOCK_MICRO_CNT_MAX defines the maximum number of microblocks that
can be in a valid block. In the worst case, this is 64 ticks (ie.
empty microblocks) + the maximum size of a block divided by the
minimum size of a microblock (ie. microblock hdr + 1 min sz txn).
This bound should be used along with the transaction parser and tick
verifier to enforce the assumptions.
This is NOT a standalone conservative bound against malicious
validators.
A tighter bound could probably be derived if necessary. */
#define FD_MICROBLOCK_MAX_PER_SLOT ((FD_SHRED_DATA_PAYLOAD_MAX_PER_SLOT - 64UL*sizeof(fd_microblock_hdr_t)) / (sizeof(fd_microblock_hdr_t)+FD_TXN_MIN_SERIALIZED_SZ) + 64UL) /* 200,796 */
/* 64 ticks per slot, and a single gigantic microblock containing min
size transactions. */
#define FD_TXN_MAX_PER_SLOT ((FD_SHRED_DATA_PAYLOAD_MAX_PER_SLOT - 65UL*sizeof(fd_microblock_hdr_t)) / (FD_TXN_MIN_SERIALIZED_SZ)) /* 272,635 */
verifier to enforce the assumptions. This is NOT a standalone
conservative bound against malicious validators. A tighter bound
could probably be derived if necessary. */

#define FD_BLOCK_MICRO_CNT_MAX ((FD_BLOCK_SZ_MAX - 64UL*sizeof(fd_microblock_hdr_t)) / (sizeof(fd_microblock_hdr_t)+FD_TXN_MIN_SERIALIZED_SZ) + 64UL) /* 200,796 */

/* FD_BLOCK_TXN_CNT_MAX defines the maximum number of transactions that
can be in a valid block. In the worst case, this is 64 ticks (ie.
empty microblocks) + a single microblock header (because in the worst
case all the transactions will be packed into a single microblock
which minimizes the space occupied by headers) divided by the minimum
size of a transaction. */

#define FD_BLOCK_TXN_CNT_MAX ((FD_BLOCK_SZ_MAX - 65UL*sizeof(fd_microblock_hdr_t)) / (FD_TXN_MIN_SERIALIZED_SZ)) /* 272,635 */

// TODO centralize these
// https://github.com/firedancer-io/solana/blob/v1.17.5/sdk/program/src/clock.rs#L34
Expand Down
4 changes: 2 additions & 2 deletions src/flamenco/runtime/fd_runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -4191,12 +4191,12 @@ fd_runtime_block_eval_tpool( fd_exec_slot_ctx_t * slot_ctx,
break;
}

uchar * block_data = fd_scratch_alloc( 128UL, FD_MBATCH_MAX );
uchar * block_data = fd_scratch_alloc( 128UL, FD_BLOCK_BATCH_SZ_MAX );
ulong tick_res = fd_runtime_block_verify_ticks(
slot_ctx->blockstore,
slot,
block_data,
FD_MBATCH_MAX,
FD_BLOCK_BATCH_SZ_MAX,
slot_ctx->slot_bank.tick_height,
slot_ctx->slot_bank.max_tick_height,
slot_ctx->epoch_ctx->epoch_bank.hashes_per_tick
Expand Down

0 comments on commit 247c9fe

Please sign in to comment.